blob: d7ebdf8651f5f57fe598197b1e0620754d1dcc55 [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 Roeckcd1faefa2015-08-30 19:45:19 -070042 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070043 *
44 * #temp lists the number of monitored temperature sources (first value) plus
45 * the number of directly connectable temperature sensors (second value).
46 */
47
48#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
50#include <linux/module.h>
51#include <linux/init.h>
52#include <linux/slab.h>
53#include <linux/jiffies.h>
54#include <linux/platform_device.h>
55#include <linux/hwmon.h>
56#include <linux/hwmon-sysfs.h>
57#include <linux/hwmon-vid.h>
58#include <linux/err.h>
59#include <linux/mutex.h>
60#include <linux/acpi.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080061#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070062#include <linux/io.h>
63#include "lm75.h"
64
Guenter Roeckaa136e52012-12-04 03:26:05 -080065#define USE_ALTERNATE
66
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070067enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070068
69/* used to set data->name = nct6775_device_names[data->sio_kind] */
70static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070071 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070072 "nct6775",
73 "nct6776",
74 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070075 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080076 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070077 "nct6793",
78};
79
80static const char * const nct6775_sio_names[] __initconst = {
81 "NCT6106D",
82 "NCT6775F",
83 "NCT6776D/F",
84 "NCT6779D",
85 "NCT6791D",
86 "NCT6792D",
87 "NCT6793D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070088};
89
90static unsigned short force_id;
91module_param(force_id, ushort, 0);
92MODULE_PARM_DESC(force_id, "Override the detected device ID");
93
Guenter Roeck47ece962012-12-04 07:59:32 -080094static unsigned short fan_debounce;
95module_param(fan_debounce, ushort, 0);
96MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
97
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070098#define DRVNAME "nct6775"
99
100/*
101 * Super-I/O constants and functions
102 */
103
Guenter Roecka6bd5872012-12-04 03:13:34 -0800104#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700105#define NCT6775_LD_HWM 0x0b
106#define NCT6775_LD_VID 0x0d
107
108#define SIO_REG_LDSEL 0x07 /* Logical device select */
109#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
110#define SIO_REG_ENABLE 0x30 /* Logical device enable */
111#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
112
Guenter Roeck6c009502012-07-01 08:23:15 -0700113#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114#define SIO_NCT6775_ID 0xb470
115#define SIO_NCT6776_ID 0xc330
116#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700117#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800118#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700119#define SIO_NCT6793_ID 0xd120
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700120#define SIO_ID_MASK 0xFFF0
121
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800122enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
123
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700124static inline void
125superio_outb(int ioreg, int reg, int val)
126{
127 outb(reg, ioreg);
128 outb(val, ioreg + 1);
129}
130
131static inline int
132superio_inb(int ioreg, int reg)
133{
134 outb(reg, ioreg);
135 return inb(ioreg + 1);
136}
137
138static inline void
139superio_select(int ioreg, int ld)
140{
141 outb(SIO_REG_LDSEL, ioreg);
142 outb(ld, ioreg + 1);
143}
144
145static inline int
146superio_enter(int ioreg)
147{
148 /*
149 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
150 */
151 if (!request_muxed_region(ioreg, 2, DRVNAME))
152 return -EBUSY;
153
154 outb(0x87, ioreg);
155 outb(0x87, ioreg);
156
157 return 0;
158}
159
160static inline void
161superio_exit(int ioreg)
162{
163 outb(0xaa, ioreg);
164 outb(0x02, ioreg);
165 outb(0x02, ioreg + 1);
166 release_region(ioreg, 2);
167}
168
169/*
170 * ISA constants
171 */
172
173#define IOREGION_ALIGNMENT (~7)
174#define IOREGION_OFFSET 5
175#define IOREGION_LENGTH 2
176#define ADDR_REG_OFFSET 0
177#define DATA_REG_OFFSET 1
178
179#define NCT6775_REG_BANK 0x4E
180#define NCT6775_REG_CONFIG 0x40
181
182/*
183 * Not currently used:
184 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
185 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
186 * REG_MAN_ID is at port 0x4f
187 * REG_CHIP_ID is at port 0x58
188 */
189
Guenter Roeckaa136e52012-12-04 03:26:05 -0800190#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
191#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
192
Guenter Roeck6c009502012-07-01 08:23:15 -0700193#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700194#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700195
David Bartley578ab5f2013-06-24 22:28:28 -0700196#define NUM_FAN 6
197
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700198/* Common and NCT6775 specific data */
199
200/* Voltage min/max registers for nr=7..14 are in bank 5 */
201
202static const u16 NCT6775_REG_IN_MAX[] = {
203 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
204 0x55c, 0x55e, 0x560, 0x562 };
205static const u16 NCT6775_REG_IN_MIN[] = {
206 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
207 0x55d, 0x55f, 0x561, 0x563 };
208static const u16 NCT6775_REG_IN[] = {
209 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
210};
211
212#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800213#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700214#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700215
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800216#define NCT6775_REG_FANDIV1 0x506
217#define NCT6775_REG_FANDIV2 0x507
218
Guenter Roeck47ece962012-12-04 07:59:32 -0800219#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
220
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700221static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
222
Guenter Roeck30846992013-06-24 22:21:59 -0700223/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700224
225static const s8 NCT6775_ALARM_BITS[] = {
226 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
227 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
228 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700229 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700230 -1, -1, -1, /* unused */
231 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
232 12, -1 }; /* intrusion0, intrusion1 */
233
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800234#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800235#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800236#define INTRUSION_ALARM_BASE 30
237
Guenter Roeck30846992013-06-24 22:21:59 -0700238static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
239
240/*
241 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
242 * 30..31 intrusion
243 */
244static const s8 NCT6775_BEEP_BITS[] = {
245 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
246 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
247 21, /* global beep enable */
248 6, 7, 11, 28, -1, /* fan1..fan5 */
249 -1, -1, -1, /* unused */
250 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
251 12, -1 }; /* intrusion0, intrusion1 */
252
253#define BEEP_ENABLE_BASE 15
254
Guenter Roecka6bd5872012-12-04 03:13:34 -0800255static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
256static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
257
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800258/* DC or PWM output fan configuration */
259static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
260static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
261
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800262/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800263
David Bartley578ab5f2013-06-24 22:28:28 -0700264static const u16 NCT6775_REG_TARGET[] = {
265 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
266static const u16 NCT6775_REG_FAN_MODE[] = {
267 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800268static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700269 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800270static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700271 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800272static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700273 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
274static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
275 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800276static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
277static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
278
279static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700280 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
281static const u16 NCT6775_REG_PWM[] = {
282 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
283static const u16 NCT6775_REG_PWM_READ[] = {
284 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800285
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800286static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
287static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800288static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700289static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800290
Guenter Roeckaa136e52012-12-04 03:26:05 -0800291static const u16 NCT6775_REG_TEMP[] = {
292 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
293
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800294static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
295
Guenter Roeckaa136e52012-12-04 03:26:05 -0800296static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
297 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
298static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
299 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
300static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
301 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
302
303static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
304 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
305
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800306static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700307 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800308
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800309static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700310 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800311static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700312 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800313static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700314 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800315static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700316 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800317static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700318 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800319
Guenter Roeckaa136e52012-12-04 03:26:05 -0800320static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
321
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800322static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700323 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800324static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700325 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800326
327#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
328#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
329
330static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
331
332static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700333 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800334static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700335 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800336
Guenter Roeckaa136e52012-12-04 03:26:05 -0800337static const char *const nct6775_temp_label[] = {
338 "",
339 "SYSTIN",
340 "CPUTIN",
341 "AUXTIN",
342 "AMD SB-TSI",
343 "PECI Agent 0",
344 "PECI Agent 1",
345 "PECI Agent 2",
346 "PECI Agent 3",
347 "PECI Agent 4",
348 "PECI Agent 5",
349 "PECI Agent 6",
350 "PECI Agent 7",
351 "PCH_CHIP_CPU_MAX_TEMP",
352 "PCH_CHIP_TEMP",
353 "PCH_CPU_TEMP",
354 "PCH_MCH_TEMP",
355 "PCH_DIM0_TEMP",
356 "PCH_DIM1_TEMP",
357 "PCH_DIM2_TEMP",
358 "PCH_DIM3_TEMP"
359};
360
361static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
362 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
363
364static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
365 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
366 0xa07 };
367
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700368/* NCT6776 specific data */
369
Guenter Roeck728d2942015-08-31 16:13:47 -0700370/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
371#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
372#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
373
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700374static const s8 NCT6776_ALARM_BITS[] = {
375 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
376 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
377 -1, /* unused */
378 6, 7, 11, 10, 23, /* fan1..fan5 */
379 -1, -1, -1, /* unused */
380 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
381 12, 9 }; /* intrusion0, intrusion1 */
382
Guenter Roeck30846992013-06-24 22:21:59 -0700383static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
384
385static const s8 NCT6776_BEEP_BITS[] = {
386 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
387 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
388 24, /* global beep enable */
389 25, 26, 27, 28, 29, /* fan1..fan5 */
390 -1, -1, -1, /* unused */
391 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
392 30, 31 }; /* intrusion0, intrusion1 */
393
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800394static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700395 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800396
David Bartley578ab5f2013-06-24 22:28:28 -0700397static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
398static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800399
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800400static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800401static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800402
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800403static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700404 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800405
Guenter Roeckaa136e52012-12-04 03:26:05 -0800406static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
407 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
408
409static const char *const nct6776_temp_label[] = {
410 "",
411 "SYSTIN",
412 "CPUTIN",
413 "AUXTIN",
414 "SMBUSMASTER 0",
415 "SMBUSMASTER 1",
416 "SMBUSMASTER 2",
417 "SMBUSMASTER 3",
418 "SMBUSMASTER 4",
419 "SMBUSMASTER 5",
420 "SMBUSMASTER 6",
421 "SMBUSMASTER 7",
422 "PECI Agent 0",
423 "PECI Agent 1",
424 "PCH_CHIP_CPU_MAX_TEMP",
425 "PCH_CHIP_TEMP",
426 "PCH_CPU_TEMP",
427 "PCH_MCH_TEMP",
428 "PCH_DIM0_TEMP",
429 "PCH_DIM1_TEMP",
430 "PCH_DIM2_TEMP",
431 "PCH_DIM3_TEMP",
432 "BYTE_TEMP"
433};
434
435static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
436 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
437
438static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
439 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
440
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700441/* NCT6779 specific data */
442
443static const u16 NCT6779_REG_IN[] = {
444 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
445 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
446
447static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
448 0x459, 0x45A, 0x45B, 0x568 };
449
450static const s8 NCT6779_ALARM_BITS[] = {
451 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
452 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
453 -1, /* unused */
454 6, 7, 11, 10, 23, /* fan1..fan5 */
455 -1, -1, -1, /* unused */
456 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
457 12, 9 }; /* intrusion0, intrusion1 */
458
Guenter Roeck30846992013-06-24 22:21:59 -0700459static const s8 NCT6779_BEEP_BITS[] = {
460 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
461 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
462 24, /* global beep enable */
463 25, 26, 27, 28, 29, /* fan1..fan5 */
464 -1, -1, -1, /* unused */
465 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
466 30, 31 }; /* intrusion0, intrusion1 */
467
David Bartley578ab5f2013-06-24 22:28:28 -0700468static const u16 NCT6779_REG_FAN[] = {
469 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800470static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700471 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800472
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800473static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700474 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700475#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800476static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700477 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800478
Guenter Roeckaa136e52012-12-04 03:26:05 -0800479static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800480static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800481static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
482 0x18, 0x152 };
483static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
484 0x3a, 0x153 };
485static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
486 0x39, 0x155 };
487
488static const u16 NCT6779_REG_TEMP_OFFSET[] = {
489 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
490
491static const char *const nct6779_temp_label[] = {
492 "",
493 "SYSTIN",
494 "CPUTIN",
495 "AUXTIN0",
496 "AUXTIN1",
497 "AUXTIN2",
498 "AUXTIN3",
499 "",
500 "SMBUSMASTER 0",
501 "SMBUSMASTER 1",
502 "SMBUSMASTER 2",
503 "SMBUSMASTER 3",
504 "SMBUSMASTER 4",
505 "SMBUSMASTER 5",
506 "SMBUSMASTER 6",
507 "SMBUSMASTER 7",
508 "PECI Agent 0",
509 "PECI Agent 1",
510 "PCH_CHIP_CPU_MAX_TEMP",
511 "PCH_CHIP_TEMP",
512 "PCH_CPU_TEMP",
513 "PCH_MCH_TEMP",
514 "PCH_DIM0_TEMP",
515 "PCH_DIM1_TEMP",
516 "PCH_DIM2_TEMP",
517 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700518 "BYTE_TEMP",
519 "",
520 "",
521 "",
522 "",
523 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800524};
525
Guenter Roeck9a383712015-08-29 15:29:25 -0700526#define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5)
527#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label)
528
529static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800530 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
531 0, 0, 0, 0, 0, 0, 0, 0,
532 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
533 0x408, 0 };
534
Guenter Roeck9a383712015-08-29 15:29:25 -0700535static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800536 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
537
David Bartley578ab5f2013-06-24 22:28:28 -0700538/* NCT6791 specific data */
539
540#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
541
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800542static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
543static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
544static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
545static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
546static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
547static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
548
David Bartley578ab5f2013-06-24 22:28:28 -0700549static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
550 0x459, 0x45A, 0x45B, 0x568, 0x45D };
551
552static const s8 NCT6791_ALARM_BITS[] = {
553 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
554 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
555 -1, /* unused */
556 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
557 -1, -1, /* unused */
558 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
559 12, 9 }; /* intrusion0, intrusion1 */
560
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700561/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800562
563static const u16 NCT6792_REG_TEMP_MON[] = {
564 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
565static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
566 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700567
Guenter Roeck50224f42015-10-30 07:52:39 -0700568static const char *const nct6792_temp_label[] = {
569 "",
570 "SYSTIN",
571 "CPUTIN",
572 "AUXTIN0",
573 "AUXTIN1",
574 "AUXTIN2",
575 "AUXTIN3",
576 "",
577 "SMBUSMASTER 0",
578 "SMBUSMASTER 1",
579 "SMBUSMASTER 2",
580 "SMBUSMASTER 3",
581 "SMBUSMASTER 4",
582 "SMBUSMASTER 5",
583 "SMBUSMASTER 6",
584 "SMBUSMASTER 7",
585 "PECI Agent 0",
586 "PECI Agent 1",
587 "PCH_CHIP_CPU_MAX_TEMP",
588 "PCH_CHIP_TEMP",
589 "PCH_CPU_TEMP",
590 "PCH_MCH_TEMP",
591 "PCH_DIM0_TEMP",
592 "PCH_DIM1_TEMP",
593 "PCH_DIM2_TEMP",
594 "PCH_DIM3_TEMP",
595 "BYTE_TEMP",
596 "PECI Agent 0 Calibration",
597 "PECI Agent 1 Calibration",
598 "",
599 "",
600 "Virtual_TEMP"
601};
602
603static const char *const nct6793_temp_label[] = {
604 "",
605 "SYSTIN",
606 "CPUTIN",
607 "AUXTIN0",
608 "AUXTIN1",
609 "AUXTIN2",
610 "AUXTIN3",
611 "",
612 "SMBUSMASTER 0",
613 "SMBUSMASTER 1",
614 "",
615 "",
616 "",
617 "",
618 "",
619 "",
620 "PECI Agent 0",
621 "PECI Agent 1",
622 "PCH_CHIP_CPU_MAX_TEMP",
623 "PCH_CHIP_TEMP",
624 "PCH_CPU_TEMP",
625 "PCH_MCH_TEMP",
626 "Agent0 Dimm0 ",
627 "Agent0 Dimm1",
628 "Agent1 Dimm0",
629 "Agent1 Dimm1",
630 "BYTE_TEMP0",
631 "BYTE_TEMP1",
632 "PECI Agent 0 Calibration",
633 "PECI Agent 1 Calibration",
634 "",
635 "Virtual_TEMP"
636};
637
Guenter Roeck6c009502012-07-01 08:23:15 -0700638/* NCT6102D/NCT6106D specific data */
639
640#define NCT6106_REG_VBAT 0x318
641#define NCT6106_REG_DIODE 0x319
642#define NCT6106_DIODE_MASK 0x01
643
644static const u16 NCT6106_REG_IN_MAX[] = {
645 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
646static const u16 NCT6106_REG_IN_MIN[] = {
647 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
648static const u16 NCT6106_REG_IN[] = {
649 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
650
651static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800652static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700653static const u16 NCT6106_REG_TEMP_HYST[] = {
654 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
655static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700656 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
657static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
658 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
659static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
660 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700661static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
662static const u16 NCT6106_REG_TEMP_CONFIG[] = {
663 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
664
665static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
666static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
667static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
668static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
669
670static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
671static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
672static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
673static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
674static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
675static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
676static const u16 NCT6106_REG_TEMP_SOURCE[] = {
677 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
678
679static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
680static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
681 0x11b, 0x12b, 0x13b };
682
683static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
684#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
685static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
686
687static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
688static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
689static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
690static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
691static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
692static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
693
694static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
695
696static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
697static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
698static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
699static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
700static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
701static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
702
703static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
704static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
705
706static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
707 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
708
709static const s8 NCT6106_ALARM_BITS[] = {
710 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
711 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
712 -1, /* unused */
713 32, 33, 34, -1, -1, /* fan1..fan5 */
714 -1, -1, -1, /* unused */
715 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
716 48, -1 /* intrusion0, intrusion1 */
717};
718
Guenter Roeck30846992013-06-24 22:21:59 -0700719static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
720 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
721
722static const s8 NCT6106_BEEP_BITS[] = {
723 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
724 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
725 32, /* global beep enable */
726 24, 25, 26, 27, 28, /* fan1..fan5 */
727 -1, -1, -1, /* unused */
728 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
729 34, -1 /* intrusion0, intrusion1 */
730};
731
Guenter Roeck6c009502012-07-01 08:23:15 -0700732static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
733 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
734
735static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
736 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
737
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800738static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
739{
740 if (mode == 0 && pwm == 255)
741 return off;
742 return mode + 1;
743}
744
745static int pwm_enable_to_reg(enum pwm_enable mode)
746{
747 if (mode == off)
748 return 0;
749 return mode - 1;
750}
751
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700752/*
753 * Conversions
754 */
755
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800756/* 1 is DC mode, output in ms */
757static unsigned int step_time_from_reg(u8 reg, u8 mode)
758{
759 return mode ? 400 * reg : 100 * reg;
760}
761
762static u8 step_time_to_reg(unsigned int msec, u8 mode)
763{
764 return clamp_val((mode ? (msec + 200) / 400 :
765 (msec + 50) / 100), 1, 255);
766}
767
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800768static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
769{
770 if (reg == 0 || reg == 255)
771 return 0;
772 return 1350000U / (reg << divreg);
773}
774
775static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
776{
777 if ((reg & 0xff1f) == 0xff1f)
778 return 0;
779
780 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
781
782 if (reg == 0)
783 return 0;
784
785 return 1350000U / reg;
786}
787
788static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
789{
790 if (reg == 0 || reg == 0xffff)
791 return 0;
792
793 /*
794 * Even though the registers are 16 bit wide, the fan divisor
795 * still applies.
796 */
797 return 1350000U / (reg << divreg);
798}
799
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800800static u16 fan_to_reg(u32 fan, unsigned int divreg)
801{
802 if (!fan)
803 return 0;
804
805 return (1350000U / fan) >> divreg;
806}
807
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800808static inline unsigned int
809div_from_reg(u8 reg)
810{
811 return 1 << reg;
812}
813
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700814/*
815 * Some of the voltage inputs have internal scaling, the tables below
816 * contain 8 (the ADC LSB in mV) * scaling factor * 100
817 */
818static const u16 scale_in[15] = {
819 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
820 800, 800
821};
822
823static inline long in_from_reg(u8 reg, u8 nr)
824{
825 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
826}
827
828static inline u8 in_to_reg(u32 val, u8 nr)
829{
830 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
831}
832
833/*
834 * Data structures and manipulation thereof
835 */
836
837struct nct6775_data {
838 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700839 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700840 enum kinds kind;
841 const char *name;
842
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700843 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700844
Guenter Roeckb7a61352013-04-02 22:14:06 -0700845 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
846 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800847 */
848 u8 temp_src[NUM_TEMP];
849 u16 reg_temp_config[NUM_TEMP];
850 const char * const *temp_label;
851 int temp_label_num;
852
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700853 u16 REG_CONFIG;
854 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800855 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700856 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700857
858 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700859 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700860
861 const u16 *REG_VIN;
862 const u16 *REG_IN_MINMAX[2];
863
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800864 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800865 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800866 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800867 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800868 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700869 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800870 const u16 *REG_FAN_TIME[3];
871
872 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800873
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800874 const u8 *REG_PWM_MODE;
875 const u8 *PWM_MODE_MASK;
876
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800877 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
878 * [3]=pwm_max, [4]=pwm_step,
879 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800880 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800881 const u16 *REG_PWM_READ;
882
Guenter Roeck6c009502012-07-01 08:23:15 -0700883 const u16 *REG_CRITICAL_PWM_ENABLE;
884 u8 CRITICAL_PWM_ENABLE_MASK;
885 const u16 *REG_CRITICAL_PWM;
886
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800887 const u16 *REG_AUTO_TEMP;
888 const u16 *REG_AUTO_PWM;
889
890 const u16 *REG_CRITICAL_TEMP;
891 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
892
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800893 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800894 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800895 const u16 *REG_WEIGHT_TEMP_SEL;
896 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
897
Guenter Roeckaa136e52012-12-04 03:26:05 -0800898 const u16 *REG_TEMP_OFFSET;
899
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700900 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700901 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700902
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800903 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
904 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
905
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700906 struct mutex update_lock;
907 bool valid; /* true if following fields are valid */
908 unsigned long last_updated; /* In jiffies */
909
910 /* Register values */
911 u8 bank; /* current register bank */
912 u8 in_num; /* number of in inputs we have */
913 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700914 unsigned int rpm[NUM_FAN];
915 u16 fan_min[NUM_FAN];
916 u8 fan_pulses[NUM_FAN];
917 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800918 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800919 u8 has_fan; /* some fan inputs can be disabled */
920 u8 has_fan_min; /* some fans don't have min register */
921 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700922
Guenter Roeck6c009502012-07-01 08:23:15 -0700923 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700924 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800925 u8 temp_fixed_num; /* 3 or 6 */
926 u8 temp_type[NUM_TEMP_FIXED];
927 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300928 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
929 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700930 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700931 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700932
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800933 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700934 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
935 * 0->PWM variable duty cycle
936 */
937 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800938 /* 0->off
939 * 1->manual
940 * 2->thermal cruise mode (also called SmartFan I)
941 * 3->fan speed cruise mode
942 * 4->SmartFan III
943 * 5->enhanced variable thermal cruise (SmartFan IV)
944 */
David Bartley578ab5f2013-06-24 22:28:28 -0700945 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
946 * [3]=pwm_max, [4]=pwm_step,
947 * [5]=weight_duty_step, [6]=weight_duty_base
948 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800949
David Bartley578ab5f2013-06-24 22:28:28 -0700950 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800951 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700952 u32 target_speed[NUM_FAN];
953 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800954 u8 speed_tolerance_limit;
955
David Bartley578ab5f2013-06-24 22:28:28 -0700956 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800957 u8 tolerance_mask;
958
David Bartley578ab5f2013-06-24 22:28:28 -0700959 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800960
961 /* Automatic fan speed control registers */
962 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700963 u8 auto_pwm[NUM_FAN][7];
964 u8 auto_temp[NUM_FAN][7];
965 u8 pwm_temp_sel[NUM_FAN];
966 u8 pwm_weight_temp_sel[NUM_FAN];
967 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
968 * 2->temp_base
969 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800970
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700971 u8 vid;
972 u8 vrm;
973
Guenter Roeckf73cf632013-03-18 09:22:50 -0700974 bool have_vid;
975
Guenter Roeckaa136e52012-12-04 03:26:05 -0800976 u16 have_temp;
977 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700978 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800979
Guenter Roeck84d19d92012-12-04 08:01:39 -0800980 /* Remember extra register values over suspend/resume */
981 u8 vbat;
982 u8 fandiv1;
983 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800984 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700985};
986
987struct nct6775_sio_data {
988 int sioreg;
989 enum kinds kind;
990};
991
Guenter Roeckf73cf632013-03-18 09:22:50 -0700992struct sensor_device_template {
993 struct device_attribute dev_attr;
994 union {
995 struct {
996 u8 nr;
997 u8 index;
998 } s;
999 int index;
1000 } u;
1001 bool s2; /* true if both index and nr are used */
1002};
1003
1004struct sensor_device_attr_u {
1005 union {
1006 struct sensor_device_attribute a1;
1007 struct sensor_device_attribute_2 a2;
1008 } u;
1009 char name[32];
1010};
1011
1012#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1013 .attr = {.name = _template, .mode = _mode }, \
1014 .show = _show, \
1015 .store = _store, \
1016}
1017
1018#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1019 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1020 .u.index = _index, \
1021 .s2 = false }
1022
1023#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1024 _nr, _index) \
1025 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1026 .u.s.index = _index, \
1027 .u.s.nr = _nr, \
1028 .s2 = true }
1029
1030#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1031static struct sensor_device_template sensor_dev_template_##_name \
1032 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1033 _index)
1034
1035#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1036 _nr, _index) \
1037static struct sensor_device_template sensor_dev_template_##_name \
1038 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1039 _nr, _index)
1040
1041struct sensor_template_group {
1042 struct sensor_device_template **templates;
1043 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1044 int base;
1045};
1046
1047static struct attribute_group *
1048nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
1049 int repeat)
1050{
1051 struct attribute_group *group;
1052 struct sensor_device_attr_u *su;
1053 struct sensor_device_attribute *a;
1054 struct sensor_device_attribute_2 *a2;
1055 struct attribute **attrs;
1056 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001057 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001058
1059 if (repeat <= 0)
1060 return ERR_PTR(-EINVAL);
1061
1062 t = tg->templates;
1063 for (count = 0; *t; t++, count++)
1064 ;
1065
1066 if (count == 0)
1067 return ERR_PTR(-EINVAL);
1068
1069 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1070 if (group == NULL)
1071 return ERR_PTR(-ENOMEM);
1072
1073 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1074 GFP_KERNEL);
1075 if (attrs == NULL)
1076 return ERR_PTR(-ENOMEM);
1077
1078 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1079 GFP_KERNEL);
1080 if (su == NULL)
1081 return ERR_PTR(-ENOMEM);
1082
1083 group->attrs = attrs;
1084 group->is_visible = tg->is_visible;
1085
1086 for (i = 0; i < repeat; i++) {
1087 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001088 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001089 snprintf(su->name, sizeof(su->name),
1090 (*t)->dev_attr.attr.name, tg->base + i);
1091 if ((*t)->s2) {
1092 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001093 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001094 a2->dev_attr.attr.name = su->name;
1095 a2->nr = (*t)->u.s.nr + i;
1096 a2->index = (*t)->u.s.index;
1097 a2->dev_attr.attr.mode =
1098 (*t)->dev_attr.attr.mode;
1099 a2->dev_attr.show = (*t)->dev_attr.show;
1100 a2->dev_attr.store = (*t)->dev_attr.store;
1101 *attrs = &a2->dev_attr.attr;
1102 } else {
1103 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001104 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001105 a->dev_attr.attr.name = su->name;
1106 a->index = (*t)->u.index + i;
1107 a->dev_attr.attr.mode =
1108 (*t)->dev_attr.attr.mode;
1109 a->dev_attr.show = (*t)->dev_attr.show;
1110 a->dev_attr.store = (*t)->dev_attr.store;
1111 *attrs = &a->dev_attr.attr;
1112 }
1113 attrs++;
1114 su++;
1115 t++;
1116 }
1117 }
1118
Guenter Roeckf73cf632013-03-18 09:22:50 -07001119 return group;
1120}
1121
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001122static bool is_word_sized(struct nct6775_data *data, u16 reg)
1123{
1124 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001125 case nct6106:
1126 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1127 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1128 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001129 case nct6775:
1130 return (((reg & 0xff00) == 0x100 ||
1131 (reg & 0xff00) == 0x200) &&
1132 ((reg & 0x00ff) == 0x50 ||
1133 (reg & 0x00ff) == 0x53 ||
1134 (reg & 0x00ff) == 0x55)) ||
1135 (reg & 0xfff0) == 0x630 ||
1136 reg == 0x640 || reg == 0x642 ||
1137 reg == 0x662 ||
1138 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1139 reg == 0x73 || reg == 0x75 || reg == 0x77;
1140 case nct6776:
1141 return (((reg & 0xff00) == 0x100 ||
1142 (reg & 0xff00) == 0x200) &&
1143 ((reg & 0x00ff) == 0x50 ||
1144 (reg & 0x00ff) == 0x53 ||
1145 (reg & 0x00ff) == 0x55)) ||
1146 (reg & 0xfff0) == 0x630 ||
1147 reg == 0x402 ||
1148 reg == 0x640 || reg == 0x642 ||
1149 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1150 reg == 0x73 || reg == 0x75 || reg == 0x77;
1151 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001152 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001153 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001154 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001155 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001156 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001157 reg == 0x402 ||
1158 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1159 reg == 0x640 || reg == 0x642 ||
1160 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001161 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001162 }
1163 return false;
1164}
1165
1166/*
1167 * On older chips, only registers 0x50-0x5f are banked.
1168 * On more recent chips, all registers are banked.
1169 * Assume that is the case and set the bank number for each access.
1170 * Cache the bank number so it only needs to be set if it changes.
1171 */
1172static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1173{
1174 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001175
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001176 if (data->bank != bank) {
1177 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1178 outb_p(bank, data->addr + DATA_REG_OFFSET);
1179 data->bank = bank;
1180 }
1181}
1182
1183static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1184{
1185 int res, word_sized = is_word_sized(data, reg);
1186
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001187 nct6775_set_bank(data, reg);
1188 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1189 res = inb_p(data->addr + DATA_REG_OFFSET);
1190 if (word_sized) {
1191 outb_p((reg & 0xff) + 1,
1192 data->addr + ADDR_REG_OFFSET);
1193 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1194 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001195 return res;
1196}
1197
1198static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1199{
1200 int word_sized = is_word_sized(data, reg);
1201
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001202 nct6775_set_bank(data, reg);
1203 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1204 if (word_sized) {
1205 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1206 outb_p((reg & 0xff) + 1,
1207 data->addr + ADDR_REG_OFFSET);
1208 }
1209 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001210 return 0;
1211}
1212
Guenter Roeckaa136e52012-12-04 03:26:05 -08001213/* We left-align 8-bit temperature values to make the code simpler */
1214static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1215{
1216 u16 res;
1217
1218 res = nct6775_read_value(data, reg);
1219 if (!is_word_sized(data, reg))
1220 res <<= 8;
1221
1222 return res;
1223}
1224
1225static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1226{
1227 if (!is_word_sized(data, reg))
1228 value >>= 8;
1229 return nct6775_write_value(data, reg, value);
1230}
1231
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001232/* This function assumes that the caller holds data->update_lock */
1233static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1234{
1235 u8 reg;
1236
1237 switch (nr) {
1238 case 0:
1239 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1240 | (data->fan_div[0] & 0x7);
1241 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1242 break;
1243 case 1:
1244 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1245 | ((data->fan_div[1] << 4) & 0x70);
1246 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1247 break;
1248 case 2:
1249 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1250 | (data->fan_div[2] & 0x7);
1251 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1252 break;
1253 case 3:
1254 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1255 | ((data->fan_div[3] << 4) & 0x70);
1256 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1257 break;
1258 }
1259}
1260
1261static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1262{
1263 if (data->kind == nct6775)
1264 nct6775_write_fan_div(data, nr);
1265}
1266
1267static void nct6775_update_fan_div(struct nct6775_data *data)
1268{
1269 u8 i;
1270
1271 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1272 data->fan_div[0] = i & 0x7;
1273 data->fan_div[1] = (i & 0x70) >> 4;
1274 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1275 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001276 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001277 data->fan_div[3] = (i & 0x70) >> 4;
1278}
1279
1280static void nct6775_update_fan_div_common(struct nct6775_data *data)
1281{
1282 if (data->kind == nct6775)
1283 nct6775_update_fan_div(data);
1284}
1285
1286static void nct6775_init_fan_div(struct nct6775_data *data)
1287{
1288 int i;
1289
1290 nct6775_update_fan_div_common(data);
1291 /*
1292 * For all fans, start with highest divider value if the divider
1293 * register is not initialized. This ensures that we get a
1294 * reading from the fan count register, even if it is not optimal.
1295 * We'll compute a better divider later on.
1296 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001297 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001298 if (!(data->has_fan & (1 << i)))
1299 continue;
1300 if (data->fan_div[i] == 0) {
1301 data->fan_div[i] = 7;
1302 nct6775_write_fan_div_common(data, i);
1303 }
1304 }
1305}
1306
1307static void nct6775_init_fan_common(struct device *dev,
1308 struct nct6775_data *data)
1309{
1310 int i;
1311 u8 reg;
1312
1313 if (data->has_fan_div)
1314 nct6775_init_fan_div(data);
1315
1316 /*
1317 * If fan_min is not set (0), set it to 0xff to disable it. This
1318 * prevents the unnecessary warning when fanX_min is reported as 0.
1319 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001320 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001321 if (data->has_fan_min & (1 << i)) {
1322 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1323 if (!reg)
1324 nct6775_write_value(data, data->REG_FAN_MIN[i],
1325 data->has_fan_div ? 0xff
1326 : 0xff1f);
1327 }
1328 }
1329}
1330
1331static void nct6775_select_fan_div(struct device *dev,
1332 struct nct6775_data *data, int nr, u16 reg)
1333{
1334 u8 fan_div = data->fan_div[nr];
1335 u16 fan_min;
1336
1337 if (!data->has_fan_div)
1338 return;
1339
1340 /*
1341 * If we failed to measure the fan speed, or the reported value is not
1342 * in the optimal range, and the clock divider can be modified,
1343 * let's try that for next time.
1344 */
1345 if (reg == 0x00 && fan_div < 0x07)
1346 fan_div++;
1347 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1348 fan_div--;
1349
1350 if (fan_div != data->fan_div[nr]) {
1351 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1352 nr + 1, div_from_reg(data->fan_div[nr]),
1353 div_from_reg(fan_div));
1354
1355 /* Preserve min limit if possible */
1356 if (data->has_fan_min & (1 << nr)) {
1357 fan_min = data->fan_min[nr];
1358 if (fan_div > data->fan_div[nr]) {
1359 if (fan_min != 255 && fan_min > 1)
1360 fan_min >>= 1;
1361 } else {
1362 if (fan_min != 255) {
1363 fan_min <<= 1;
1364 if (fan_min > 254)
1365 fan_min = 254;
1366 }
1367 }
1368 if (fan_min != data->fan_min[nr]) {
1369 data->fan_min[nr] = fan_min;
1370 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1371 fan_min);
1372 }
1373 }
1374 data->fan_div[nr] = fan_div;
1375 nct6775_write_fan_div_common(data, nr);
1376 }
1377}
1378
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001379static void nct6775_update_pwm(struct device *dev)
1380{
1381 struct nct6775_data *data = dev_get_drvdata(dev);
1382 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001383 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001384 bool duty_is_dc;
1385
1386 for (i = 0; i < data->pwm_num; i++) {
1387 if (!(data->has_pwm & (1 << i)))
1388 continue;
1389
1390 duty_is_dc = data->REG_PWM_MODE[i] &&
1391 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1392 & data->PWM_MODE_MASK[i]);
1393 data->pwm_mode[i] = duty_is_dc;
1394
1395 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1396 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1397 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1398 data->pwm[j][i]
1399 = nct6775_read_value(data,
1400 data->REG_PWM[j][i]);
1401 }
1402 }
1403
1404 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1405 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001406
1407 if (!data->temp_tolerance[0][i] ||
1408 data->pwm_enable[i] != speed_cruise)
1409 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1410 if (!data->target_speed_tolerance[i] ||
1411 data->pwm_enable[i] == speed_cruise) {
1412 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001413
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001414 if (data->REG_TOLERANCE_H) {
1415 t |= (nct6775_read_value(data,
1416 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1417 }
1418 data->target_speed_tolerance[i] = t;
1419 }
1420
1421 data->temp_tolerance[1][i] =
1422 nct6775_read_value(data,
1423 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1424
1425 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1426 data->pwm_temp_sel[i] = reg & 0x1f;
1427 /* If fan can stop, report floor as 0 */
1428 if (reg & 0x80)
1429 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001430
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001431 if (!data->REG_WEIGHT_TEMP_SEL[i])
1432 continue;
1433
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001434 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1435 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1436 /* If weight is disabled, report weight source as 0 */
1437 if (j == 1 && !(reg & 0x80))
1438 data->pwm_weight_temp_sel[i] = 0;
1439
1440 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001441 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001442 data->weight_temp[j][i]
1443 = nct6775_read_value(data,
1444 data->REG_WEIGHT_TEMP[j][i]);
1445 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001446 }
1447}
1448
1449static void nct6775_update_pwm_limits(struct device *dev)
1450{
1451 struct nct6775_data *data = dev_get_drvdata(dev);
1452 int i, j;
1453 u8 reg;
1454 u16 reg_t;
1455
1456 for (i = 0; i < data->pwm_num; i++) {
1457 if (!(data->has_pwm & (1 << i)))
1458 continue;
1459
Guenter Roeckc409fd42013-04-09 05:04:00 -07001460 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001461 data->fan_time[j][i] =
1462 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1463 }
1464
1465 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1466 /* Update only in matching mode or if never updated */
1467 if (!data->target_temp[i] ||
1468 data->pwm_enable[i] == thermal_cruise)
1469 data->target_temp[i] = reg_t & data->target_temp_mask;
1470 if (!data->target_speed[i] ||
1471 data->pwm_enable[i] == speed_cruise) {
1472 if (data->REG_TOLERANCE_H) {
1473 reg_t |= (nct6775_read_value(data,
1474 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1475 }
1476 data->target_speed[i] = reg_t;
1477 }
1478
1479 for (j = 0; j < data->auto_pwm_num; j++) {
1480 data->auto_pwm[i][j] =
1481 nct6775_read_value(data,
1482 NCT6775_AUTO_PWM(data, i, j));
1483 data->auto_temp[i][j] =
1484 nct6775_read_value(data,
1485 NCT6775_AUTO_TEMP(data, i, j));
1486 }
1487
1488 /* critical auto_pwm temperature data */
1489 data->auto_temp[i][data->auto_pwm_num] =
1490 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1491
1492 switch (data->kind) {
1493 case nct6775:
1494 reg = nct6775_read_value(data,
1495 NCT6775_REG_CRITICAL_ENAB[i]);
1496 data->auto_pwm[i][data->auto_pwm_num] =
1497 (reg & 0x02) ? 0xff : 0x00;
1498 break;
1499 case nct6776:
1500 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1501 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001502 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001503 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001504 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001505 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001506 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001507 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001508 data->REG_CRITICAL_PWM_ENABLE[i]);
1509 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1510 reg = nct6775_read_value(data,
1511 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001512 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001513 reg = 0xff;
1514 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001515 break;
1516 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001517 }
1518}
1519
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001520static struct nct6775_data *nct6775_update_device(struct device *dev)
1521{
1522 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001523 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001524
1525 mutex_lock(&data->update_lock);
1526
Guenter Roeck6445e662013-04-21 09:13:28 -07001527 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001528 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001529 /* Fan clock dividers */
1530 nct6775_update_fan_div_common(data);
1531
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001532 /* Measured voltages and limits */
1533 for (i = 0; i < data->in_num; i++) {
1534 if (!(data->have_in & (1 << i)))
1535 continue;
1536
1537 data->in[i][0] = nct6775_read_value(data,
1538 data->REG_VIN[i]);
1539 data->in[i][1] = nct6775_read_value(data,
1540 data->REG_IN_MINMAX[0][i]);
1541 data->in[i][2] = nct6775_read_value(data,
1542 data->REG_IN_MINMAX[1][i]);
1543 }
1544
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001545 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001546 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001547 u16 reg;
1548
1549 if (!(data->has_fan & (1 << i)))
1550 continue;
1551
1552 reg = nct6775_read_value(data, data->REG_FAN[i]);
1553 data->rpm[i] = data->fan_from_reg(reg,
1554 data->fan_div[i]);
1555
1556 if (data->has_fan_min & (1 << i))
1557 data->fan_min[i] = nct6775_read_value(data,
1558 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001559 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001560 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1561 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001562
1563 nct6775_select_fan_div(dev, data, i, reg);
1564 }
1565
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001566 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001567 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001568
Guenter Roeckaa136e52012-12-04 03:26:05 -08001569 /* Measured temperatures and limits */
1570 for (i = 0; i < NUM_TEMP; i++) {
1571 if (!(data->have_temp & (1 << i)))
1572 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001573 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001574 if (data->reg_temp[j][i])
1575 data->temp[j][i]
1576 = nct6775_read_temp(data,
1577 data->reg_temp[j][i]);
1578 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001579 if (i >= NUM_TEMP_FIXED ||
1580 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001581 continue;
1582 data->temp_offset[i]
1583 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1584 }
1585
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001586 data->alarms = 0;
1587 for (i = 0; i < NUM_REG_ALARM; i++) {
1588 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001589
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001590 if (!data->REG_ALARM[i])
1591 continue;
1592 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1593 data->alarms |= ((u64)alarm) << (i << 3);
1594 }
1595
Guenter Roeck30846992013-06-24 22:21:59 -07001596 data->beeps = 0;
1597 for (i = 0; i < NUM_REG_BEEP; i++) {
1598 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001599
Guenter Roeck30846992013-06-24 22:21:59 -07001600 if (!data->REG_BEEP[i])
1601 continue;
1602 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1603 data->beeps |= ((u64)beep) << (i << 3);
1604 }
1605
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001606 data->last_updated = jiffies;
1607 data->valid = true;
1608 }
1609
1610 mutex_unlock(&data->update_lock);
1611 return data;
1612}
1613
1614/*
1615 * Sysfs callback functions
1616 */
1617static ssize_t
1618show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1619{
1620 struct nct6775_data *data = nct6775_update_device(dev);
1621 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001622 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001623 int nr = sattr->nr;
1624
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001625 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1626}
1627
1628static ssize_t
1629store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1630 size_t count)
1631{
1632 struct nct6775_data *data = dev_get_drvdata(dev);
1633 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001634 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001635 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001636 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001637 int err;
1638
1639 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001640 if (err < 0)
1641 return err;
1642 mutex_lock(&data->update_lock);
1643 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001644 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001645 data->in[nr][index]);
1646 mutex_unlock(&data->update_lock);
1647 return count;
1648}
1649
1650static ssize_t
1651show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1652{
1653 struct nct6775_data *data = nct6775_update_device(dev);
1654 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1655 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001656
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001657 return sprintf(buf, "%u\n",
1658 (unsigned int)((data->alarms >> nr) & 0x01));
1659}
1660
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001661static int find_temp_source(struct nct6775_data *data, int index, int count)
1662{
1663 int source = data->temp_src[index];
1664 int nr;
1665
1666 for (nr = 0; nr < count; nr++) {
1667 int src;
1668
1669 src = nct6775_read_value(data,
1670 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1671 if (src == source)
1672 return nr;
1673 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001674 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001675}
1676
1677static ssize_t
1678show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1679{
1680 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1681 struct nct6775_data *data = nct6775_update_device(dev);
1682 unsigned int alarm = 0;
1683 int nr;
1684
1685 /*
1686 * For temperatures, there is no fixed mapping from registers to alarm
1687 * bits. Alarm bits are determined by the temperature source mapping.
1688 */
1689 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1690 if (nr >= 0) {
1691 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001692
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001693 alarm = (data->alarms >> bit) & 0x01;
1694 }
1695 return sprintf(buf, "%u\n", alarm);
1696}
1697
Guenter Roeck30846992013-06-24 22:21:59 -07001698static ssize_t
1699show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1700{
1701 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1702 struct nct6775_data *data = nct6775_update_device(dev);
1703 int nr = data->BEEP_BITS[sattr->index];
1704
1705 return sprintf(buf, "%u\n",
1706 (unsigned int)((data->beeps >> nr) & 0x01));
1707}
1708
1709static ssize_t
1710store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1711 size_t count)
1712{
1713 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1714 struct nct6775_data *data = dev_get_drvdata(dev);
1715 int nr = data->BEEP_BITS[sattr->index];
1716 int regindex = nr >> 3;
1717 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001718 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001719
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001720 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001721 if (err < 0)
1722 return err;
1723 if (val > 1)
1724 return -EINVAL;
1725
1726 mutex_lock(&data->update_lock);
1727 if (val)
1728 data->beeps |= (1ULL << nr);
1729 else
1730 data->beeps &= ~(1ULL << nr);
1731 nct6775_write_value(data, data->REG_BEEP[regindex],
1732 (data->beeps >> (regindex << 3)) & 0xff);
1733 mutex_unlock(&data->update_lock);
1734 return count;
1735}
1736
1737static ssize_t
1738show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1739{
1740 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1741 struct nct6775_data *data = nct6775_update_device(dev);
1742 unsigned int beep = 0;
1743 int nr;
1744
1745 /*
1746 * For temperatures, there is no fixed mapping from registers to beep
1747 * enable bits. Beep enable bits are determined by the temperature
1748 * source mapping.
1749 */
1750 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1751 if (nr >= 0) {
1752 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001753
Guenter Roeck30846992013-06-24 22:21:59 -07001754 beep = (data->beeps >> bit) & 0x01;
1755 }
1756 return sprintf(buf, "%u\n", beep);
1757}
1758
1759static ssize_t
1760store_temp_beep(struct device *dev, struct device_attribute *attr,
1761 const char *buf, size_t count)
1762{
1763 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1764 struct nct6775_data *data = dev_get_drvdata(dev);
1765 int nr, bit, regindex;
1766 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001767 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001768
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001769 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001770 if (err < 0)
1771 return err;
1772 if (val > 1)
1773 return -EINVAL;
1774
1775 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1776 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001777 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001778
1779 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1780 regindex = bit >> 3;
1781
1782 mutex_lock(&data->update_lock);
1783 if (val)
1784 data->beeps |= (1ULL << bit);
1785 else
1786 data->beeps &= ~(1ULL << bit);
1787 nct6775_write_value(data, data->REG_BEEP[regindex],
1788 (data->beeps >> (regindex << 3)) & 0xff);
1789 mutex_unlock(&data->update_lock);
1790
1791 return count;
1792}
1793
Guenter Roeckf73cf632013-03-18 09:22:50 -07001794static umode_t nct6775_in_is_visible(struct kobject *kobj,
1795 struct attribute *attr, int index)
1796{
1797 struct device *dev = container_of(kobj, struct device, kobj);
1798 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001799 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001800
Guenter Roeckf73cf632013-03-18 09:22:50 -07001801 if (!(data->have_in & (1 << in)))
1802 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001803
Guenter Roeckf73cf632013-03-18 09:22:50 -07001804 return attr->mode;
1805}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001806
Guenter Roeckf73cf632013-03-18 09:22:50 -07001807SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1808SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001809SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1810 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001811SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1812 store_in_reg, 0, 1);
1813SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1814 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001815
Guenter Roeckf73cf632013-03-18 09:22:50 -07001816/*
1817 * nct6775_in_is_visible uses the index into the following array
1818 * to determine if attributes should be created or not.
1819 * Any change in order or content must be matched.
1820 */
1821static struct sensor_device_template *nct6775_attributes_in_template[] = {
1822 &sensor_dev_template_in_input,
1823 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001824 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001825 &sensor_dev_template_in_min,
1826 &sensor_dev_template_in_max,
1827 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001828};
1829
Guenter Roeckf73cf632013-03-18 09:22:50 -07001830static struct sensor_template_group nct6775_in_template_group = {
1831 .templates = nct6775_attributes_in_template,
1832 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001833};
1834
1835static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001836show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1837{
1838 struct nct6775_data *data = nct6775_update_device(dev);
1839 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1840 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001841
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001842 return sprintf(buf, "%d\n", data->rpm[nr]);
1843}
1844
1845static ssize_t
1846show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1847{
1848 struct nct6775_data *data = nct6775_update_device(dev);
1849 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1850 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001851
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001852 return sprintf(buf, "%d\n",
1853 data->fan_from_reg_min(data->fan_min[nr],
1854 data->fan_div[nr]));
1855}
1856
1857static ssize_t
1858show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1859{
1860 struct nct6775_data *data = nct6775_update_device(dev);
1861 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1862 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001863
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001864 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1865}
1866
1867static ssize_t
1868store_fan_min(struct device *dev, struct device_attribute *attr,
1869 const char *buf, size_t count)
1870{
1871 struct nct6775_data *data = dev_get_drvdata(dev);
1872 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1873 int nr = sattr->index;
1874 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001875 unsigned int reg;
1876 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001877 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001878
1879 err = kstrtoul(buf, 10, &val);
1880 if (err < 0)
1881 return err;
1882
1883 mutex_lock(&data->update_lock);
1884 if (!data->has_fan_div) {
1885 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1886 if (!val) {
1887 val = 0xff1f;
1888 } else {
1889 if (val > 1350000U)
1890 val = 135000U;
1891 val = 1350000U / val;
1892 val = (val & 0x1f) | ((val << 3) & 0xff00);
1893 }
1894 data->fan_min[nr] = val;
1895 goto write_min; /* Leave fan divider alone */
1896 }
1897 if (!val) {
1898 /* No min limit, alarm disabled */
1899 data->fan_min[nr] = 255;
1900 new_div = data->fan_div[nr]; /* No change */
1901 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1902 goto write_div;
1903 }
1904 reg = 1350000U / val;
1905 if (reg >= 128 * 255) {
1906 /*
1907 * Speed below this value cannot possibly be represented,
1908 * even with the highest divider (128)
1909 */
1910 data->fan_min[nr] = 254;
1911 new_div = 7; /* 128 == (1 << 7) */
1912 dev_warn(dev,
1913 "fan%u low limit %lu below minimum %u, set to minimum\n",
1914 nr + 1, val, data->fan_from_reg_min(254, 7));
1915 } else if (!reg) {
1916 /*
1917 * Speed above this value cannot possibly be represented,
1918 * even with the lowest divider (1)
1919 */
1920 data->fan_min[nr] = 1;
1921 new_div = 0; /* 1 == (1 << 0) */
1922 dev_warn(dev,
1923 "fan%u low limit %lu above maximum %u, set to maximum\n",
1924 nr + 1, val, data->fan_from_reg_min(1, 0));
1925 } else {
1926 /*
1927 * Automatically pick the best divider, i.e. the one such
1928 * that the min limit will correspond to a register value
1929 * in the 96..192 range
1930 */
1931 new_div = 0;
1932 while (reg > 192 && new_div < 7) {
1933 reg >>= 1;
1934 new_div++;
1935 }
1936 data->fan_min[nr] = reg;
1937 }
1938
1939write_div:
1940 /*
1941 * Write both the fan clock divider (if it changed) and the new
1942 * fan min (unconditionally)
1943 */
1944 if (new_div != data->fan_div[nr]) {
1945 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1946 nr + 1, div_from_reg(data->fan_div[nr]),
1947 div_from_reg(new_div));
1948 data->fan_div[nr] = new_div;
1949 nct6775_write_fan_div_common(data, nr);
1950 /* Give the chip time to sample a new speed value */
1951 data->last_updated = jiffies;
1952 }
1953
1954write_min:
1955 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1956 mutex_unlock(&data->update_lock);
1957
1958 return count;
1959}
1960
Guenter Roeck5c25d952012-12-11 07:29:06 -08001961static ssize_t
1962show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1963{
1964 struct nct6775_data *data = nct6775_update_device(dev);
1965 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1966 int p = data->fan_pulses[sattr->index];
1967
1968 return sprintf(buf, "%d\n", p ? : 4);
1969}
1970
1971static ssize_t
1972store_fan_pulses(struct device *dev, struct device_attribute *attr,
1973 const char *buf, size_t count)
1974{
1975 struct nct6775_data *data = dev_get_drvdata(dev);
1976 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1977 int nr = sattr->index;
1978 unsigned long val;
1979 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001980 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001981
1982 err = kstrtoul(buf, 10, &val);
1983 if (err < 0)
1984 return err;
1985
1986 if (val > 4)
1987 return -EINVAL;
1988
1989 mutex_lock(&data->update_lock);
1990 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001991 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1992 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1993 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1994 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001995 mutex_unlock(&data->update_lock);
1996
1997 return count;
1998}
1999
Guenter Roeckf73cf632013-03-18 09:22:50 -07002000static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2001 struct attribute *attr, int index)
2002{
2003 struct device *dev = container_of(kobj, struct device, kobj);
2004 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002005 int fan = index / 6; /* fan index */
2006 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002007
2008 if (!(data->has_fan & (1 << fan)))
2009 return 0;
2010
2011 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2012 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002013 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002014 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002015 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
2016 return 0;
2017 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002018 return 0;
2019
2020 return attr->mode;
2021}
2022
2023SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2024SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2025 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002026SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2027 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002028SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2029 store_fan_pulses, 0);
2030SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2031 store_fan_min, 0);
2032SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2033
2034/*
2035 * nct6775_fan_is_visible uses the index into the following array
2036 * to determine if attributes should be created or not.
2037 * Any change in order or content must be matched.
2038 */
2039static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2040 &sensor_dev_template_fan_input,
2041 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002042 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002043 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002044 &sensor_dev_template_fan_min, /* 4 */
2045 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002046 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002047};
2048
Guenter Roeckf73cf632013-03-18 09:22:50 -07002049static struct sensor_template_group nct6775_fan_template_group = {
2050 .templates = nct6775_attributes_fan_template,
2051 .is_visible = nct6775_fan_is_visible,
2052 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002053};
2054
2055static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002056show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2057{
2058 struct nct6775_data *data = nct6775_update_device(dev);
2059 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2060 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002061
Guenter Roeckaa136e52012-12-04 03:26:05 -08002062 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2063}
2064
2065static ssize_t
2066show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2067{
2068 struct nct6775_data *data = nct6775_update_device(dev);
2069 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2070 int nr = sattr->nr;
2071 int index = sattr->index;
2072
2073 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2074}
2075
2076static ssize_t
2077store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2078 size_t count)
2079{
2080 struct nct6775_data *data = dev_get_drvdata(dev);
2081 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2082 int nr = sattr->nr;
2083 int index = sattr->index;
2084 int err;
2085 long val;
2086
2087 err = kstrtol(buf, 10, &val);
2088 if (err < 0)
2089 return err;
2090
2091 mutex_lock(&data->update_lock);
2092 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2093 nct6775_write_temp(data, data->reg_temp[index][nr],
2094 data->temp[index][nr]);
2095 mutex_unlock(&data->update_lock);
2096 return count;
2097}
2098
2099static ssize_t
2100show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2101{
2102 struct nct6775_data *data = nct6775_update_device(dev);
2103 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2104
2105 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2106}
2107
2108static ssize_t
2109store_temp_offset(struct device *dev, struct device_attribute *attr,
2110 const char *buf, size_t count)
2111{
2112 struct nct6775_data *data = dev_get_drvdata(dev);
2113 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2114 int nr = sattr->index;
2115 long val;
2116 int err;
2117
2118 err = kstrtol(buf, 10, &val);
2119 if (err < 0)
2120 return err;
2121
2122 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2123
2124 mutex_lock(&data->update_lock);
2125 data->temp_offset[nr] = val;
2126 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2127 mutex_unlock(&data->update_lock);
2128
2129 return count;
2130}
2131
2132static ssize_t
2133show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2134{
2135 struct nct6775_data *data = nct6775_update_device(dev);
2136 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2137 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002138
Guenter Roeckaa136e52012-12-04 03:26:05 -08002139 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2140}
2141
2142static ssize_t
2143store_temp_type(struct device *dev, struct device_attribute *attr,
2144 const char *buf, size_t count)
2145{
2146 struct nct6775_data *data = nct6775_update_device(dev);
2147 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2148 int nr = sattr->index;
2149 unsigned long val;
2150 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002151 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002152
2153 err = kstrtoul(buf, 10, &val);
2154 if (err < 0)
2155 return err;
2156
2157 if (val != 1 && val != 3 && val != 4)
2158 return -EINVAL;
2159
2160 mutex_lock(&data->update_lock);
2161
2162 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002163 vbit = 0x02 << nr;
2164 dbit = data->DIODE_MASK << nr;
2165 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2166 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002167 switch (val) {
2168 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002169 vbat |= vbit;
2170 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002171 break;
2172 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002173 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002174 break;
2175 case 4: /* thermistor */
2176 break;
2177 }
2178 nct6775_write_value(data, data->REG_VBAT, vbat);
2179 nct6775_write_value(data, data->REG_DIODE, diode);
2180
2181 mutex_unlock(&data->update_lock);
2182 return count;
2183}
2184
Guenter Roeckf73cf632013-03-18 09:22:50 -07002185static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2186 struct attribute *attr, int index)
2187{
2188 struct device *dev = container_of(kobj, struct device, kobj);
2189 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002190 int temp = index / 10; /* temp index */
2191 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002192
2193 if (!(data->have_temp & (1 << temp)))
2194 return 0;
2195
2196 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2197 return 0; /* alarm */
2198
Guenter Roeck30846992013-06-24 22:21:59 -07002199 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2200 return 0; /* beep */
2201
2202 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002203 return 0;
2204
Guenter Roeck30846992013-06-24 22:21:59 -07002205 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002206 return 0;
2207
Guenter Roeck30846992013-06-24 22:21:59 -07002208 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002209 return 0;
2210
Guenter Roeck30846992013-06-24 22:21:59 -07002211 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002212 return 0;
2213
2214 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002215 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002216 return 0;
2217
2218 return attr->mode;
2219}
2220
2221SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2222SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2223SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2224 store_temp, 0, 1);
2225SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2226 show_temp, store_temp, 0, 2);
2227SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2228 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002229SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2230 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002231SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2232 show_temp_offset, store_temp_offset, 0);
2233SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2234 store_temp_type, 0);
2235SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002236SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2237 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002238
2239/*
2240 * nct6775_temp_is_visible uses the index into the following array
2241 * to determine if attributes should be created or not.
2242 * Any change in order or content must be matched.
2243 */
2244static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2245 &sensor_dev_template_temp_input,
2246 &sensor_dev_template_temp_label,
2247 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002248 &sensor_dev_template_temp_beep, /* 3 */
2249 &sensor_dev_template_temp_max, /* 4 */
2250 &sensor_dev_template_temp_max_hyst, /* 5 */
2251 &sensor_dev_template_temp_crit, /* 6 */
2252 &sensor_dev_template_temp_lcrit, /* 7 */
2253 &sensor_dev_template_temp_offset, /* 8 */
2254 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002255 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002256};
2257
Guenter Roeckf73cf632013-03-18 09:22:50 -07002258static struct sensor_template_group nct6775_temp_template_group = {
2259 .templates = nct6775_attributes_temp_template,
2260 .is_visible = nct6775_temp_is_visible,
2261 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002262};
2263
Guenter Roeckaa136e52012-12-04 03:26:05 -08002264static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002265show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2266{
2267 struct nct6775_data *data = nct6775_update_device(dev);
2268 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2269
2270 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2271}
2272
2273static ssize_t
2274store_pwm_mode(struct device *dev, struct device_attribute *attr,
2275 const char *buf, size_t count)
2276{
2277 struct nct6775_data *data = dev_get_drvdata(dev);
2278 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2279 int nr = sattr->index;
2280 unsigned long val;
2281 int err;
2282 u8 reg;
2283
2284 err = kstrtoul(buf, 10, &val);
2285 if (err < 0)
2286 return err;
2287
2288 if (val > 1)
2289 return -EINVAL;
2290
2291 /* Setting DC mode is not supported for all chips/channels */
2292 if (data->REG_PWM_MODE[nr] == 0) {
2293 if (val)
2294 return -EINVAL;
2295 return count;
2296 }
2297
2298 mutex_lock(&data->update_lock);
2299 data->pwm_mode[nr] = val;
2300 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2301 reg &= ~data->PWM_MODE_MASK[nr];
2302 if (val)
2303 reg |= data->PWM_MODE_MASK[nr];
2304 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2305 mutex_unlock(&data->update_lock);
2306 return count;
2307}
2308
2309static ssize_t
2310show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2311{
2312 struct nct6775_data *data = nct6775_update_device(dev);
2313 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2314 int nr = sattr->nr;
2315 int index = sattr->index;
2316 int pwm;
2317
2318 /*
2319 * For automatic fan control modes, show current pwm readings.
2320 * Otherwise, show the configured value.
2321 */
2322 if (index == 0 && data->pwm_enable[nr] > manual)
2323 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2324 else
2325 pwm = data->pwm[index][nr];
2326
2327 return sprintf(buf, "%d\n", pwm);
2328}
2329
2330static ssize_t
2331store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2332 size_t count)
2333{
2334 struct nct6775_data *data = dev_get_drvdata(dev);
2335 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2336 int nr = sattr->nr;
2337 int index = sattr->index;
2338 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002339 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2340 int maxval[7]
2341 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002342 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002343 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002344
2345 err = kstrtoul(buf, 10, &val);
2346 if (err < 0)
2347 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002348 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002349
2350 mutex_lock(&data->update_lock);
2351 data->pwm[index][nr] = val;
2352 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002353 if (index == 2) { /* floor: disable if val == 0 */
2354 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2355 reg &= 0x7f;
2356 if (val)
2357 reg |= 0x80;
2358 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2359 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002360 mutex_unlock(&data->update_lock);
2361 return count;
2362}
2363
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002364/* Returns 0 if OK, -EINVAL otherwise */
2365static int check_trip_points(struct nct6775_data *data, int nr)
2366{
2367 int i;
2368
2369 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2370 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2371 return -EINVAL;
2372 }
2373 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2374 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2375 return -EINVAL;
2376 }
2377 /* validate critical temperature and pwm if enabled (pwm > 0) */
2378 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2379 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2380 data->auto_temp[nr][data->auto_pwm_num] ||
2381 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2382 data->auto_pwm[nr][data->auto_pwm_num])
2383 return -EINVAL;
2384 }
2385 return 0;
2386}
2387
2388static void pwm_update_registers(struct nct6775_data *data, int nr)
2389{
2390 u8 reg;
2391
2392 switch (data->pwm_enable[nr]) {
2393 case off:
2394 case manual:
2395 break;
2396 case speed_cruise:
2397 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2398 reg = (reg & ~data->tolerance_mask) |
2399 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2400 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2401 nct6775_write_value(data, data->REG_TARGET[nr],
2402 data->target_speed[nr] & 0xff);
2403 if (data->REG_TOLERANCE_H) {
2404 reg = (data->target_speed[nr] >> 8) & 0x0f;
2405 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2406 nct6775_write_value(data,
2407 data->REG_TOLERANCE_H[nr],
2408 reg);
2409 }
2410 break;
2411 case thermal_cruise:
2412 nct6775_write_value(data, data->REG_TARGET[nr],
2413 data->target_temp[nr]);
2414 /* intentional */
2415 default:
2416 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2417 reg = (reg & ~data->tolerance_mask) |
2418 data->temp_tolerance[0][nr];
2419 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2420 break;
2421 }
2422}
2423
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002424static ssize_t
2425show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2426{
2427 struct nct6775_data *data = nct6775_update_device(dev);
2428 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2429
2430 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2431}
2432
2433static ssize_t
2434store_pwm_enable(struct device *dev, struct device_attribute *attr,
2435 const char *buf, size_t count)
2436{
2437 struct nct6775_data *data = dev_get_drvdata(dev);
2438 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2439 int nr = sattr->index;
2440 unsigned long val;
2441 int err;
2442 u16 reg;
2443
2444 err = kstrtoul(buf, 10, &val);
2445 if (err < 0)
2446 return err;
2447
2448 if (val > sf4)
2449 return -EINVAL;
2450
2451 if (val == sf3 && data->kind != nct6775)
2452 return -EINVAL;
2453
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002454 if (val == sf4 && check_trip_points(data, nr)) {
2455 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2456 dev_err(dev, "Adjust trip points and try again\n");
2457 return -EINVAL;
2458 }
2459
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002460 mutex_lock(&data->update_lock);
2461 data->pwm_enable[nr] = val;
2462 if (val == off) {
2463 /*
2464 * turn off pwm control: select manual mode, set pwm to maximum
2465 */
2466 data->pwm[0][nr] = 255;
2467 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2468 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002469 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002470 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2471 reg &= 0x0f;
2472 reg |= pwm_enable_to_reg(val) << 4;
2473 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2474 mutex_unlock(&data->update_lock);
2475 return count;
2476}
2477
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002478static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002479show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002480{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002481 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002482
2483 for (i = 0; i < NUM_TEMP; i++) {
2484 if (!(data->have_temp & (1 << i)))
2485 continue;
2486 if (src == data->temp_src[i]) {
2487 sel = i + 1;
2488 break;
2489 }
2490 }
2491
2492 return sprintf(buf, "%d\n", sel);
2493}
2494
2495static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002496show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2497{
2498 struct nct6775_data *data = nct6775_update_device(dev);
2499 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2500 int index = sattr->index;
2501
2502 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2503}
2504
2505static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002506store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2507 const char *buf, size_t count)
2508{
2509 struct nct6775_data *data = nct6775_update_device(dev);
2510 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2511 int nr = sattr->index;
2512 unsigned long val;
2513 int err, reg, src;
2514
2515 err = kstrtoul(buf, 10, &val);
2516 if (err < 0)
2517 return err;
2518 if (val == 0 || val > NUM_TEMP)
2519 return -EINVAL;
2520 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2521 return -EINVAL;
2522
2523 mutex_lock(&data->update_lock);
2524 src = data->temp_src[val - 1];
2525 data->pwm_temp_sel[nr] = src;
2526 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2527 reg &= 0xe0;
2528 reg |= src;
2529 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2530 mutex_unlock(&data->update_lock);
2531
2532 return count;
2533}
2534
2535static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002536show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2537 char *buf)
2538{
2539 struct nct6775_data *data = nct6775_update_device(dev);
2540 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2541 int index = sattr->index;
2542
2543 return show_pwm_temp_sel_common(data, buf,
2544 data->pwm_weight_temp_sel[index]);
2545}
2546
2547static ssize_t
2548store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2549 const char *buf, size_t count)
2550{
2551 struct nct6775_data *data = nct6775_update_device(dev);
2552 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2553 int nr = sattr->index;
2554 unsigned long val;
2555 int err, reg, src;
2556
2557 err = kstrtoul(buf, 10, &val);
2558 if (err < 0)
2559 return err;
2560 if (val > NUM_TEMP)
2561 return -EINVAL;
2562 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2563 !data->temp_src[val - 1]))
2564 return -EINVAL;
2565
2566 mutex_lock(&data->update_lock);
2567 if (val) {
2568 src = data->temp_src[val - 1];
2569 data->pwm_weight_temp_sel[nr] = src;
2570 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2571 reg &= 0xe0;
2572 reg |= (src | 0x80);
2573 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2574 } else {
2575 data->pwm_weight_temp_sel[nr] = 0;
2576 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2577 reg &= 0x7f;
2578 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2579 }
2580 mutex_unlock(&data->update_lock);
2581
2582 return count;
2583}
2584
2585static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002586show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2587{
2588 struct nct6775_data *data = nct6775_update_device(dev);
2589 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2590
2591 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2592}
2593
2594static ssize_t
2595store_target_temp(struct device *dev, struct device_attribute *attr,
2596 const char *buf, size_t count)
2597{
2598 struct nct6775_data *data = dev_get_drvdata(dev);
2599 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2600 int nr = sattr->index;
2601 unsigned long val;
2602 int err;
2603
2604 err = kstrtoul(buf, 10, &val);
2605 if (err < 0)
2606 return err;
2607
2608 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2609 data->target_temp_mask);
2610
2611 mutex_lock(&data->update_lock);
2612 data->target_temp[nr] = val;
2613 pwm_update_registers(data, nr);
2614 mutex_unlock(&data->update_lock);
2615 return count;
2616}
2617
2618static ssize_t
2619show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2620{
2621 struct nct6775_data *data = nct6775_update_device(dev);
2622 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2623 int nr = sattr->index;
2624
2625 return sprintf(buf, "%d\n",
2626 fan_from_reg16(data->target_speed[nr],
2627 data->fan_div[nr]));
2628}
2629
2630static ssize_t
2631store_target_speed(struct device *dev, struct device_attribute *attr,
2632 const char *buf, size_t count)
2633{
2634 struct nct6775_data *data = dev_get_drvdata(dev);
2635 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2636 int nr = sattr->index;
2637 unsigned long val;
2638 int err;
2639 u16 speed;
2640
2641 err = kstrtoul(buf, 10, &val);
2642 if (err < 0)
2643 return err;
2644
2645 val = clamp_val(val, 0, 1350000U);
2646 speed = fan_to_reg(val, data->fan_div[nr]);
2647
2648 mutex_lock(&data->update_lock);
2649 data->target_speed[nr] = speed;
2650 pwm_update_registers(data, nr);
2651 mutex_unlock(&data->update_lock);
2652 return count;
2653}
2654
2655static ssize_t
2656show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2657 char *buf)
2658{
2659 struct nct6775_data *data = nct6775_update_device(dev);
2660 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2661 int nr = sattr->nr;
2662 int index = sattr->index;
2663
2664 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2665}
2666
2667static ssize_t
2668store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2669 const char *buf, size_t count)
2670{
2671 struct nct6775_data *data = dev_get_drvdata(dev);
2672 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2673 int nr = sattr->nr;
2674 int index = sattr->index;
2675 unsigned long val;
2676 int err;
2677
2678 err = kstrtoul(buf, 10, &val);
2679 if (err < 0)
2680 return err;
2681
2682 /* Limit tolerance as needed */
2683 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2684
2685 mutex_lock(&data->update_lock);
2686 data->temp_tolerance[index][nr] = val;
2687 if (index)
2688 pwm_update_registers(data, nr);
2689 else
2690 nct6775_write_value(data,
2691 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2692 val);
2693 mutex_unlock(&data->update_lock);
2694 return count;
2695}
2696
2697/*
2698 * Fan speed tolerance is a tricky beast, since the associated register is
2699 * a tick counter, but the value is reported and configured as rpm.
2700 * Compute resulting low and high rpm values and report the difference.
2701 */
2702static ssize_t
2703show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2704 char *buf)
2705{
2706 struct nct6775_data *data = nct6775_update_device(dev);
2707 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2708 int nr = sattr->index;
2709 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2710 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2711 int tolerance;
2712
2713 if (low <= 0)
2714 low = 1;
2715 if (high > 0xffff)
2716 high = 0xffff;
2717 if (high < low)
2718 high = low;
2719
2720 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2721 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2722
2723 return sprintf(buf, "%d\n", tolerance);
2724}
2725
2726static ssize_t
2727store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2728 const char *buf, size_t count)
2729{
2730 struct nct6775_data *data = dev_get_drvdata(dev);
2731 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2732 int nr = sattr->index;
2733 unsigned long val;
2734 int err;
2735 int low, high;
2736
2737 err = kstrtoul(buf, 10, &val);
2738 if (err < 0)
2739 return err;
2740
2741 high = fan_from_reg16(data->target_speed[nr],
2742 data->fan_div[nr]) + val;
2743 low = fan_from_reg16(data->target_speed[nr],
2744 data->fan_div[nr]) - val;
2745 if (low <= 0)
2746 low = 1;
2747 if (high < low)
2748 high = low;
2749
2750 val = (fan_to_reg(low, data->fan_div[nr]) -
2751 fan_to_reg(high, data->fan_div[nr])) / 2;
2752
2753 /* Limit tolerance as needed */
2754 val = clamp_val(val, 0, data->speed_tolerance_limit);
2755
2756 mutex_lock(&data->update_lock);
2757 data->target_speed_tolerance[nr] = val;
2758 pwm_update_registers(data, nr);
2759 mutex_unlock(&data->update_lock);
2760 return count;
2761}
2762
Guenter Roeckf73cf632013-03-18 09:22:50 -07002763SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2764SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2765 store_pwm_mode, 0);
2766SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2767 store_pwm_enable, 0);
2768SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2769 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2770SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2771 show_target_temp, store_target_temp, 0);
2772SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2773 show_target_speed, store_target_speed, 0);
2774SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2775 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002776
2777/* Smart Fan registers */
2778
2779static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002780show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2781{
2782 struct nct6775_data *data = nct6775_update_device(dev);
2783 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2784 int nr = sattr->nr;
2785 int index = sattr->index;
2786
2787 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2788}
2789
2790static ssize_t
2791store_weight_temp(struct device *dev, struct device_attribute *attr,
2792 const char *buf, size_t count)
2793{
2794 struct nct6775_data *data = dev_get_drvdata(dev);
2795 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2796 int nr = sattr->nr;
2797 int index = sattr->index;
2798 unsigned long val;
2799 int err;
2800
2801 err = kstrtoul(buf, 10, &val);
2802 if (err < 0)
2803 return err;
2804
2805 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2806
2807 mutex_lock(&data->update_lock);
2808 data->weight_temp[index][nr] = val;
2809 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2810 mutex_unlock(&data->update_lock);
2811 return count;
2812}
2813
Guenter Roeckf73cf632013-03-18 09:22:50 -07002814SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2815 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2816SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2817 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2818SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2819 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2820SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2821 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2822SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2823 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2824SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2825 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002826
2827static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002828show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2829{
2830 struct nct6775_data *data = nct6775_update_device(dev);
2831 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2832 int nr = sattr->nr;
2833 int index = sattr->index;
2834
2835 return sprintf(buf, "%d\n",
2836 step_time_from_reg(data->fan_time[index][nr],
2837 data->pwm_mode[nr]));
2838}
2839
2840static ssize_t
2841store_fan_time(struct device *dev, struct device_attribute *attr,
2842 const char *buf, size_t count)
2843{
2844 struct nct6775_data *data = dev_get_drvdata(dev);
2845 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2846 int nr = sattr->nr;
2847 int index = sattr->index;
2848 unsigned long val;
2849 int err;
2850
2851 err = kstrtoul(buf, 10, &val);
2852 if (err < 0)
2853 return err;
2854
2855 val = step_time_to_reg(val, data->pwm_mode[nr]);
2856 mutex_lock(&data->update_lock);
2857 data->fan_time[index][nr] = val;
2858 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2859 mutex_unlock(&data->update_lock);
2860 return count;
2861}
2862
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002863static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002864show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2865{
2866 struct nct6775_data *data = nct6775_update_device(dev);
2867 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2868
2869 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2870}
2871
2872static ssize_t
2873store_auto_pwm(struct device *dev, struct device_attribute *attr,
2874 const char *buf, size_t count)
2875{
2876 struct nct6775_data *data = dev_get_drvdata(dev);
2877 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2878 int nr = sattr->nr;
2879 int point = sattr->index;
2880 unsigned long val;
2881 int err;
2882 u8 reg;
2883
2884 err = kstrtoul(buf, 10, &val);
2885 if (err < 0)
2886 return err;
2887 if (val > 255)
2888 return -EINVAL;
2889
2890 if (point == data->auto_pwm_num) {
2891 if (data->kind != nct6775 && !val)
2892 return -EINVAL;
2893 if (data->kind != nct6779 && val)
2894 val = 0xff;
2895 }
2896
2897 mutex_lock(&data->update_lock);
2898 data->auto_pwm[nr][point] = val;
2899 if (point < data->auto_pwm_num) {
2900 nct6775_write_value(data,
2901 NCT6775_AUTO_PWM(data, nr, point),
2902 data->auto_pwm[nr][point]);
2903 } else {
2904 switch (data->kind) {
2905 case nct6775:
2906 /* disable if needed (pwm == 0) */
2907 reg = nct6775_read_value(data,
2908 NCT6775_REG_CRITICAL_ENAB[nr]);
2909 if (val)
2910 reg |= 0x02;
2911 else
2912 reg &= ~0x02;
2913 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2914 reg);
2915 break;
2916 case nct6776:
2917 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002918 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002919 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002920 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002921 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002922 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002923 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002924 val);
2925 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002926 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002927 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002928 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002929 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002930 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002931 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002932 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002933 reg);
2934 break;
2935 }
2936 }
2937 mutex_unlock(&data->update_lock);
2938 return count;
2939}
2940
2941static ssize_t
2942show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2943{
2944 struct nct6775_data *data = nct6775_update_device(dev);
2945 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2946 int nr = sattr->nr;
2947 int point = sattr->index;
2948
2949 /*
2950 * We don't know for sure if the temperature is signed or unsigned.
2951 * Assume it is unsigned.
2952 */
2953 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2954}
2955
2956static ssize_t
2957store_auto_temp(struct device *dev, struct device_attribute *attr,
2958 const char *buf, size_t count)
2959{
2960 struct nct6775_data *data = dev_get_drvdata(dev);
2961 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2962 int nr = sattr->nr;
2963 int point = sattr->index;
2964 unsigned long val;
2965 int err;
2966
2967 err = kstrtoul(buf, 10, &val);
2968 if (err)
2969 return err;
2970 if (val > 255000)
2971 return -EINVAL;
2972
2973 mutex_lock(&data->update_lock);
2974 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2975 if (point < data->auto_pwm_num) {
2976 nct6775_write_value(data,
2977 NCT6775_AUTO_TEMP(data, nr, point),
2978 data->auto_temp[nr][point]);
2979 } else {
2980 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2981 data->auto_temp[nr][point]);
2982 }
2983 mutex_unlock(&data->update_lock);
2984 return count;
2985}
2986
Guenter Roeckf73cf632013-03-18 09:22:50 -07002987static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2988 struct attribute *attr, int index)
2989{
2990 struct device *dev = container_of(kobj, struct device, kobj);
2991 struct nct6775_data *data = dev_get_drvdata(dev);
2992 int pwm = index / 36; /* pwm index */
2993 int nr = index % 36; /* attribute index */
2994
2995 if (!(data->has_pwm & (1 << pwm)))
2996 return 0;
2997
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002998 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2999 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3000 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003001 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3002 return 0;
3003 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3004 return 0;
3005 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3006 return 0;
3007
3008 if (nr >= 22 && nr <= 35) { /* auto point */
3009 int api = (nr - 22) / 2; /* auto point index */
3010
3011 if (api > data->auto_pwm_num)
3012 return 0;
3013 }
3014 return attr->mode;
3015}
3016
3017SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3018 show_fan_time, store_fan_time, 0, 0);
3019SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3020 show_fan_time, store_fan_time, 0, 1);
3021SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3022 show_fan_time, store_fan_time, 0, 2);
3023SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3024 store_pwm, 0, 1);
3025SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3026 store_pwm, 0, 2);
3027SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3028 show_temp_tolerance, store_temp_tolerance, 0, 0);
3029SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3030 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3031 0, 1);
3032
3033SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3034 0, 3);
3035
3036SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3037 store_pwm, 0, 4);
3038
3039SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3040 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3041SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3042 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3043
3044SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3045 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3046SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3047 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3048
3049SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3050 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3051SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3052 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3053
3054SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3055 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3056SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3057 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3058
3059SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3060 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3061SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3062 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3063
3064SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3065 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3066SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3067 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3068
3069SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3070 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3071SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3072 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3073
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003074/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003075 * nct6775_pwm_is_visible uses the index into the following array
3076 * to determine if attributes should be created or not.
3077 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003078 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003079static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3080 &sensor_dev_template_pwm,
3081 &sensor_dev_template_pwm_mode,
3082 &sensor_dev_template_pwm_enable,
3083 &sensor_dev_template_pwm_temp_sel,
3084 &sensor_dev_template_pwm_temp_tolerance,
3085 &sensor_dev_template_pwm_crit_temp_tolerance,
3086 &sensor_dev_template_pwm_target_temp,
3087 &sensor_dev_template_fan_target,
3088 &sensor_dev_template_fan_tolerance,
3089 &sensor_dev_template_pwm_stop_time,
3090 &sensor_dev_template_pwm_step_up_time,
3091 &sensor_dev_template_pwm_step_down_time,
3092 &sensor_dev_template_pwm_start,
3093 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003094 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003095 &sensor_dev_template_pwm_weight_temp_step,
3096 &sensor_dev_template_pwm_weight_temp_step_tol,
3097 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003098 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003099 &sensor_dev_template_pwm_max, /* 19 */
3100 &sensor_dev_template_pwm_step, /* 20 */
3101 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3102 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3103 &sensor_dev_template_pwm_auto_point1_temp,
3104 &sensor_dev_template_pwm_auto_point2_pwm,
3105 &sensor_dev_template_pwm_auto_point2_temp,
3106 &sensor_dev_template_pwm_auto_point3_pwm,
3107 &sensor_dev_template_pwm_auto_point3_temp,
3108 &sensor_dev_template_pwm_auto_point4_pwm,
3109 &sensor_dev_template_pwm_auto_point4_temp,
3110 &sensor_dev_template_pwm_auto_point5_pwm,
3111 &sensor_dev_template_pwm_auto_point5_temp,
3112 &sensor_dev_template_pwm_auto_point6_pwm,
3113 &sensor_dev_template_pwm_auto_point6_temp,
3114 &sensor_dev_template_pwm_auto_point7_pwm,
3115 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003116
Guenter Roeckf73cf632013-03-18 09:22:50 -07003117 NULL
3118};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003119
Guenter Roeckf73cf632013-03-18 09:22:50 -07003120static struct sensor_template_group nct6775_pwm_template_group = {
3121 .templates = nct6775_attributes_pwm_template,
3122 .is_visible = nct6775_pwm_is_visible,
3123 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003124};
3125
3126static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003127show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3128{
3129 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003130
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003131 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3132}
3133
3134static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3135
Guenter Roecka6bd5872012-12-04 03:13:34 -08003136/* Case open detection */
3137
3138static ssize_t
3139clear_caseopen(struct device *dev, struct device_attribute *attr,
3140 const char *buf, size_t count)
3141{
3142 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003143 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3144 unsigned long val;
3145 u8 reg;
3146 int ret;
3147
3148 if (kstrtoul(buf, 10, &val) || val != 0)
3149 return -EINVAL;
3150
3151 mutex_lock(&data->update_lock);
3152
3153 /*
3154 * Use CR registers to clear caseopen status.
3155 * The CR registers are the same for all chips, and not all chips
3156 * support clearing the caseopen status through "regular" registers.
3157 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003158 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003159 if (ret) {
3160 count = ret;
3161 goto error;
3162 }
3163
Guenter Roeckdf612d52013-07-08 13:15:04 -07003164 superio_select(data->sioreg, NCT6775_LD_ACPI);
3165 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003166 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003167 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003168 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003169 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3170 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003171
3172 data->valid = false; /* Force cache refresh */
3173error:
3174 mutex_unlock(&data->update_lock);
3175 return count;
3176}
3177
Guenter Roeckf73cf632013-03-18 09:22:50 -07003178static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3179 clear_caseopen, INTRUSION_ALARM_BASE);
3180static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3181 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003182static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3183 store_beep, INTRUSION_ALARM_BASE);
3184static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3185 store_beep, INTRUSION_ALARM_BASE + 1);
3186static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3187 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003188
3189static umode_t nct6775_other_is_visible(struct kobject *kobj,
3190 struct attribute *attr, int index)
3191{
3192 struct device *dev = container_of(kobj, struct device, kobj);
3193 struct nct6775_data *data = dev_get_drvdata(dev);
3194
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003195 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003196 return 0;
3197
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003198 if (index == 1 || index == 2) {
3199 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003200 return 0;
3201 }
3202
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003203 if (index == 3 || index == 4) {
3204 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003205 return 0;
3206 }
3207
Guenter Roeckf73cf632013-03-18 09:22:50 -07003208 return attr->mode;
3209}
3210
3211/*
3212 * nct6775_other_is_visible uses the index into the following array
3213 * to determine if attributes should be created or not.
3214 * Any change in order or content must be matched.
3215 */
3216static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003217 &dev_attr_cpu0_vid.attr, /* 0 */
3218 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3219 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3220 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3221 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3222 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003223
3224 NULL
3225};
3226
3227static const struct attribute_group nct6775_group_other = {
3228 .attrs = nct6775_attributes_other,
3229 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003230};
3231
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003232static inline void nct6775_init_device(struct nct6775_data *data)
3233{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003234 int i;
3235 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003236
3237 /* Start monitoring if needed */
3238 if (data->REG_CONFIG) {
3239 tmp = nct6775_read_value(data, data->REG_CONFIG);
3240 if (!(tmp & 0x01))
3241 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3242 }
3243
Guenter Roeckaa136e52012-12-04 03:26:05 -08003244 /* Enable temperature sensors if needed */
3245 for (i = 0; i < NUM_TEMP; i++) {
3246 if (!(data->have_temp & (1 << i)))
3247 continue;
3248 if (!data->reg_temp_config[i])
3249 continue;
3250 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3251 if (tmp & 0x01)
3252 nct6775_write_value(data, data->reg_temp_config[i],
3253 tmp & 0xfe);
3254 }
3255
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003256 /* Enable VBAT monitoring if needed */
3257 tmp = nct6775_read_value(data, data->REG_VBAT);
3258 if (!(tmp & 0x01))
3259 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003260
3261 diode = nct6775_read_value(data, data->REG_DIODE);
3262
3263 for (i = 0; i < data->temp_fixed_num; i++) {
3264 if (!(data->have_temp_fixed & (1 << i)))
3265 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003266 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3267 data->temp_type[i]
3268 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003269 else /* thermistor */
3270 data->temp_type[i] = 4;
3271 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003272}
3273
Guenter Roeckf73cf632013-03-18 09:22:50 -07003274static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003275nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003276{
David Bartley578ab5f2013-06-24 22:28:28 -07003277 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3278 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003279 int sioreg = data->sioreg;
3280 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003281
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003282 /* Store SIO_REG_ENABLE for use during resume */
3283 superio_select(sioreg, NCT6775_LD_HWM);
3284 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3285
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003286 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3287 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003288 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003289
3290 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003291 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003292
3293 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003294 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003295 fan4min = false;
3296 fan5pin = false;
3297 fan6pin = false;
3298 pwm4pin = false;
3299 pwm5pin = false;
3300 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003301 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003302 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003303 const char *board_vendor, *board_name;
3304
3305 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3306 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3307
3308 if (board_name && board_vendor &&
3309 !strcmp(board_vendor, "ASRock")) {
3310 /*
3311 * Auxiliary fan monitoring is not enabled on ASRock
3312 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3313 * Observed with BIOS version 2.00.
3314 */
3315 if (!strcmp(board_name, "Z77 Pro4-M")) {
3316 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3317 data->sio_reg_enable |= 0xe0;
3318 superio_outb(sioreg, SIO_REG_ENABLE,
3319 data->sio_reg_enable);
3320 }
3321 }
3322 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003323
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003324 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003325 fan3pin = gpok;
3326 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003327 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003328
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003329 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003330 fan4pin = gpok;
3331 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003332 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003333
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003334 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003335 fan5pin = gpok;
3336 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003337 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003338
3339 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003340 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003341 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003342 pwm4pin = false;
3343 pwm5pin = false;
3344 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003345 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003346 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003347 fan3pin = !(regval & 0x80);
3348 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003349
3350 fan4pin = false;
3351 fan4min = false;
3352 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003353 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003354 pwm4pin = false;
3355 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003356 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003357 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003358 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003359
3360 fan3pin = !(regval & (1 << 5));
3361 fan4pin = !(regval & (1 << 6));
3362 fan5pin = !(regval & (1 << 7));
3363
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003364 pwm3pin = !(regval & (1 << 0));
3365 pwm4pin = !(regval & (1 << 1));
3366 pwm5pin = !(regval & (1 << 2));
3367
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003368 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003369
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003370 if (data->kind == nct6791 || data->kind == nct6792 ||
3371 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003372 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003373 fan6pin = (regval & (1 << 1));
3374 pwm6pin = (regval & (1 << 0));
3375 } else { /* NCT6779D */
3376 fan6pin = false;
3377 pwm6pin = false;
3378 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003379 }
3380
David Bartley578ab5f2013-06-24 22:28:28 -07003381 /* fan 1 and 2 (0x03) are always present */
3382 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3383 (fan5pin << 4) | (fan6pin << 5);
3384 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3385 (fan5pin << 4);
3386 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3387 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003388}
3389
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003390static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3391 int *available, int *mask)
3392{
3393 int i;
3394 u8 src;
3395
3396 for (i = 0; i < data->pwm_num && *available; i++) {
3397 int index;
3398
3399 if (!regp[i])
3400 continue;
3401 src = nct6775_read_value(data, regp[i]);
3402 src &= 0x1f;
3403 if (!src || (*mask & (1 << src)))
3404 continue;
3405 if (src >= data->temp_label_num ||
3406 !strlen(data->temp_label[src]))
3407 continue;
3408
3409 index = __ffs(*available);
3410 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3411 *available &= ~(1 << index);
3412 *mask |= 1 << src;
3413 }
3414}
3415
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003416static int nct6775_probe(struct platform_device *pdev)
3417{
3418 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003419 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003420 struct nct6775_data *data;
3421 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003422 int i, s, err = 0;
3423 int src, mask, available;
3424 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003425 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003426 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003427 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003428 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003429 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003430 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003431 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003432
3433 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3434 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3435 DRVNAME))
3436 return -EBUSY;
3437
3438 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3439 GFP_KERNEL);
3440 if (!data)
3441 return -ENOMEM;
3442
3443 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003444 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003445 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003446 mutex_init(&data->update_lock);
3447 data->name = nct6775_device_names[data->kind];
3448 data->bank = 0xff; /* Force initial bank selection */
3449 platform_set_drvdata(pdev, data);
3450
3451 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003452 case nct6106:
3453 data->in_num = 9;
3454 data->pwm_num = 3;
3455 data->auto_pwm_num = 4;
3456 data->temp_fixed_num = 3;
3457 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003458 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003459
3460 data->fan_from_reg = fan_from_reg13;
3461 data->fan_from_reg_min = fan_from_reg13;
3462
3463 data->temp_label = nct6776_temp_label;
3464 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3465
3466 data->REG_VBAT = NCT6106_REG_VBAT;
3467 data->REG_DIODE = NCT6106_REG_DIODE;
3468 data->DIODE_MASK = NCT6106_DIODE_MASK;
3469 data->REG_VIN = NCT6106_REG_IN;
3470 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3471 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3472 data->REG_TARGET = NCT6106_REG_TARGET;
3473 data->REG_FAN = NCT6106_REG_FAN;
3474 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3475 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3476 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3477 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3478 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3479 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3480 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3481 data->REG_PWM[0] = NCT6106_REG_PWM;
3482 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3483 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3484 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3485 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3486 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3487 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3488 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3489 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3490 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3491 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3492 data->REG_CRITICAL_TEMP_TOLERANCE
3493 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3494 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3495 data->CRITICAL_PWM_ENABLE_MASK
3496 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3497 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3498 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3499 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3500 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3501 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3502 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3503 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3504 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3505 data->REG_ALARM = NCT6106_REG_ALARM;
3506 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003507 data->REG_BEEP = NCT6106_REG_BEEP;
3508 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003509
3510 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003511 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003512 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003513 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003514 reg_temp_over = NCT6106_REG_TEMP_OVER;
3515 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3516 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3517 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3518 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003519 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3520 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003521
3522 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003523 case nct6775:
3524 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003525 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003526 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003527 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003528 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003529 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003530 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003531
3532 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003533 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003534
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003535 data->fan_from_reg = fan_from_reg16;
3536 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003537 data->target_temp_mask = 0x7f;
3538 data->tolerance_mask = 0x0f;
3539 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003540
Guenter Roeckaa136e52012-12-04 03:26:05 -08003541 data->temp_label = nct6775_temp_label;
3542 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3543
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003544 data->REG_CONFIG = NCT6775_REG_CONFIG;
3545 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003546 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003547 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003548 data->REG_VIN = NCT6775_REG_IN;
3549 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3550 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003551 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003552 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003553 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003554 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003555 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003556 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003557 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3558 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3559 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003560 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003561 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3562 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3563 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3564 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003565 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003566 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3567 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3568 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003569 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3570 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3571 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3572 data->REG_CRITICAL_TEMP_TOLERANCE
3573 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003574 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3575 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003576 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003577 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3578 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3579 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3580 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003581 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003582 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003583
3584 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003585 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003586 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003587 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003588 reg_temp_over = NCT6775_REG_TEMP_OVER;
3589 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3590 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3591 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3592 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3593
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003594 break;
3595 case nct6776:
3596 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003597 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003598 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003599 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003600 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003601 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003602 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003603
3604 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003605 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003606
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003607 data->fan_from_reg = fan_from_reg13;
3608 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003609 data->target_temp_mask = 0xff;
3610 data->tolerance_mask = 0x07;
3611 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003612
Guenter Roeckaa136e52012-12-04 03:26:05 -08003613 data->temp_label = nct6776_temp_label;
3614 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3615
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003616 data->REG_CONFIG = NCT6775_REG_CONFIG;
3617 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003618 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003619 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003620 data->REG_VIN = NCT6775_REG_IN;
3621 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3622 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003623 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003624 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003625 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003626 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003627 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003628 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003629 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003630 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3631 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003632 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003633 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003634 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3635 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003636 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3637 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003638 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3639 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3640 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003641 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3642 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3643 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3644 data->REG_CRITICAL_TEMP_TOLERANCE
3645 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003646 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3647 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003648 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003649 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3650 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3651 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3652 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003653 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003654 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003655
3656 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003657 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003658 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003659 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003660 reg_temp_over = NCT6775_REG_TEMP_OVER;
3661 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3662 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3663 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3664 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3665
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003666 break;
3667 case nct6779:
3668 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003669 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003670 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003671 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003672 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003673 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003674 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003675
3676 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003677 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003678
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003679 data->fan_from_reg = fan_from_reg13;
3680 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003681 data->target_temp_mask = 0xff;
3682 data->tolerance_mask = 0x07;
3683 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003684
Guenter Roeckaa136e52012-12-04 03:26:05 -08003685 data->temp_label = nct6779_temp_label;
Guenter Roeck9a383712015-08-29 15:29:25 -07003686 data->temp_label_num = NCT6779_NUM_LABELS;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003687
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003688 data->REG_CONFIG = NCT6775_REG_CONFIG;
3689 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003690 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003691 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003692 data->REG_VIN = NCT6779_REG_IN;
3693 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3694 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003695 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003696 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003697 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003698 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003699 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003700 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003701 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003702 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3703 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003704 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003705 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003706 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3707 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003708 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3709 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003710 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3711 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3712 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003713 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3714 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3715 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3716 data->REG_CRITICAL_TEMP_TOLERANCE
3717 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003718 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3719 data->CRITICAL_PWM_ENABLE_MASK
3720 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3721 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003722 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3723 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003724 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003725 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3726 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3727 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3728 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003729 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003730 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003731
3732 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003733 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003734 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003735 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003736 reg_temp_over = NCT6779_REG_TEMP_OVER;
3737 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3738 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3739 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3740 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3741
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003742 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003743 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003744 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003745 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003746 data->in_num = 15;
3747 data->pwm_num = 6;
3748 data->auto_pwm_num = 4;
3749 data->has_fan_div = false;
3750 data->temp_fixed_num = 6;
3751 data->num_temp_alarms = 2;
3752 data->num_temp_beeps = 2;
3753
3754 data->ALARM_BITS = NCT6791_ALARM_BITS;
3755 data->BEEP_BITS = NCT6779_BEEP_BITS;
3756
3757 data->fan_from_reg = fan_from_reg13;
3758 data->fan_from_reg_min = fan_from_reg13;
3759 data->target_temp_mask = 0xff;
3760 data->tolerance_mask = 0x07;
3761 data->speed_tolerance_limit = 63;
3762
Guenter Roeck50224f42015-10-30 07:52:39 -07003763 switch (data->kind) {
3764 default:
3765 case nct6791:
3766 data->temp_label = nct6779_temp_label;
3767 break;
3768 case nct6792:
3769 data->temp_label = nct6792_temp_label;
3770 break;
3771 case nct6793:
3772 data->temp_label = nct6793_temp_label;
3773 break;
3774 }
Guenter Roeck9a383712015-08-29 15:29:25 -07003775 data->temp_label_num = NCT6791_NUM_LABELS;
David Bartley578ab5f2013-06-24 22:28:28 -07003776
3777 data->REG_CONFIG = NCT6775_REG_CONFIG;
3778 data->REG_VBAT = NCT6775_REG_VBAT;
3779 data->REG_DIODE = NCT6775_REG_DIODE;
3780 data->DIODE_MASK = NCT6775_DIODE_MASK;
3781 data->REG_VIN = NCT6779_REG_IN;
3782 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3783 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3784 data->REG_TARGET = NCT6775_REG_TARGET;
3785 data->REG_FAN = NCT6779_REG_FAN;
3786 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3787 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3788 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3789 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3790 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003791 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3792 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003793 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3794 data->REG_PWM[0] = NCT6775_REG_PWM;
3795 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3796 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003797 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3798 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003799 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3800 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3801 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3802 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3803 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3804 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3805 data->REG_CRITICAL_TEMP_TOLERANCE
3806 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3807 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3808 data->CRITICAL_PWM_ENABLE_MASK
3809 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3810 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3811 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3812 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3813 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003814 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3815 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3816 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3817 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003818 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003819 if (data->kind == nct6791)
3820 data->REG_BEEP = NCT6776_REG_BEEP;
3821 else
3822 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003823
3824 reg_temp = NCT6779_REG_TEMP;
3825 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003826 if (data->kind == nct6791) {
3827 reg_temp_mon = NCT6779_REG_TEMP_MON;
3828 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3829 } else {
3830 reg_temp_mon = NCT6792_REG_TEMP_MON;
3831 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3832 }
David Bartley578ab5f2013-06-24 22:28:28 -07003833 reg_temp_over = NCT6779_REG_TEMP_OVER;
3834 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3835 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3836 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3837 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3838
3839 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003840 default:
3841 return -ENODEV;
3842 }
3843 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003844 data->have_temp = 0;
3845
3846 /*
3847 * On some boards, not all available temperature sources are monitored,
3848 * even though some of the monitoring registers are unused.
3849 * Get list of unused monitoring registers, then detect if any fan
3850 * controls are configured to use unmonitored temperature sources.
3851 * If so, assign the unmonitored temperature sources to available
3852 * monitoring registers.
3853 */
3854 mask = 0;
3855 available = 0;
3856 for (i = 0; i < num_reg_temp; i++) {
3857 if (reg_temp[i] == 0)
3858 continue;
3859
3860 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3861 if (!src || (mask & (1 << src)))
3862 available |= 1 << i;
3863
3864 mask |= 1 << src;
3865 }
3866
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003867 /*
3868 * Now find unmonitored temperature registers and enable monitoring
3869 * if additional monitoring registers are available.
3870 */
3871 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3872 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3873
Guenter Roeckaa136e52012-12-04 03:26:05 -08003874 mask = 0;
3875 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3876 for (i = 0; i < num_reg_temp; i++) {
3877 if (reg_temp[i] == 0)
3878 continue;
3879
3880 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3881 if (!src || (mask & (1 << src)))
3882 continue;
3883
3884 if (src >= data->temp_label_num ||
3885 !strlen(data->temp_label[src])) {
3886 dev_info(dev,
3887 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3888 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3889 continue;
3890 }
3891
3892 mask |= 1 << src;
3893
3894 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3895 if (src <= data->temp_fixed_num) {
3896 data->have_temp |= 1 << (src - 1);
3897 data->have_temp_fixed |= 1 << (src - 1);
3898 data->reg_temp[0][src - 1] = reg_temp[i];
3899 data->reg_temp[1][src - 1] = reg_temp_over[i];
3900 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003901 if (reg_temp_crit_h && reg_temp_crit_h[i])
3902 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3903 else if (reg_temp_crit[src - 1])
3904 data->reg_temp[3][src - 1]
3905 = reg_temp_crit[src - 1];
3906 if (reg_temp_crit_l && reg_temp_crit_l[i])
3907 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003908 data->reg_temp_config[src - 1] = reg_temp_config[i];
3909 data->temp_src[src - 1] = src;
3910 continue;
3911 }
3912
3913 if (s >= NUM_TEMP)
3914 continue;
3915
3916 /* Use dynamic index for other sources */
3917 data->have_temp |= 1 << s;
3918 data->reg_temp[0][s] = reg_temp[i];
3919 data->reg_temp[1][s] = reg_temp_over[i];
3920 data->reg_temp[2][s] = reg_temp_hyst[i];
3921 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003922 if (reg_temp_crit_h && reg_temp_crit_h[i])
3923 data->reg_temp[3][s] = reg_temp_crit_h[i];
3924 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003925 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003926 if (reg_temp_crit_l && reg_temp_crit_l[i])
3927 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003928
3929 data->temp_src[s] = src;
3930 s++;
3931 }
3932
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003933 /*
3934 * Repeat with temperatures used for fan control.
3935 * This set of registers does not support limits.
3936 */
3937 for (i = 0; i < num_reg_temp_mon; i++) {
3938 if (reg_temp_mon[i] == 0)
3939 continue;
3940
3941 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3942 if (!src || (mask & (1 << src)))
3943 continue;
3944
3945 if (src >= data->temp_label_num ||
3946 !strlen(data->temp_label[src])) {
3947 dev_info(dev,
3948 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3949 src, i, data->REG_TEMP_SEL[i],
3950 reg_temp_mon[i]);
3951 continue;
3952 }
3953
3954 mask |= 1 << src;
3955
3956 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3957 if (src <= data->temp_fixed_num) {
3958 if (data->have_temp & (1 << (src - 1)))
3959 continue;
3960 data->have_temp |= 1 << (src - 1);
3961 data->have_temp_fixed |= 1 << (src - 1);
3962 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3963 data->temp_src[src - 1] = src;
3964 continue;
3965 }
3966
3967 if (s >= NUM_TEMP)
3968 continue;
3969
3970 /* Use dynamic index for other sources */
3971 data->have_temp |= 1 << s;
3972 data->reg_temp[0][s] = reg_temp_mon[i];
3973 data->temp_src[s] = src;
3974 s++;
3975 }
3976
Guenter Roeckaa136e52012-12-04 03:26:05 -08003977#ifdef USE_ALTERNATE
3978 /*
3979 * Go through the list of alternate temp registers and enable
3980 * if possible.
3981 * The temperature is already monitored if the respective bit in <mask>
3982 * is set.
3983 */
3984 for (i = 0; i < data->temp_label_num - 1; i++) {
3985 if (!reg_temp_alternate[i])
3986 continue;
3987 if (mask & (1 << (i + 1)))
3988 continue;
3989 if (i < data->temp_fixed_num) {
3990 if (data->have_temp & (1 << i))
3991 continue;
3992 data->have_temp |= 1 << i;
3993 data->have_temp_fixed |= 1 << i;
3994 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003995 if (i < num_reg_temp) {
3996 data->reg_temp[1][i] = reg_temp_over[i];
3997 data->reg_temp[2][i] = reg_temp_hyst[i];
3998 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003999 data->temp_src[i] = i + 1;
4000 continue;
4001 }
4002
4003 if (s >= NUM_TEMP) /* Abort if no more space */
4004 break;
4005
4006 data->have_temp |= 1 << s;
4007 data->reg_temp[0][s] = reg_temp_alternate[i];
4008 data->temp_src[s] = i + 1;
4009 s++;
4010 }
4011#endif /* USE_ALTERNATE */
4012
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004013 /* Initialize the chip */
4014 nct6775_init_device(data);
4015
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004016 err = superio_enter(sio_data->sioreg);
4017 if (err)
4018 return err;
4019
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004020 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4021 switch (data->kind) {
4022 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004023 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004024 break;
4025 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004026 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004027 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004028 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004029 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004030 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004031 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004032 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004033 break;
4034 }
4035
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004036 /*
4037 * Read VID value
4038 * We can get the VID input values directly at logical device D 0xe3.
4039 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004040 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004041 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4042 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4043 data->vrm = vid_which_vrm();
4044 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004045
4046 if (fan_debounce) {
4047 u8 tmp;
4048
4049 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4050 tmp = superio_inb(sio_data->sioreg,
4051 NCT6775_REG_CR_FAN_DEBOUNCE);
4052 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004053 case nct6106:
4054 tmp |= 0xe0;
4055 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004056 case nct6775:
4057 tmp |= 0x1e;
4058 break;
4059 case nct6776:
4060 case nct6779:
4061 tmp |= 0x3e;
4062 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004063 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004064 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004065 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07004066 tmp |= 0x7e;
4067 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004068 }
4069 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4070 tmp);
4071 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4072 data->name);
4073 }
4074
Guenter Roeckdf612d52013-07-08 13:15:04 -07004075 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004076
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004077 superio_exit(sio_data->sioreg);
4078
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004079 /* Read fan clock dividers immediately */
4080 nct6775_init_fan_common(dev, data);
4081
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004082 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004083 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4084 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004085 if (IS_ERR(group))
4086 return PTR_ERR(group);
4087
Axel Lin55bdee62014-07-24 08:59:34 +08004088 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004089
Guenter Roeckf73cf632013-03-18 09:22:50 -07004090 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4091 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004092 if (IS_ERR(group))
4093 return PTR_ERR(group);
4094
Axel Lin55bdee62014-07-24 08:59:34 +08004095 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004096
Guenter Roeckf73cf632013-03-18 09:22:50 -07004097 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4098 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004099 if (IS_ERR(group))
4100 return PTR_ERR(group);
4101
Axel Lin55bdee62014-07-24 08:59:34 +08004102 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004103
Guenter Roeckf73cf632013-03-18 09:22:50 -07004104 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4105 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004106 if (IS_ERR(group))
4107 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004108
Axel Lin55bdee62014-07-24 08:59:34 +08004109 data->groups[num_attr_groups++] = group;
4110 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004111
Guenter Roecka150d952013-07-11 22:55:22 -07004112 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4113 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004114 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004115}
4116
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004117static void nct6791_enable_io_mapping(int sioaddr)
4118{
4119 int val;
4120
4121 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4122 if (val & 0x10) {
4123 pr_info("Enabling hardware monitor logical device mappings.\n");
4124 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4125 val & ~0x10);
4126 }
4127}
4128
Guenter Roeck48e93182015-02-07 08:48:49 -08004129static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004130{
4131 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004132
4133 mutex_lock(&data->update_lock);
4134 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004135 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004136 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4137 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4138 }
4139 mutex_unlock(&data->update_lock);
4140
4141 return 0;
4142}
4143
Guenter Roeck48e93182015-02-07 08:48:49 -08004144static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004145{
4146 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004147 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004148 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004149 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004150
4151 mutex_lock(&data->update_lock);
4152 data->bank = 0xff; /* Force initial bank selection */
4153
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004154 err = superio_enter(sioreg);
4155 if (err)
4156 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004157
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004158 superio_select(sioreg, NCT6775_LD_HWM);
4159 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4160 if (reg != data->sio_reg_enable)
4161 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4162
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004163 if (data->kind == nct6791 || data->kind == nct6792 ||
4164 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004165 nct6791_enable_io_mapping(sioreg);
4166
4167 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004168
Guenter Roeck84d19d92012-12-04 08:01:39 -08004169 /* Restore limits */
4170 for (i = 0; i < data->in_num; i++) {
4171 if (!(data->have_in & (1 << i)))
4172 continue;
4173
4174 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4175 data->in[i][1]);
4176 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4177 data->in[i][2]);
4178 }
4179
Guenter Roeckc409fd42013-04-09 05:04:00 -07004180 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004181 if (!(data->has_fan_min & (1 << i)))
4182 continue;
4183
4184 nct6775_write_value(data, data->REG_FAN_MIN[i],
4185 data->fan_min[i]);
4186 }
4187
4188 for (i = 0; i < NUM_TEMP; i++) {
4189 if (!(data->have_temp & (1 << i)))
4190 continue;
4191
Guenter Roeckc409fd42013-04-09 05:04:00 -07004192 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004193 if (data->reg_temp[j][i])
4194 nct6775_write_temp(data, data->reg_temp[j][i],
4195 data->temp[j][i]);
4196 }
4197
4198 /* Restore other settings */
4199 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004200 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004201 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4202 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4203 }
4204
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004205abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004206 /* Force re-reading all values */
4207 data->valid = false;
4208 mutex_unlock(&data->update_lock);
4209
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004210 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004211}
4212
Guenter Roeck48e93182015-02-07 08:48:49 -08004213static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004214
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004215static struct platform_driver nct6775_driver = {
4216 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004217 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004218 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004219 },
4220 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004221};
4222
4223/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004224static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004225{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004226 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004227 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004228 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004229
4230 err = superio_enter(sioaddr);
4231 if (err)
4232 return err;
4233
4234 if (force_id)
4235 val = force_id;
4236 else
4237 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4238 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4239 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004240 case SIO_NCT6106_ID:
4241 sio_data->kind = nct6106;
4242 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004243 case SIO_NCT6775_ID:
4244 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004245 break;
4246 case SIO_NCT6776_ID:
4247 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004248 break;
4249 case SIO_NCT6779_ID:
4250 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004251 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004252 case SIO_NCT6791_ID:
4253 sio_data->kind = nct6791;
4254 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004255 case SIO_NCT6792_ID:
4256 sio_data->kind = nct6792;
4257 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004258 case SIO_NCT6793_ID:
4259 sio_data->kind = nct6793;
4260 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004261 default:
4262 if (val != 0xffff)
4263 pr_debug("unsupported chip ID: 0x%04x\n", val);
4264 superio_exit(sioaddr);
4265 return -ENODEV;
4266 }
4267
4268 /* We have a known chip, find the HWM I/O address */
4269 superio_select(sioaddr, NCT6775_LD_HWM);
4270 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4271 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004272 addr = val & IOREGION_ALIGNMENT;
4273 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004274 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4275 superio_exit(sioaddr);
4276 return -ENODEV;
4277 }
4278
4279 /* Activate logical device if needed */
4280 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4281 if (!(val & 0x01)) {
4282 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4283 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4284 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004285
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004286 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4287 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004288 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004289
4290 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004291 pr_info("Found %s or compatible chip at %#x:%#x\n",
4292 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004293 sio_data->sioreg = sioaddr;
4294
Guenter Roeck698a7c22013-04-05 07:35:25 -07004295 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004296}
4297
4298/*
4299 * when Super-I/O functions move to a separate file, the Super-I/O
4300 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004301 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004302 * must keep track of the device
4303 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004304static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004305
4306static int __init sensors_nct6775_init(void)
4307{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004308 int i, err;
4309 bool found = false;
4310 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004311 struct resource res;
4312 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004313 int sioaddr[2] = { 0x2e, 0x4e };
4314
4315 err = platform_driver_register(&nct6775_driver);
4316 if (err)
4317 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004318
4319 /*
4320 * initialize sio_data->kind and sio_data->sioreg.
4321 *
4322 * when Super-I/O functions move to a separate file, the Super-I/O
4323 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4324 * nct6775 hardware monitor, and call probe()
4325 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004326 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4327 address = nct6775_find(sioaddr[i], &sio_data);
4328 if (address <= 0)
4329 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004330
Guenter Roeck698a7c22013-04-05 07:35:25 -07004331 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004332
Guenter Roeck698a7c22013-04-05 07:35:25 -07004333 pdev[i] = platform_device_alloc(DRVNAME, address);
4334 if (!pdev[i]) {
4335 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004336 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004337 }
4338
4339 err = platform_device_add_data(pdev[i], &sio_data,
4340 sizeof(struct nct6775_sio_data));
4341 if (err)
4342 goto exit_device_put;
4343
4344 memset(&res, 0, sizeof(res));
4345 res.name = DRVNAME;
4346 res.start = address + IOREGION_OFFSET;
4347 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4348 res.flags = IORESOURCE_IO;
4349
4350 err = acpi_check_resource_conflict(&res);
4351 if (err) {
4352 platform_device_put(pdev[i]);
4353 pdev[i] = NULL;
4354 continue;
4355 }
4356
4357 err = platform_device_add_resources(pdev[i], &res, 1);
4358 if (err)
4359 goto exit_device_put;
4360
4361 /* platform_device_add calls probe() */
4362 err = platform_device_add(pdev[i]);
4363 if (err)
4364 goto exit_device_put;
4365 }
4366 if (!found) {
4367 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004368 goto exit_unregister;
4369 }
4370
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004371 return 0;
4372
4373exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004374 platform_device_put(pdev[i]);
4375exit_device_unregister:
4376 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004377 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004378 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004379 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004380exit_unregister:
4381 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004382 return err;
4383}
4384
4385static void __exit sensors_nct6775_exit(void)
4386{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004387 int i;
4388
4389 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4390 if (pdev[i])
4391 platform_device_unregister(pdev[i]);
4392 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004393 platform_driver_unregister(&nct6775_driver);
4394}
4395
4396MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004397MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004398MODULE_LICENSE("GPL");
4399
4400module_init(sensors_nct6775_init);
4401module_exit(sensors_nct6775_exit);