blob: d087a8e00cf51abede39cc653341365a841b28d3 [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 *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001048nct6775_create_attr_group(struct device *dev,
1049 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001050 int repeat)
1051{
1052 struct attribute_group *group;
1053 struct sensor_device_attr_u *su;
1054 struct sensor_device_attribute *a;
1055 struct sensor_device_attribute_2 *a2;
1056 struct attribute **attrs;
1057 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001058 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001059
1060 if (repeat <= 0)
1061 return ERR_PTR(-EINVAL);
1062
1063 t = tg->templates;
1064 for (count = 0; *t; t++, count++)
1065 ;
1066
1067 if (count == 0)
1068 return ERR_PTR(-EINVAL);
1069
1070 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1071 if (group == NULL)
1072 return ERR_PTR(-ENOMEM);
1073
1074 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1075 GFP_KERNEL);
1076 if (attrs == NULL)
1077 return ERR_PTR(-ENOMEM);
1078
1079 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1080 GFP_KERNEL);
1081 if (su == NULL)
1082 return ERR_PTR(-ENOMEM);
1083
1084 group->attrs = attrs;
1085 group->is_visible = tg->is_visible;
1086
1087 for (i = 0; i < repeat; i++) {
1088 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001089 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001090 snprintf(su->name, sizeof(su->name),
1091 (*t)->dev_attr.attr.name, tg->base + i);
1092 if ((*t)->s2) {
1093 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001094 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001095 a2->dev_attr.attr.name = su->name;
1096 a2->nr = (*t)->u.s.nr + i;
1097 a2->index = (*t)->u.s.index;
1098 a2->dev_attr.attr.mode =
1099 (*t)->dev_attr.attr.mode;
1100 a2->dev_attr.show = (*t)->dev_attr.show;
1101 a2->dev_attr.store = (*t)->dev_attr.store;
1102 *attrs = &a2->dev_attr.attr;
1103 } else {
1104 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001105 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001106 a->dev_attr.attr.name = su->name;
1107 a->index = (*t)->u.index + i;
1108 a->dev_attr.attr.mode =
1109 (*t)->dev_attr.attr.mode;
1110 a->dev_attr.show = (*t)->dev_attr.show;
1111 a->dev_attr.store = (*t)->dev_attr.store;
1112 *attrs = &a->dev_attr.attr;
1113 }
1114 attrs++;
1115 su++;
1116 t++;
1117 }
1118 }
1119
Guenter Roeckf73cf632013-03-18 09:22:50 -07001120 return group;
1121}
1122
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001123static bool is_word_sized(struct nct6775_data *data, u16 reg)
1124{
1125 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001126 case nct6106:
1127 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1128 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1129 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001130 case nct6775:
1131 return (((reg & 0xff00) == 0x100 ||
1132 (reg & 0xff00) == 0x200) &&
1133 ((reg & 0x00ff) == 0x50 ||
1134 (reg & 0x00ff) == 0x53 ||
1135 (reg & 0x00ff) == 0x55)) ||
1136 (reg & 0xfff0) == 0x630 ||
1137 reg == 0x640 || reg == 0x642 ||
1138 reg == 0x662 ||
1139 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1140 reg == 0x73 || reg == 0x75 || reg == 0x77;
1141 case nct6776:
1142 return (((reg & 0xff00) == 0x100 ||
1143 (reg & 0xff00) == 0x200) &&
1144 ((reg & 0x00ff) == 0x50 ||
1145 (reg & 0x00ff) == 0x53 ||
1146 (reg & 0x00ff) == 0x55)) ||
1147 (reg & 0xfff0) == 0x630 ||
1148 reg == 0x402 ||
1149 reg == 0x640 || reg == 0x642 ||
1150 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1151 reg == 0x73 || reg == 0x75 || reg == 0x77;
1152 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001153 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001154 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001155 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001156 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001157 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001158 reg == 0x402 ||
1159 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1160 reg == 0x640 || reg == 0x642 ||
1161 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001162 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001163 }
1164 return false;
1165}
1166
1167/*
1168 * On older chips, only registers 0x50-0x5f are banked.
1169 * On more recent chips, all registers are banked.
1170 * Assume that is the case and set the bank number for each access.
1171 * Cache the bank number so it only needs to be set if it changes.
1172 */
1173static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1174{
1175 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001176
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001177 if (data->bank != bank) {
1178 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1179 outb_p(bank, data->addr + DATA_REG_OFFSET);
1180 data->bank = bank;
1181 }
1182}
1183
1184static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1185{
1186 int res, word_sized = is_word_sized(data, reg);
1187
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001188 nct6775_set_bank(data, reg);
1189 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1190 res = inb_p(data->addr + DATA_REG_OFFSET);
1191 if (word_sized) {
1192 outb_p((reg & 0xff) + 1,
1193 data->addr + ADDR_REG_OFFSET);
1194 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1195 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001196 return res;
1197}
1198
1199static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1200{
1201 int word_sized = is_word_sized(data, reg);
1202
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001203 nct6775_set_bank(data, reg);
1204 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1205 if (word_sized) {
1206 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1207 outb_p((reg & 0xff) + 1,
1208 data->addr + ADDR_REG_OFFSET);
1209 }
1210 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001211 return 0;
1212}
1213
Guenter Roeckaa136e52012-12-04 03:26:05 -08001214/* We left-align 8-bit temperature values to make the code simpler */
1215static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1216{
1217 u16 res;
1218
1219 res = nct6775_read_value(data, reg);
1220 if (!is_word_sized(data, reg))
1221 res <<= 8;
1222
1223 return res;
1224}
1225
1226static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1227{
1228 if (!is_word_sized(data, reg))
1229 value >>= 8;
1230 return nct6775_write_value(data, reg, value);
1231}
1232
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001233/* This function assumes that the caller holds data->update_lock */
1234static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1235{
1236 u8 reg;
1237
1238 switch (nr) {
1239 case 0:
1240 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1241 | (data->fan_div[0] & 0x7);
1242 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1243 break;
1244 case 1:
1245 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1246 | ((data->fan_div[1] << 4) & 0x70);
1247 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1248 break;
1249 case 2:
1250 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1251 | (data->fan_div[2] & 0x7);
1252 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1253 break;
1254 case 3:
1255 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1256 | ((data->fan_div[3] << 4) & 0x70);
1257 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1258 break;
1259 }
1260}
1261
1262static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1263{
1264 if (data->kind == nct6775)
1265 nct6775_write_fan_div(data, nr);
1266}
1267
1268static void nct6775_update_fan_div(struct nct6775_data *data)
1269{
1270 u8 i;
1271
1272 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1273 data->fan_div[0] = i & 0x7;
1274 data->fan_div[1] = (i & 0x70) >> 4;
1275 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1276 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001277 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001278 data->fan_div[3] = (i & 0x70) >> 4;
1279}
1280
1281static void nct6775_update_fan_div_common(struct nct6775_data *data)
1282{
1283 if (data->kind == nct6775)
1284 nct6775_update_fan_div(data);
1285}
1286
1287static void nct6775_init_fan_div(struct nct6775_data *data)
1288{
1289 int i;
1290
1291 nct6775_update_fan_div_common(data);
1292 /*
1293 * For all fans, start with highest divider value if the divider
1294 * register is not initialized. This ensures that we get a
1295 * reading from the fan count register, even if it is not optimal.
1296 * We'll compute a better divider later on.
1297 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001298 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001299 if (!(data->has_fan & (1 << i)))
1300 continue;
1301 if (data->fan_div[i] == 0) {
1302 data->fan_div[i] = 7;
1303 nct6775_write_fan_div_common(data, i);
1304 }
1305 }
1306}
1307
1308static void nct6775_init_fan_common(struct device *dev,
1309 struct nct6775_data *data)
1310{
1311 int i;
1312 u8 reg;
1313
1314 if (data->has_fan_div)
1315 nct6775_init_fan_div(data);
1316
1317 /*
1318 * If fan_min is not set (0), set it to 0xff to disable it. This
1319 * prevents the unnecessary warning when fanX_min is reported as 0.
1320 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001321 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001322 if (data->has_fan_min & (1 << i)) {
1323 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1324 if (!reg)
1325 nct6775_write_value(data, data->REG_FAN_MIN[i],
1326 data->has_fan_div ? 0xff
1327 : 0xff1f);
1328 }
1329 }
1330}
1331
1332static void nct6775_select_fan_div(struct device *dev,
1333 struct nct6775_data *data, int nr, u16 reg)
1334{
1335 u8 fan_div = data->fan_div[nr];
1336 u16 fan_min;
1337
1338 if (!data->has_fan_div)
1339 return;
1340
1341 /*
1342 * If we failed to measure the fan speed, or the reported value is not
1343 * in the optimal range, and the clock divider can be modified,
1344 * let's try that for next time.
1345 */
1346 if (reg == 0x00 && fan_div < 0x07)
1347 fan_div++;
1348 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1349 fan_div--;
1350
1351 if (fan_div != data->fan_div[nr]) {
1352 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1353 nr + 1, div_from_reg(data->fan_div[nr]),
1354 div_from_reg(fan_div));
1355
1356 /* Preserve min limit if possible */
1357 if (data->has_fan_min & (1 << nr)) {
1358 fan_min = data->fan_min[nr];
1359 if (fan_div > data->fan_div[nr]) {
1360 if (fan_min != 255 && fan_min > 1)
1361 fan_min >>= 1;
1362 } else {
1363 if (fan_min != 255) {
1364 fan_min <<= 1;
1365 if (fan_min > 254)
1366 fan_min = 254;
1367 }
1368 }
1369 if (fan_min != data->fan_min[nr]) {
1370 data->fan_min[nr] = fan_min;
1371 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1372 fan_min);
1373 }
1374 }
1375 data->fan_div[nr] = fan_div;
1376 nct6775_write_fan_div_common(data, nr);
1377 }
1378}
1379
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001380static void nct6775_update_pwm(struct device *dev)
1381{
1382 struct nct6775_data *data = dev_get_drvdata(dev);
1383 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001384 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001385 bool duty_is_dc;
1386
1387 for (i = 0; i < data->pwm_num; i++) {
1388 if (!(data->has_pwm & (1 << i)))
1389 continue;
1390
1391 duty_is_dc = data->REG_PWM_MODE[i] &&
1392 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1393 & data->PWM_MODE_MASK[i]);
1394 data->pwm_mode[i] = duty_is_dc;
1395
1396 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1397 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1398 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1399 data->pwm[j][i]
1400 = nct6775_read_value(data,
1401 data->REG_PWM[j][i]);
1402 }
1403 }
1404
1405 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1406 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001407
1408 if (!data->temp_tolerance[0][i] ||
1409 data->pwm_enable[i] != speed_cruise)
1410 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1411 if (!data->target_speed_tolerance[i] ||
1412 data->pwm_enable[i] == speed_cruise) {
1413 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001414
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001415 if (data->REG_TOLERANCE_H) {
1416 t |= (nct6775_read_value(data,
1417 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1418 }
1419 data->target_speed_tolerance[i] = t;
1420 }
1421
1422 data->temp_tolerance[1][i] =
1423 nct6775_read_value(data,
1424 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1425
1426 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1427 data->pwm_temp_sel[i] = reg & 0x1f;
1428 /* If fan can stop, report floor as 0 */
1429 if (reg & 0x80)
1430 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001431
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001432 if (!data->REG_WEIGHT_TEMP_SEL[i])
1433 continue;
1434
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001435 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1436 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1437 /* If weight is disabled, report weight source as 0 */
1438 if (j == 1 && !(reg & 0x80))
1439 data->pwm_weight_temp_sel[i] = 0;
1440
1441 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001442 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001443 data->weight_temp[j][i]
1444 = nct6775_read_value(data,
1445 data->REG_WEIGHT_TEMP[j][i]);
1446 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001447 }
1448}
1449
1450static void nct6775_update_pwm_limits(struct device *dev)
1451{
1452 struct nct6775_data *data = dev_get_drvdata(dev);
1453 int i, j;
1454 u8 reg;
1455 u16 reg_t;
1456
1457 for (i = 0; i < data->pwm_num; i++) {
1458 if (!(data->has_pwm & (1 << i)))
1459 continue;
1460
Guenter Roeckc409fd42013-04-09 05:04:00 -07001461 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001462 data->fan_time[j][i] =
1463 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1464 }
1465
1466 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1467 /* Update only in matching mode or if never updated */
1468 if (!data->target_temp[i] ||
1469 data->pwm_enable[i] == thermal_cruise)
1470 data->target_temp[i] = reg_t & data->target_temp_mask;
1471 if (!data->target_speed[i] ||
1472 data->pwm_enable[i] == speed_cruise) {
1473 if (data->REG_TOLERANCE_H) {
1474 reg_t |= (nct6775_read_value(data,
1475 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1476 }
1477 data->target_speed[i] = reg_t;
1478 }
1479
1480 for (j = 0; j < data->auto_pwm_num; j++) {
1481 data->auto_pwm[i][j] =
1482 nct6775_read_value(data,
1483 NCT6775_AUTO_PWM(data, i, j));
1484 data->auto_temp[i][j] =
1485 nct6775_read_value(data,
1486 NCT6775_AUTO_TEMP(data, i, j));
1487 }
1488
1489 /* critical auto_pwm temperature data */
1490 data->auto_temp[i][data->auto_pwm_num] =
1491 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1492
1493 switch (data->kind) {
1494 case nct6775:
1495 reg = nct6775_read_value(data,
1496 NCT6775_REG_CRITICAL_ENAB[i]);
1497 data->auto_pwm[i][data->auto_pwm_num] =
1498 (reg & 0x02) ? 0xff : 0x00;
1499 break;
1500 case nct6776:
1501 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1502 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001503 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001504 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001505 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001506 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001507 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001508 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001509 data->REG_CRITICAL_PWM_ENABLE[i]);
1510 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1511 reg = nct6775_read_value(data,
1512 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001513 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001514 reg = 0xff;
1515 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001516 break;
1517 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001518 }
1519}
1520
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001521static struct nct6775_data *nct6775_update_device(struct device *dev)
1522{
1523 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001524 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001525
1526 mutex_lock(&data->update_lock);
1527
Guenter Roeck6445e662013-04-21 09:13:28 -07001528 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001529 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001530 /* Fan clock dividers */
1531 nct6775_update_fan_div_common(data);
1532
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001533 /* Measured voltages and limits */
1534 for (i = 0; i < data->in_num; i++) {
1535 if (!(data->have_in & (1 << i)))
1536 continue;
1537
1538 data->in[i][0] = nct6775_read_value(data,
1539 data->REG_VIN[i]);
1540 data->in[i][1] = nct6775_read_value(data,
1541 data->REG_IN_MINMAX[0][i]);
1542 data->in[i][2] = nct6775_read_value(data,
1543 data->REG_IN_MINMAX[1][i]);
1544 }
1545
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001546 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001547 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001548 u16 reg;
1549
1550 if (!(data->has_fan & (1 << i)))
1551 continue;
1552
1553 reg = nct6775_read_value(data, data->REG_FAN[i]);
1554 data->rpm[i] = data->fan_from_reg(reg,
1555 data->fan_div[i]);
1556
1557 if (data->has_fan_min & (1 << i))
1558 data->fan_min[i] = nct6775_read_value(data,
1559 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001560 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001561 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1562 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001563
1564 nct6775_select_fan_div(dev, data, i, reg);
1565 }
1566
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001567 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001568 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001569
Guenter Roeckaa136e52012-12-04 03:26:05 -08001570 /* Measured temperatures and limits */
1571 for (i = 0; i < NUM_TEMP; i++) {
1572 if (!(data->have_temp & (1 << i)))
1573 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001574 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001575 if (data->reg_temp[j][i])
1576 data->temp[j][i]
1577 = nct6775_read_temp(data,
1578 data->reg_temp[j][i]);
1579 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001580 if (i >= NUM_TEMP_FIXED ||
1581 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001582 continue;
1583 data->temp_offset[i]
1584 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1585 }
1586
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001587 data->alarms = 0;
1588 for (i = 0; i < NUM_REG_ALARM; i++) {
1589 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001590
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001591 if (!data->REG_ALARM[i])
1592 continue;
1593 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1594 data->alarms |= ((u64)alarm) << (i << 3);
1595 }
1596
Guenter Roeck30846992013-06-24 22:21:59 -07001597 data->beeps = 0;
1598 for (i = 0; i < NUM_REG_BEEP; i++) {
1599 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001600
Guenter Roeck30846992013-06-24 22:21:59 -07001601 if (!data->REG_BEEP[i])
1602 continue;
1603 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1604 data->beeps |= ((u64)beep) << (i << 3);
1605 }
1606
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001607 data->last_updated = jiffies;
1608 data->valid = true;
1609 }
1610
1611 mutex_unlock(&data->update_lock);
1612 return data;
1613}
1614
1615/*
1616 * Sysfs callback functions
1617 */
1618static ssize_t
1619show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1620{
1621 struct nct6775_data *data = nct6775_update_device(dev);
1622 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001623 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001624 int nr = sattr->nr;
1625
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001626 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1627}
1628
1629static ssize_t
1630store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1631 size_t count)
1632{
1633 struct nct6775_data *data = dev_get_drvdata(dev);
1634 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001635 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001636 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001637 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001638 int err;
1639
1640 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001641 if (err < 0)
1642 return err;
1643 mutex_lock(&data->update_lock);
1644 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001645 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001646 data->in[nr][index]);
1647 mutex_unlock(&data->update_lock);
1648 return count;
1649}
1650
1651static ssize_t
1652show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1653{
1654 struct nct6775_data *data = nct6775_update_device(dev);
1655 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1656 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001657
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001658 return sprintf(buf, "%u\n",
1659 (unsigned int)((data->alarms >> nr) & 0x01));
1660}
1661
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001662static int find_temp_source(struct nct6775_data *data, int index, int count)
1663{
1664 int source = data->temp_src[index];
1665 int nr;
1666
1667 for (nr = 0; nr < count; nr++) {
1668 int src;
1669
1670 src = nct6775_read_value(data,
1671 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1672 if (src == source)
1673 return nr;
1674 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001675 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001676}
1677
1678static ssize_t
1679show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1680{
1681 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1682 struct nct6775_data *data = nct6775_update_device(dev);
1683 unsigned int alarm = 0;
1684 int nr;
1685
1686 /*
1687 * For temperatures, there is no fixed mapping from registers to alarm
1688 * bits. Alarm bits are determined by the temperature source mapping.
1689 */
1690 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1691 if (nr >= 0) {
1692 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001693
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001694 alarm = (data->alarms >> bit) & 0x01;
1695 }
1696 return sprintf(buf, "%u\n", alarm);
1697}
1698
Guenter Roeck30846992013-06-24 22:21:59 -07001699static ssize_t
1700show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1701{
1702 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1703 struct nct6775_data *data = nct6775_update_device(dev);
1704 int nr = data->BEEP_BITS[sattr->index];
1705
1706 return sprintf(buf, "%u\n",
1707 (unsigned int)((data->beeps >> nr) & 0x01));
1708}
1709
1710static ssize_t
1711store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1712 size_t count)
1713{
1714 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1715 struct nct6775_data *data = dev_get_drvdata(dev);
1716 int nr = data->BEEP_BITS[sattr->index];
1717 int regindex = nr >> 3;
1718 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001719 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001720
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001721 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001722 if (err < 0)
1723 return err;
1724 if (val > 1)
1725 return -EINVAL;
1726
1727 mutex_lock(&data->update_lock);
1728 if (val)
1729 data->beeps |= (1ULL << nr);
1730 else
1731 data->beeps &= ~(1ULL << nr);
1732 nct6775_write_value(data, data->REG_BEEP[regindex],
1733 (data->beeps >> (regindex << 3)) & 0xff);
1734 mutex_unlock(&data->update_lock);
1735 return count;
1736}
1737
1738static ssize_t
1739show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1740{
1741 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1742 struct nct6775_data *data = nct6775_update_device(dev);
1743 unsigned int beep = 0;
1744 int nr;
1745
1746 /*
1747 * For temperatures, there is no fixed mapping from registers to beep
1748 * enable bits. Beep enable bits are determined by the temperature
1749 * source mapping.
1750 */
1751 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1752 if (nr >= 0) {
1753 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001754
Guenter Roeck30846992013-06-24 22:21:59 -07001755 beep = (data->beeps >> bit) & 0x01;
1756 }
1757 return sprintf(buf, "%u\n", beep);
1758}
1759
1760static ssize_t
1761store_temp_beep(struct device *dev, struct device_attribute *attr,
1762 const char *buf, size_t count)
1763{
1764 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1765 struct nct6775_data *data = dev_get_drvdata(dev);
1766 int nr, bit, regindex;
1767 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001768 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001769
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001770 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001771 if (err < 0)
1772 return err;
1773 if (val > 1)
1774 return -EINVAL;
1775
1776 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1777 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001778 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001779
1780 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1781 regindex = bit >> 3;
1782
1783 mutex_lock(&data->update_lock);
1784 if (val)
1785 data->beeps |= (1ULL << bit);
1786 else
1787 data->beeps &= ~(1ULL << bit);
1788 nct6775_write_value(data, data->REG_BEEP[regindex],
1789 (data->beeps >> (regindex << 3)) & 0xff);
1790 mutex_unlock(&data->update_lock);
1791
1792 return count;
1793}
1794
Guenter Roeckf73cf632013-03-18 09:22:50 -07001795static umode_t nct6775_in_is_visible(struct kobject *kobj,
1796 struct attribute *attr, int index)
1797{
1798 struct device *dev = container_of(kobj, struct device, kobj);
1799 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001800 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001801
Guenter Roeckf73cf632013-03-18 09:22:50 -07001802 if (!(data->have_in & (1 << in)))
1803 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001804
Guenter Roeckf73cf632013-03-18 09:22:50 -07001805 return attr->mode;
1806}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001807
Guenter Roeckf73cf632013-03-18 09:22:50 -07001808SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1809SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001810SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1811 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001812SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1813 store_in_reg, 0, 1);
1814SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1815 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001816
Guenter Roeckf73cf632013-03-18 09:22:50 -07001817/*
1818 * nct6775_in_is_visible uses the index into the following array
1819 * to determine if attributes should be created or not.
1820 * Any change in order or content must be matched.
1821 */
1822static struct sensor_device_template *nct6775_attributes_in_template[] = {
1823 &sensor_dev_template_in_input,
1824 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001825 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001826 &sensor_dev_template_in_min,
1827 &sensor_dev_template_in_max,
1828 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001829};
1830
Julia Lawallc60fdf82015-12-12 17:36:39 +01001831static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001832 .templates = nct6775_attributes_in_template,
1833 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001834};
1835
1836static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001837show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1838{
1839 struct nct6775_data *data = nct6775_update_device(dev);
1840 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1841 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001842
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001843 return sprintf(buf, "%d\n", data->rpm[nr]);
1844}
1845
1846static ssize_t
1847show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1848{
1849 struct nct6775_data *data = nct6775_update_device(dev);
1850 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1851 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001852
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001853 return sprintf(buf, "%d\n",
1854 data->fan_from_reg_min(data->fan_min[nr],
1855 data->fan_div[nr]));
1856}
1857
1858static ssize_t
1859show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1860{
1861 struct nct6775_data *data = nct6775_update_device(dev);
1862 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1863 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001864
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001865 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1866}
1867
1868static ssize_t
1869store_fan_min(struct device *dev, struct device_attribute *attr,
1870 const char *buf, size_t count)
1871{
1872 struct nct6775_data *data = dev_get_drvdata(dev);
1873 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1874 int nr = sattr->index;
1875 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001876 unsigned int reg;
1877 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001878 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001879
1880 err = kstrtoul(buf, 10, &val);
1881 if (err < 0)
1882 return err;
1883
1884 mutex_lock(&data->update_lock);
1885 if (!data->has_fan_div) {
1886 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1887 if (!val) {
1888 val = 0xff1f;
1889 } else {
1890 if (val > 1350000U)
1891 val = 135000U;
1892 val = 1350000U / val;
1893 val = (val & 0x1f) | ((val << 3) & 0xff00);
1894 }
1895 data->fan_min[nr] = val;
1896 goto write_min; /* Leave fan divider alone */
1897 }
1898 if (!val) {
1899 /* No min limit, alarm disabled */
1900 data->fan_min[nr] = 255;
1901 new_div = data->fan_div[nr]; /* No change */
1902 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1903 goto write_div;
1904 }
1905 reg = 1350000U / val;
1906 if (reg >= 128 * 255) {
1907 /*
1908 * Speed below this value cannot possibly be represented,
1909 * even with the highest divider (128)
1910 */
1911 data->fan_min[nr] = 254;
1912 new_div = 7; /* 128 == (1 << 7) */
1913 dev_warn(dev,
1914 "fan%u low limit %lu below minimum %u, set to minimum\n",
1915 nr + 1, val, data->fan_from_reg_min(254, 7));
1916 } else if (!reg) {
1917 /*
1918 * Speed above this value cannot possibly be represented,
1919 * even with the lowest divider (1)
1920 */
1921 data->fan_min[nr] = 1;
1922 new_div = 0; /* 1 == (1 << 0) */
1923 dev_warn(dev,
1924 "fan%u low limit %lu above maximum %u, set to maximum\n",
1925 nr + 1, val, data->fan_from_reg_min(1, 0));
1926 } else {
1927 /*
1928 * Automatically pick the best divider, i.e. the one such
1929 * that the min limit will correspond to a register value
1930 * in the 96..192 range
1931 */
1932 new_div = 0;
1933 while (reg > 192 && new_div < 7) {
1934 reg >>= 1;
1935 new_div++;
1936 }
1937 data->fan_min[nr] = reg;
1938 }
1939
1940write_div:
1941 /*
1942 * Write both the fan clock divider (if it changed) and the new
1943 * fan min (unconditionally)
1944 */
1945 if (new_div != data->fan_div[nr]) {
1946 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1947 nr + 1, div_from_reg(data->fan_div[nr]),
1948 div_from_reg(new_div));
1949 data->fan_div[nr] = new_div;
1950 nct6775_write_fan_div_common(data, nr);
1951 /* Give the chip time to sample a new speed value */
1952 data->last_updated = jiffies;
1953 }
1954
1955write_min:
1956 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1957 mutex_unlock(&data->update_lock);
1958
1959 return count;
1960}
1961
Guenter Roeck5c25d952012-12-11 07:29:06 -08001962static ssize_t
1963show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1964{
1965 struct nct6775_data *data = nct6775_update_device(dev);
1966 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1967 int p = data->fan_pulses[sattr->index];
1968
1969 return sprintf(buf, "%d\n", p ? : 4);
1970}
1971
1972static ssize_t
1973store_fan_pulses(struct device *dev, struct device_attribute *attr,
1974 const char *buf, size_t count)
1975{
1976 struct nct6775_data *data = dev_get_drvdata(dev);
1977 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1978 int nr = sattr->index;
1979 unsigned long val;
1980 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001981 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001982
1983 err = kstrtoul(buf, 10, &val);
1984 if (err < 0)
1985 return err;
1986
1987 if (val > 4)
1988 return -EINVAL;
1989
1990 mutex_lock(&data->update_lock);
1991 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001992 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1993 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1994 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1995 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001996 mutex_unlock(&data->update_lock);
1997
1998 return count;
1999}
2000
Guenter Roeckf73cf632013-03-18 09:22:50 -07002001static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2002 struct attribute *attr, int index)
2003{
2004 struct device *dev = container_of(kobj, struct device, kobj);
2005 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002006 int fan = index / 6; /* fan index */
2007 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002008
2009 if (!(data->has_fan & (1 << fan)))
2010 return 0;
2011
2012 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2013 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002014 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002015 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002016 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
2017 return 0;
2018 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002019 return 0;
2020
2021 return attr->mode;
2022}
2023
2024SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2025SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2026 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002027SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2028 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002029SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2030 store_fan_pulses, 0);
2031SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2032 store_fan_min, 0);
2033SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2034
2035/*
2036 * nct6775_fan_is_visible uses the index into the following array
2037 * to determine if attributes should be created or not.
2038 * Any change in order or content must be matched.
2039 */
2040static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2041 &sensor_dev_template_fan_input,
2042 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002043 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002044 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002045 &sensor_dev_template_fan_min, /* 4 */
2046 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002047 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002048};
2049
Julia Lawallc60fdf82015-12-12 17:36:39 +01002050static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002051 .templates = nct6775_attributes_fan_template,
2052 .is_visible = nct6775_fan_is_visible,
2053 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002054};
2055
2056static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002057show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2058{
2059 struct nct6775_data *data = nct6775_update_device(dev);
2060 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2061 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002062
Guenter Roeckaa136e52012-12-04 03:26:05 -08002063 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2064}
2065
2066static ssize_t
2067show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2068{
2069 struct nct6775_data *data = nct6775_update_device(dev);
2070 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2071 int nr = sattr->nr;
2072 int index = sattr->index;
2073
2074 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2075}
2076
2077static ssize_t
2078store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2079 size_t count)
2080{
2081 struct nct6775_data *data = dev_get_drvdata(dev);
2082 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2083 int nr = sattr->nr;
2084 int index = sattr->index;
2085 int err;
2086 long val;
2087
2088 err = kstrtol(buf, 10, &val);
2089 if (err < 0)
2090 return err;
2091
2092 mutex_lock(&data->update_lock);
2093 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2094 nct6775_write_temp(data, data->reg_temp[index][nr],
2095 data->temp[index][nr]);
2096 mutex_unlock(&data->update_lock);
2097 return count;
2098}
2099
2100static ssize_t
2101show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2102{
2103 struct nct6775_data *data = nct6775_update_device(dev);
2104 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2105
2106 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2107}
2108
2109static ssize_t
2110store_temp_offset(struct device *dev, struct device_attribute *attr,
2111 const char *buf, size_t count)
2112{
2113 struct nct6775_data *data = dev_get_drvdata(dev);
2114 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2115 int nr = sattr->index;
2116 long val;
2117 int err;
2118
2119 err = kstrtol(buf, 10, &val);
2120 if (err < 0)
2121 return err;
2122
2123 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2124
2125 mutex_lock(&data->update_lock);
2126 data->temp_offset[nr] = val;
2127 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2128 mutex_unlock(&data->update_lock);
2129
2130 return count;
2131}
2132
2133static ssize_t
2134show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2135{
2136 struct nct6775_data *data = nct6775_update_device(dev);
2137 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2138 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002139
Guenter Roeckaa136e52012-12-04 03:26:05 -08002140 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2141}
2142
2143static ssize_t
2144store_temp_type(struct device *dev, struct device_attribute *attr,
2145 const char *buf, size_t count)
2146{
2147 struct nct6775_data *data = nct6775_update_device(dev);
2148 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2149 int nr = sattr->index;
2150 unsigned long val;
2151 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002152 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002153
2154 err = kstrtoul(buf, 10, &val);
2155 if (err < 0)
2156 return err;
2157
2158 if (val != 1 && val != 3 && val != 4)
2159 return -EINVAL;
2160
2161 mutex_lock(&data->update_lock);
2162
2163 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002164 vbit = 0x02 << nr;
2165 dbit = data->DIODE_MASK << nr;
2166 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2167 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002168 switch (val) {
2169 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002170 vbat |= vbit;
2171 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002172 break;
2173 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002174 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002175 break;
2176 case 4: /* thermistor */
2177 break;
2178 }
2179 nct6775_write_value(data, data->REG_VBAT, vbat);
2180 nct6775_write_value(data, data->REG_DIODE, diode);
2181
2182 mutex_unlock(&data->update_lock);
2183 return count;
2184}
2185
Guenter Roeckf73cf632013-03-18 09:22:50 -07002186static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2187 struct attribute *attr, int index)
2188{
2189 struct device *dev = container_of(kobj, struct device, kobj);
2190 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002191 int temp = index / 10; /* temp index */
2192 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002193
2194 if (!(data->have_temp & (1 << temp)))
2195 return 0;
2196
2197 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2198 return 0; /* alarm */
2199
Guenter Roeck30846992013-06-24 22:21:59 -07002200 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2201 return 0; /* beep */
2202
2203 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002204 return 0;
2205
Guenter Roeck30846992013-06-24 22:21:59 -07002206 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002207 return 0;
2208
Guenter Roeck30846992013-06-24 22:21:59 -07002209 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002210 return 0;
2211
Guenter Roeck30846992013-06-24 22:21:59 -07002212 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002213 return 0;
2214
2215 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002216 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002217 return 0;
2218
2219 return attr->mode;
2220}
2221
2222SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2223SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2224SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2225 store_temp, 0, 1);
2226SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2227 show_temp, store_temp, 0, 2);
2228SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2229 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002230SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2231 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002232SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2233 show_temp_offset, store_temp_offset, 0);
2234SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2235 store_temp_type, 0);
2236SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002237SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2238 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002239
2240/*
2241 * nct6775_temp_is_visible uses the index into the following array
2242 * to determine if attributes should be created or not.
2243 * Any change in order or content must be matched.
2244 */
2245static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2246 &sensor_dev_template_temp_input,
2247 &sensor_dev_template_temp_label,
2248 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002249 &sensor_dev_template_temp_beep, /* 3 */
2250 &sensor_dev_template_temp_max, /* 4 */
2251 &sensor_dev_template_temp_max_hyst, /* 5 */
2252 &sensor_dev_template_temp_crit, /* 6 */
2253 &sensor_dev_template_temp_lcrit, /* 7 */
2254 &sensor_dev_template_temp_offset, /* 8 */
2255 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002256 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002257};
2258
Julia Lawallc60fdf82015-12-12 17:36:39 +01002259static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002260 .templates = nct6775_attributes_temp_template,
2261 .is_visible = nct6775_temp_is_visible,
2262 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002263};
2264
Guenter Roeckaa136e52012-12-04 03:26:05 -08002265static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002266show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2267{
2268 struct nct6775_data *data = nct6775_update_device(dev);
2269 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2270
2271 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2272}
2273
2274static ssize_t
2275store_pwm_mode(struct device *dev, struct device_attribute *attr,
2276 const char *buf, size_t count)
2277{
2278 struct nct6775_data *data = dev_get_drvdata(dev);
2279 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2280 int nr = sattr->index;
2281 unsigned long val;
2282 int err;
2283 u8 reg;
2284
2285 err = kstrtoul(buf, 10, &val);
2286 if (err < 0)
2287 return err;
2288
2289 if (val > 1)
2290 return -EINVAL;
2291
2292 /* Setting DC mode is not supported for all chips/channels */
2293 if (data->REG_PWM_MODE[nr] == 0) {
2294 if (val)
2295 return -EINVAL;
2296 return count;
2297 }
2298
2299 mutex_lock(&data->update_lock);
2300 data->pwm_mode[nr] = val;
2301 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2302 reg &= ~data->PWM_MODE_MASK[nr];
2303 if (val)
2304 reg |= data->PWM_MODE_MASK[nr];
2305 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2306 mutex_unlock(&data->update_lock);
2307 return count;
2308}
2309
2310static ssize_t
2311show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2312{
2313 struct nct6775_data *data = nct6775_update_device(dev);
2314 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2315 int nr = sattr->nr;
2316 int index = sattr->index;
2317 int pwm;
2318
2319 /*
2320 * For automatic fan control modes, show current pwm readings.
2321 * Otherwise, show the configured value.
2322 */
2323 if (index == 0 && data->pwm_enable[nr] > manual)
2324 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2325 else
2326 pwm = data->pwm[index][nr];
2327
2328 return sprintf(buf, "%d\n", pwm);
2329}
2330
2331static ssize_t
2332store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2333 size_t count)
2334{
2335 struct nct6775_data *data = dev_get_drvdata(dev);
2336 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2337 int nr = sattr->nr;
2338 int index = sattr->index;
2339 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002340 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2341 int maxval[7]
2342 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002343 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002344 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002345
2346 err = kstrtoul(buf, 10, &val);
2347 if (err < 0)
2348 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002349 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002350
2351 mutex_lock(&data->update_lock);
2352 data->pwm[index][nr] = val;
2353 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002354 if (index == 2) { /* floor: disable if val == 0 */
2355 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2356 reg &= 0x7f;
2357 if (val)
2358 reg |= 0x80;
2359 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2360 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002361 mutex_unlock(&data->update_lock);
2362 return count;
2363}
2364
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002365/* Returns 0 if OK, -EINVAL otherwise */
2366static int check_trip_points(struct nct6775_data *data, int nr)
2367{
2368 int i;
2369
2370 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2371 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2372 return -EINVAL;
2373 }
2374 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2375 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2376 return -EINVAL;
2377 }
2378 /* validate critical temperature and pwm if enabled (pwm > 0) */
2379 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2380 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2381 data->auto_temp[nr][data->auto_pwm_num] ||
2382 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2383 data->auto_pwm[nr][data->auto_pwm_num])
2384 return -EINVAL;
2385 }
2386 return 0;
2387}
2388
2389static void pwm_update_registers(struct nct6775_data *data, int nr)
2390{
2391 u8 reg;
2392
2393 switch (data->pwm_enable[nr]) {
2394 case off:
2395 case manual:
2396 break;
2397 case speed_cruise:
2398 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2399 reg = (reg & ~data->tolerance_mask) |
2400 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2401 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2402 nct6775_write_value(data, data->REG_TARGET[nr],
2403 data->target_speed[nr] & 0xff);
2404 if (data->REG_TOLERANCE_H) {
2405 reg = (data->target_speed[nr] >> 8) & 0x0f;
2406 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2407 nct6775_write_value(data,
2408 data->REG_TOLERANCE_H[nr],
2409 reg);
2410 }
2411 break;
2412 case thermal_cruise:
2413 nct6775_write_value(data, data->REG_TARGET[nr],
2414 data->target_temp[nr]);
2415 /* intentional */
2416 default:
2417 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2418 reg = (reg & ~data->tolerance_mask) |
2419 data->temp_tolerance[0][nr];
2420 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2421 break;
2422 }
2423}
2424
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002425static ssize_t
2426show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2427{
2428 struct nct6775_data *data = nct6775_update_device(dev);
2429 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2430
2431 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2432}
2433
2434static ssize_t
2435store_pwm_enable(struct device *dev, struct device_attribute *attr,
2436 const char *buf, size_t count)
2437{
2438 struct nct6775_data *data = dev_get_drvdata(dev);
2439 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2440 int nr = sattr->index;
2441 unsigned long val;
2442 int err;
2443 u16 reg;
2444
2445 err = kstrtoul(buf, 10, &val);
2446 if (err < 0)
2447 return err;
2448
2449 if (val > sf4)
2450 return -EINVAL;
2451
2452 if (val == sf3 && data->kind != nct6775)
2453 return -EINVAL;
2454
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002455 if (val == sf4 && check_trip_points(data, nr)) {
2456 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2457 dev_err(dev, "Adjust trip points and try again\n");
2458 return -EINVAL;
2459 }
2460
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002461 mutex_lock(&data->update_lock);
2462 data->pwm_enable[nr] = val;
2463 if (val == off) {
2464 /*
2465 * turn off pwm control: select manual mode, set pwm to maximum
2466 */
2467 data->pwm[0][nr] = 255;
2468 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2469 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002470 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002471 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2472 reg &= 0x0f;
2473 reg |= pwm_enable_to_reg(val) << 4;
2474 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2475 mutex_unlock(&data->update_lock);
2476 return count;
2477}
2478
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002479static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002480show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002481{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002482 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002483
2484 for (i = 0; i < NUM_TEMP; i++) {
2485 if (!(data->have_temp & (1 << i)))
2486 continue;
2487 if (src == data->temp_src[i]) {
2488 sel = i + 1;
2489 break;
2490 }
2491 }
2492
2493 return sprintf(buf, "%d\n", sel);
2494}
2495
2496static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002497show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2498{
2499 struct nct6775_data *data = nct6775_update_device(dev);
2500 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2501 int index = sattr->index;
2502
2503 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2504}
2505
2506static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002507store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2508 const char *buf, size_t count)
2509{
2510 struct nct6775_data *data = nct6775_update_device(dev);
2511 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2512 int nr = sattr->index;
2513 unsigned long val;
2514 int err, reg, src;
2515
2516 err = kstrtoul(buf, 10, &val);
2517 if (err < 0)
2518 return err;
2519 if (val == 0 || val > NUM_TEMP)
2520 return -EINVAL;
2521 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2522 return -EINVAL;
2523
2524 mutex_lock(&data->update_lock);
2525 src = data->temp_src[val - 1];
2526 data->pwm_temp_sel[nr] = src;
2527 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2528 reg &= 0xe0;
2529 reg |= src;
2530 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2531 mutex_unlock(&data->update_lock);
2532
2533 return count;
2534}
2535
2536static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002537show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2538 char *buf)
2539{
2540 struct nct6775_data *data = nct6775_update_device(dev);
2541 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2542 int index = sattr->index;
2543
2544 return show_pwm_temp_sel_common(data, buf,
2545 data->pwm_weight_temp_sel[index]);
2546}
2547
2548static ssize_t
2549store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2550 const char *buf, size_t count)
2551{
2552 struct nct6775_data *data = nct6775_update_device(dev);
2553 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2554 int nr = sattr->index;
2555 unsigned long val;
2556 int err, reg, src;
2557
2558 err = kstrtoul(buf, 10, &val);
2559 if (err < 0)
2560 return err;
2561 if (val > NUM_TEMP)
2562 return -EINVAL;
2563 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2564 !data->temp_src[val - 1]))
2565 return -EINVAL;
2566
2567 mutex_lock(&data->update_lock);
2568 if (val) {
2569 src = data->temp_src[val - 1];
2570 data->pwm_weight_temp_sel[nr] = src;
2571 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2572 reg &= 0xe0;
2573 reg |= (src | 0x80);
2574 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2575 } else {
2576 data->pwm_weight_temp_sel[nr] = 0;
2577 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2578 reg &= 0x7f;
2579 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2580 }
2581 mutex_unlock(&data->update_lock);
2582
2583 return count;
2584}
2585
2586static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002587show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2588{
2589 struct nct6775_data *data = nct6775_update_device(dev);
2590 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2591
2592 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2593}
2594
2595static ssize_t
2596store_target_temp(struct device *dev, struct device_attribute *attr,
2597 const char *buf, size_t count)
2598{
2599 struct nct6775_data *data = dev_get_drvdata(dev);
2600 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2601 int nr = sattr->index;
2602 unsigned long val;
2603 int err;
2604
2605 err = kstrtoul(buf, 10, &val);
2606 if (err < 0)
2607 return err;
2608
2609 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2610 data->target_temp_mask);
2611
2612 mutex_lock(&data->update_lock);
2613 data->target_temp[nr] = val;
2614 pwm_update_registers(data, nr);
2615 mutex_unlock(&data->update_lock);
2616 return count;
2617}
2618
2619static ssize_t
2620show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2621{
2622 struct nct6775_data *data = nct6775_update_device(dev);
2623 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2624 int nr = sattr->index;
2625
2626 return sprintf(buf, "%d\n",
2627 fan_from_reg16(data->target_speed[nr],
2628 data->fan_div[nr]));
2629}
2630
2631static ssize_t
2632store_target_speed(struct device *dev, struct device_attribute *attr,
2633 const char *buf, size_t count)
2634{
2635 struct nct6775_data *data = dev_get_drvdata(dev);
2636 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2637 int nr = sattr->index;
2638 unsigned long val;
2639 int err;
2640 u16 speed;
2641
2642 err = kstrtoul(buf, 10, &val);
2643 if (err < 0)
2644 return err;
2645
2646 val = clamp_val(val, 0, 1350000U);
2647 speed = fan_to_reg(val, data->fan_div[nr]);
2648
2649 mutex_lock(&data->update_lock);
2650 data->target_speed[nr] = speed;
2651 pwm_update_registers(data, nr);
2652 mutex_unlock(&data->update_lock);
2653 return count;
2654}
2655
2656static ssize_t
2657show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2658 char *buf)
2659{
2660 struct nct6775_data *data = nct6775_update_device(dev);
2661 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2662 int nr = sattr->nr;
2663 int index = sattr->index;
2664
2665 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2666}
2667
2668static ssize_t
2669store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2670 const char *buf, size_t count)
2671{
2672 struct nct6775_data *data = dev_get_drvdata(dev);
2673 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2674 int nr = sattr->nr;
2675 int index = sattr->index;
2676 unsigned long val;
2677 int err;
2678
2679 err = kstrtoul(buf, 10, &val);
2680 if (err < 0)
2681 return err;
2682
2683 /* Limit tolerance as needed */
2684 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2685
2686 mutex_lock(&data->update_lock);
2687 data->temp_tolerance[index][nr] = val;
2688 if (index)
2689 pwm_update_registers(data, nr);
2690 else
2691 nct6775_write_value(data,
2692 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2693 val);
2694 mutex_unlock(&data->update_lock);
2695 return count;
2696}
2697
2698/*
2699 * Fan speed tolerance is a tricky beast, since the associated register is
2700 * a tick counter, but the value is reported and configured as rpm.
2701 * Compute resulting low and high rpm values and report the difference.
2702 */
2703static ssize_t
2704show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2705 char *buf)
2706{
2707 struct nct6775_data *data = nct6775_update_device(dev);
2708 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2709 int nr = sattr->index;
2710 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2711 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2712 int tolerance;
2713
2714 if (low <= 0)
2715 low = 1;
2716 if (high > 0xffff)
2717 high = 0xffff;
2718 if (high < low)
2719 high = low;
2720
2721 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2722 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2723
2724 return sprintf(buf, "%d\n", tolerance);
2725}
2726
2727static ssize_t
2728store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2729 const char *buf, size_t count)
2730{
2731 struct nct6775_data *data = dev_get_drvdata(dev);
2732 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2733 int nr = sattr->index;
2734 unsigned long val;
2735 int err;
2736 int low, high;
2737
2738 err = kstrtoul(buf, 10, &val);
2739 if (err < 0)
2740 return err;
2741
2742 high = fan_from_reg16(data->target_speed[nr],
2743 data->fan_div[nr]) + val;
2744 low = fan_from_reg16(data->target_speed[nr],
2745 data->fan_div[nr]) - val;
2746 if (low <= 0)
2747 low = 1;
2748 if (high < low)
2749 high = low;
2750
2751 val = (fan_to_reg(low, data->fan_div[nr]) -
2752 fan_to_reg(high, data->fan_div[nr])) / 2;
2753
2754 /* Limit tolerance as needed */
2755 val = clamp_val(val, 0, data->speed_tolerance_limit);
2756
2757 mutex_lock(&data->update_lock);
2758 data->target_speed_tolerance[nr] = val;
2759 pwm_update_registers(data, nr);
2760 mutex_unlock(&data->update_lock);
2761 return count;
2762}
2763
Guenter Roeckf73cf632013-03-18 09:22:50 -07002764SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2765SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2766 store_pwm_mode, 0);
2767SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2768 store_pwm_enable, 0);
2769SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2770 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2771SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2772 show_target_temp, store_target_temp, 0);
2773SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2774 show_target_speed, store_target_speed, 0);
2775SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2776 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002777
2778/* Smart Fan registers */
2779
2780static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002781show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2782{
2783 struct nct6775_data *data = nct6775_update_device(dev);
2784 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2785 int nr = sattr->nr;
2786 int index = sattr->index;
2787
2788 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2789}
2790
2791static ssize_t
2792store_weight_temp(struct device *dev, struct device_attribute *attr,
2793 const char *buf, size_t count)
2794{
2795 struct nct6775_data *data = dev_get_drvdata(dev);
2796 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2797 int nr = sattr->nr;
2798 int index = sattr->index;
2799 unsigned long val;
2800 int err;
2801
2802 err = kstrtoul(buf, 10, &val);
2803 if (err < 0)
2804 return err;
2805
2806 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2807
2808 mutex_lock(&data->update_lock);
2809 data->weight_temp[index][nr] = val;
2810 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2811 mutex_unlock(&data->update_lock);
2812 return count;
2813}
2814
Guenter Roeckf73cf632013-03-18 09:22:50 -07002815SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2816 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2817SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2818 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2819SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2820 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2821SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2822 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2823SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2824 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2825SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2826 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002827
2828static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002829show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2830{
2831 struct nct6775_data *data = nct6775_update_device(dev);
2832 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2833 int nr = sattr->nr;
2834 int index = sattr->index;
2835
2836 return sprintf(buf, "%d\n",
2837 step_time_from_reg(data->fan_time[index][nr],
2838 data->pwm_mode[nr]));
2839}
2840
2841static ssize_t
2842store_fan_time(struct device *dev, struct device_attribute *attr,
2843 const char *buf, size_t count)
2844{
2845 struct nct6775_data *data = dev_get_drvdata(dev);
2846 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2847 int nr = sattr->nr;
2848 int index = sattr->index;
2849 unsigned long val;
2850 int err;
2851
2852 err = kstrtoul(buf, 10, &val);
2853 if (err < 0)
2854 return err;
2855
2856 val = step_time_to_reg(val, data->pwm_mode[nr]);
2857 mutex_lock(&data->update_lock);
2858 data->fan_time[index][nr] = val;
2859 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2860 mutex_unlock(&data->update_lock);
2861 return count;
2862}
2863
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002864static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002865show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2866{
2867 struct nct6775_data *data = nct6775_update_device(dev);
2868 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2869
2870 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2871}
2872
2873static ssize_t
2874store_auto_pwm(struct device *dev, struct device_attribute *attr,
2875 const char *buf, size_t count)
2876{
2877 struct nct6775_data *data = dev_get_drvdata(dev);
2878 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2879 int nr = sattr->nr;
2880 int point = sattr->index;
2881 unsigned long val;
2882 int err;
2883 u8 reg;
2884
2885 err = kstrtoul(buf, 10, &val);
2886 if (err < 0)
2887 return err;
2888 if (val > 255)
2889 return -EINVAL;
2890
2891 if (point == data->auto_pwm_num) {
2892 if (data->kind != nct6775 && !val)
2893 return -EINVAL;
2894 if (data->kind != nct6779 && val)
2895 val = 0xff;
2896 }
2897
2898 mutex_lock(&data->update_lock);
2899 data->auto_pwm[nr][point] = val;
2900 if (point < data->auto_pwm_num) {
2901 nct6775_write_value(data,
2902 NCT6775_AUTO_PWM(data, nr, point),
2903 data->auto_pwm[nr][point]);
2904 } else {
2905 switch (data->kind) {
2906 case nct6775:
2907 /* disable if needed (pwm == 0) */
2908 reg = nct6775_read_value(data,
2909 NCT6775_REG_CRITICAL_ENAB[nr]);
2910 if (val)
2911 reg |= 0x02;
2912 else
2913 reg &= ~0x02;
2914 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2915 reg);
2916 break;
2917 case nct6776:
2918 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002919 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002920 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002921 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002922 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002923 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002924 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002925 val);
2926 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002927 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002928 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002929 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002930 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002931 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002932 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002933 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002934 reg);
2935 break;
2936 }
2937 }
2938 mutex_unlock(&data->update_lock);
2939 return count;
2940}
2941
2942static ssize_t
2943show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2944{
2945 struct nct6775_data *data = nct6775_update_device(dev);
2946 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2947 int nr = sattr->nr;
2948 int point = sattr->index;
2949
2950 /*
2951 * We don't know for sure if the temperature is signed or unsigned.
2952 * Assume it is unsigned.
2953 */
2954 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2955}
2956
2957static ssize_t
2958store_auto_temp(struct device *dev, struct device_attribute *attr,
2959 const char *buf, size_t count)
2960{
2961 struct nct6775_data *data = dev_get_drvdata(dev);
2962 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2963 int nr = sattr->nr;
2964 int point = sattr->index;
2965 unsigned long val;
2966 int err;
2967
2968 err = kstrtoul(buf, 10, &val);
2969 if (err)
2970 return err;
2971 if (val > 255000)
2972 return -EINVAL;
2973
2974 mutex_lock(&data->update_lock);
2975 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2976 if (point < data->auto_pwm_num) {
2977 nct6775_write_value(data,
2978 NCT6775_AUTO_TEMP(data, nr, point),
2979 data->auto_temp[nr][point]);
2980 } else {
2981 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2982 data->auto_temp[nr][point]);
2983 }
2984 mutex_unlock(&data->update_lock);
2985 return count;
2986}
2987
Guenter Roeckf73cf632013-03-18 09:22:50 -07002988static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2989 struct attribute *attr, int index)
2990{
2991 struct device *dev = container_of(kobj, struct device, kobj);
2992 struct nct6775_data *data = dev_get_drvdata(dev);
2993 int pwm = index / 36; /* pwm index */
2994 int nr = index % 36; /* attribute index */
2995
2996 if (!(data->has_pwm & (1 << pwm)))
2997 return 0;
2998
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002999 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3000 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3001 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003002 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3003 return 0;
3004 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3005 return 0;
3006 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3007 return 0;
3008
3009 if (nr >= 22 && nr <= 35) { /* auto point */
3010 int api = (nr - 22) / 2; /* auto point index */
3011
3012 if (api > data->auto_pwm_num)
3013 return 0;
3014 }
3015 return attr->mode;
3016}
3017
3018SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3019 show_fan_time, store_fan_time, 0, 0);
3020SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3021 show_fan_time, store_fan_time, 0, 1);
3022SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3023 show_fan_time, store_fan_time, 0, 2);
3024SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3025 store_pwm, 0, 1);
3026SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3027 store_pwm, 0, 2);
3028SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3029 show_temp_tolerance, store_temp_tolerance, 0, 0);
3030SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3031 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3032 0, 1);
3033
3034SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3035 0, 3);
3036
3037SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3038 store_pwm, 0, 4);
3039
3040SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3041 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3042SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3043 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3044
3045SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3046 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3047SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3048 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3049
3050SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3051 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3052SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3053 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3054
3055SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3056 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3057SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3058 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3059
3060SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3061 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3062SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3063 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3064
3065SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3066 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3067SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3068 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3069
3070SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3071 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3072SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3073 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3074
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003075/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003076 * nct6775_pwm_is_visible uses the index into the following array
3077 * to determine if attributes should be created or not.
3078 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003079 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003080static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3081 &sensor_dev_template_pwm,
3082 &sensor_dev_template_pwm_mode,
3083 &sensor_dev_template_pwm_enable,
3084 &sensor_dev_template_pwm_temp_sel,
3085 &sensor_dev_template_pwm_temp_tolerance,
3086 &sensor_dev_template_pwm_crit_temp_tolerance,
3087 &sensor_dev_template_pwm_target_temp,
3088 &sensor_dev_template_fan_target,
3089 &sensor_dev_template_fan_tolerance,
3090 &sensor_dev_template_pwm_stop_time,
3091 &sensor_dev_template_pwm_step_up_time,
3092 &sensor_dev_template_pwm_step_down_time,
3093 &sensor_dev_template_pwm_start,
3094 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003095 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003096 &sensor_dev_template_pwm_weight_temp_step,
3097 &sensor_dev_template_pwm_weight_temp_step_tol,
3098 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003099 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003100 &sensor_dev_template_pwm_max, /* 19 */
3101 &sensor_dev_template_pwm_step, /* 20 */
3102 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3103 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3104 &sensor_dev_template_pwm_auto_point1_temp,
3105 &sensor_dev_template_pwm_auto_point2_pwm,
3106 &sensor_dev_template_pwm_auto_point2_temp,
3107 &sensor_dev_template_pwm_auto_point3_pwm,
3108 &sensor_dev_template_pwm_auto_point3_temp,
3109 &sensor_dev_template_pwm_auto_point4_pwm,
3110 &sensor_dev_template_pwm_auto_point4_temp,
3111 &sensor_dev_template_pwm_auto_point5_pwm,
3112 &sensor_dev_template_pwm_auto_point5_temp,
3113 &sensor_dev_template_pwm_auto_point6_pwm,
3114 &sensor_dev_template_pwm_auto_point6_temp,
3115 &sensor_dev_template_pwm_auto_point7_pwm,
3116 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003117
Guenter Roeckf73cf632013-03-18 09:22:50 -07003118 NULL
3119};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003120
Julia Lawallc60fdf82015-12-12 17:36:39 +01003121static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003122 .templates = nct6775_attributes_pwm_template,
3123 .is_visible = nct6775_pwm_is_visible,
3124 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003125};
3126
3127static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003128show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3129{
3130 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003131
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003132 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3133}
3134
3135static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3136
Guenter Roecka6bd5872012-12-04 03:13:34 -08003137/* Case open detection */
3138
3139static ssize_t
3140clear_caseopen(struct device *dev, struct device_attribute *attr,
3141 const char *buf, size_t count)
3142{
3143 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003144 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3145 unsigned long val;
3146 u8 reg;
3147 int ret;
3148
3149 if (kstrtoul(buf, 10, &val) || val != 0)
3150 return -EINVAL;
3151
3152 mutex_lock(&data->update_lock);
3153
3154 /*
3155 * Use CR registers to clear caseopen status.
3156 * The CR registers are the same for all chips, and not all chips
3157 * support clearing the caseopen status through "regular" registers.
3158 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003159 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003160 if (ret) {
3161 count = ret;
3162 goto error;
3163 }
3164
Guenter Roeckdf612d52013-07-08 13:15:04 -07003165 superio_select(data->sioreg, NCT6775_LD_ACPI);
3166 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003167 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003168 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003169 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003170 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3171 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003172
3173 data->valid = false; /* Force cache refresh */
3174error:
3175 mutex_unlock(&data->update_lock);
3176 return count;
3177}
3178
Guenter Roeckf73cf632013-03-18 09:22:50 -07003179static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3180 clear_caseopen, INTRUSION_ALARM_BASE);
3181static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3182 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003183static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3184 store_beep, INTRUSION_ALARM_BASE);
3185static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3186 store_beep, INTRUSION_ALARM_BASE + 1);
3187static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3188 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003189
3190static umode_t nct6775_other_is_visible(struct kobject *kobj,
3191 struct attribute *attr, int index)
3192{
3193 struct device *dev = container_of(kobj, struct device, kobj);
3194 struct nct6775_data *data = dev_get_drvdata(dev);
3195
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003196 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003197 return 0;
3198
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003199 if (index == 1 || index == 2) {
3200 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003201 return 0;
3202 }
3203
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003204 if (index == 3 || index == 4) {
3205 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003206 return 0;
3207 }
3208
Guenter Roeckf73cf632013-03-18 09:22:50 -07003209 return attr->mode;
3210}
3211
3212/*
3213 * nct6775_other_is_visible uses the index into the following array
3214 * to determine if attributes should be created or not.
3215 * Any change in order or content must be matched.
3216 */
3217static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003218 &dev_attr_cpu0_vid.attr, /* 0 */
3219 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3220 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3221 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3222 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3223 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003224
3225 NULL
3226};
3227
3228static const struct attribute_group nct6775_group_other = {
3229 .attrs = nct6775_attributes_other,
3230 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003231};
3232
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003233static inline void nct6775_init_device(struct nct6775_data *data)
3234{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003235 int i;
3236 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003237
3238 /* Start monitoring if needed */
3239 if (data->REG_CONFIG) {
3240 tmp = nct6775_read_value(data, data->REG_CONFIG);
3241 if (!(tmp & 0x01))
3242 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3243 }
3244
Guenter Roeckaa136e52012-12-04 03:26:05 -08003245 /* Enable temperature sensors if needed */
3246 for (i = 0; i < NUM_TEMP; i++) {
3247 if (!(data->have_temp & (1 << i)))
3248 continue;
3249 if (!data->reg_temp_config[i])
3250 continue;
3251 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3252 if (tmp & 0x01)
3253 nct6775_write_value(data, data->reg_temp_config[i],
3254 tmp & 0xfe);
3255 }
3256
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003257 /* Enable VBAT monitoring if needed */
3258 tmp = nct6775_read_value(data, data->REG_VBAT);
3259 if (!(tmp & 0x01))
3260 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003261
3262 diode = nct6775_read_value(data, data->REG_DIODE);
3263
3264 for (i = 0; i < data->temp_fixed_num; i++) {
3265 if (!(data->have_temp_fixed & (1 << i)))
3266 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003267 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3268 data->temp_type[i]
3269 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003270 else /* thermistor */
3271 data->temp_type[i] = 4;
3272 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003273}
3274
Guenter Roeckf73cf632013-03-18 09:22:50 -07003275static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003276nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003277{
David Bartley578ab5f2013-06-24 22:28:28 -07003278 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3279 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003280 int sioreg = data->sioreg;
3281 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003282
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003283 /* Store SIO_REG_ENABLE for use during resume */
3284 superio_select(sioreg, NCT6775_LD_HWM);
3285 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3286
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003287 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3288 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003289 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003290
3291 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003292 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003293
3294 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003295 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003296 fan4min = false;
3297 fan5pin = false;
3298 fan6pin = false;
3299 pwm4pin = false;
3300 pwm5pin = false;
3301 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003302 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003303 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003304 const char *board_vendor, *board_name;
3305
3306 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3307 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3308
3309 if (board_name && board_vendor &&
3310 !strcmp(board_vendor, "ASRock")) {
3311 /*
3312 * Auxiliary fan monitoring is not enabled on ASRock
3313 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3314 * Observed with BIOS version 2.00.
3315 */
3316 if (!strcmp(board_name, "Z77 Pro4-M")) {
3317 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3318 data->sio_reg_enable |= 0xe0;
3319 superio_outb(sioreg, SIO_REG_ENABLE,
3320 data->sio_reg_enable);
3321 }
3322 }
3323 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003324
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003325 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003326 fan3pin = gpok;
3327 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003328 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003329
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003330 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003331 fan4pin = gpok;
3332 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003333 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003334
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003335 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003336 fan5pin = gpok;
3337 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003338 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003339
3340 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003341 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003342 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003343 pwm4pin = false;
3344 pwm5pin = false;
3345 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003346 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003347 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003348 fan3pin = !(regval & 0x80);
3349 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003350
3351 fan4pin = false;
3352 fan4min = false;
3353 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003354 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003355 pwm4pin = false;
3356 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003357 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003358 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003359 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003360
3361 fan3pin = !(regval & (1 << 5));
3362 fan4pin = !(regval & (1 << 6));
3363 fan5pin = !(regval & (1 << 7));
3364
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003365 pwm3pin = !(regval & (1 << 0));
3366 pwm4pin = !(regval & (1 << 1));
3367 pwm5pin = !(regval & (1 << 2));
3368
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003369 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003370
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003371 if (data->kind == nct6791 || data->kind == nct6792 ||
3372 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003373 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003374 fan6pin = (regval & (1 << 1));
3375 pwm6pin = (regval & (1 << 0));
3376 } else { /* NCT6779D */
3377 fan6pin = false;
3378 pwm6pin = false;
3379 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003380 }
3381
David Bartley578ab5f2013-06-24 22:28:28 -07003382 /* fan 1 and 2 (0x03) are always present */
3383 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3384 (fan5pin << 4) | (fan6pin << 5);
3385 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3386 (fan5pin << 4);
3387 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3388 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003389}
3390
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003391static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3392 int *available, int *mask)
3393{
3394 int i;
3395 u8 src;
3396
3397 for (i = 0; i < data->pwm_num && *available; i++) {
3398 int index;
3399
3400 if (!regp[i])
3401 continue;
3402 src = nct6775_read_value(data, regp[i]);
3403 src &= 0x1f;
3404 if (!src || (*mask & (1 << src)))
3405 continue;
3406 if (src >= data->temp_label_num ||
3407 !strlen(data->temp_label[src]))
3408 continue;
3409
3410 index = __ffs(*available);
3411 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3412 *available &= ~(1 << index);
3413 *mask |= 1 << src;
3414 }
3415}
3416
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003417static int nct6775_probe(struct platform_device *pdev)
3418{
3419 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003420 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003421 struct nct6775_data *data;
3422 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003423 int i, s, err = 0;
3424 int src, mask, available;
3425 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003426 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003427 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003428 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003429 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003430 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003431 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003432 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003433
3434 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3435 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3436 DRVNAME))
3437 return -EBUSY;
3438
3439 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3440 GFP_KERNEL);
3441 if (!data)
3442 return -ENOMEM;
3443
3444 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003445 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003446 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003447 mutex_init(&data->update_lock);
3448 data->name = nct6775_device_names[data->kind];
3449 data->bank = 0xff; /* Force initial bank selection */
3450 platform_set_drvdata(pdev, data);
3451
3452 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003453 case nct6106:
3454 data->in_num = 9;
3455 data->pwm_num = 3;
3456 data->auto_pwm_num = 4;
3457 data->temp_fixed_num = 3;
3458 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003459 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003460
3461 data->fan_from_reg = fan_from_reg13;
3462 data->fan_from_reg_min = fan_from_reg13;
3463
3464 data->temp_label = nct6776_temp_label;
3465 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3466
3467 data->REG_VBAT = NCT6106_REG_VBAT;
3468 data->REG_DIODE = NCT6106_REG_DIODE;
3469 data->DIODE_MASK = NCT6106_DIODE_MASK;
3470 data->REG_VIN = NCT6106_REG_IN;
3471 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3472 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3473 data->REG_TARGET = NCT6106_REG_TARGET;
3474 data->REG_FAN = NCT6106_REG_FAN;
3475 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3476 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3477 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3478 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3479 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3480 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3481 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3482 data->REG_PWM[0] = NCT6106_REG_PWM;
3483 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3484 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3485 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3486 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3487 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3488 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3489 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3490 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3491 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3492 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3493 data->REG_CRITICAL_TEMP_TOLERANCE
3494 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3495 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3496 data->CRITICAL_PWM_ENABLE_MASK
3497 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3498 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3499 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3500 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3501 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3502 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3503 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3504 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3505 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3506 data->REG_ALARM = NCT6106_REG_ALARM;
3507 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003508 data->REG_BEEP = NCT6106_REG_BEEP;
3509 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003510
3511 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003512 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003513 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003514 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003515 reg_temp_over = NCT6106_REG_TEMP_OVER;
3516 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3517 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3518 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3519 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003520 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3521 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003522
3523 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003524 case nct6775:
3525 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003526 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003527 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003528 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003529 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003530 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003531 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003532
3533 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003534 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003535
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003536 data->fan_from_reg = fan_from_reg16;
3537 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003538 data->target_temp_mask = 0x7f;
3539 data->tolerance_mask = 0x0f;
3540 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003541
Guenter Roeckaa136e52012-12-04 03:26:05 -08003542 data->temp_label = nct6775_temp_label;
3543 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3544
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003545 data->REG_CONFIG = NCT6775_REG_CONFIG;
3546 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003547 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003548 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003549 data->REG_VIN = NCT6775_REG_IN;
3550 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3551 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003552 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003553 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003554 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003555 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003556 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003557 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003558 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3559 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3560 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003561 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003562 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3563 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3564 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3565 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003566 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003567 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3568 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3569 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003570 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3571 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3572 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3573 data->REG_CRITICAL_TEMP_TOLERANCE
3574 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003575 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3576 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003577 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003578 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3579 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3580 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3581 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003582 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003583 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003584
3585 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003586 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003587 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003588 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003589 reg_temp_over = NCT6775_REG_TEMP_OVER;
3590 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3591 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3592 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3593 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3594
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003595 break;
3596 case nct6776:
3597 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003598 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003599 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003600 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003601 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003602 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003603 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003604
3605 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003606 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003607
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003608 data->fan_from_reg = fan_from_reg13;
3609 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003610 data->target_temp_mask = 0xff;
3611 data->tolerance_mask = 0x07;
3612 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003613
Guenter Roeckaa136e52012-12-04 03:26:05 -08003614 data->temp_label = nct6776_temp_label;
3615 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3616
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003617 data->REG_CONFIG = NCT6775_REG_CONFIG;
3618 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003619 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003620 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003621 data->REG_VIN = NCT6775_REG_IN;
3622 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3623 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003624 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003625 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003626 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003627 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003628 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003629 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003630 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003631 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3632 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003633 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003634 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003635 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3636 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003637 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3638 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003639 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3640 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3641 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003642 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3643 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3644 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3645 data->REG_CRITICAL_TEMP_TOLERANCE
3646 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003647 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3648 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003649 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003650 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3651 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3652 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3653 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003654 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003655 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003656
3657 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003658 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003659 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003660 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003661 reg_temp_over = NCT6775_REG_TEMP_OVER;
3662 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3663 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3664 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3665 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3666
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003667 break;
3668 case nct6779:
3669 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003670 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003671 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003672 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003673 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003674 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003675 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003676
3677 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003678 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003679
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003680 data->fan_from_reg = fan_from_reg13;
3681 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003682 data->target_temp_mask = 0xff;
3683 data->tolerance_mask = 0x07;
3684 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003685
Guenter Roeckaa136e52012-12-04 03:26:05 -08003686 data->temp_label = nct6779_temp_label;
Guenter Roeck9a383712015-08-29 15:29:25 -07003687 data->temp_label_num = NCT6779_NUM_LABELS;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003688
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003689 data->REG_CONFIG = NCT6775_REG_CONFIG;
3690 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003691 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003692 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003693 data->REG_VIN = NCT6779_REG_IN;
3694 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3695 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003696 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003697 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003698 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003699 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003700 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003701 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003702 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003703 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3704 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003705 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003706 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003707 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3708 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003709 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3710 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003711 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3712 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3713 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003714 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3715 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3716 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3717 data->REG_CRITICAL_TEMP_TOLERANCE
3718 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003719 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3720 data->CRITICAL_PWM_ENABLE_MASK
3721 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3722 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003723 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3724 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003725 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003726 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3727 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3728 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3729 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003730 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003731 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003732
3733 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003734 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003735 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003736 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003737 reg_temp_over = NCT6779_REG_TEMP_OVER;
3738 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3739 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3740 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3741 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3742
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003743 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003744 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003745 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003746 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003747 data->in_num = 15;
3748 data->pwm_num = 6;
3749 data->auto_pwm_num = 4;
3750 data->has_fan_div = false;
3751 data->temp_fixed_num = 6;
3752 data->num_temp_alarms = 2;
3753 data->num_temp_beeps = 2;
3754
3755 data->ALARM_BITS = NCT6791_ALARM_BITS;
3756 data->BEEP_BITS = NCT6779_BEEP_BITS;
3757
3758 data->fan_from_reg = fan_from_reg13;
3759 data->fan_from_reg_min = fan_from_reg13;
3760 data->target_temp_mask = 0xff;
3761 data->tolerance_mask = 0x07;
3762 data->speed_tolerance_limit = 63;
3763
Guenter Roeck50224f42015-10-30 07:52:39 -07003764 switch (data->kind) {
3765 default:
3766 case nct6791:
3767 data->temp_label = nct6779_temp_label;
3768 break;
3769 case nct6792:
3770 data->temp_label = nct6792_temp_label;
3771 break;
3772 case nct6793:
3773 data->temp_label = nct6793_temp_label;
3774 break;
3775 }
Guenter Roeck9a383712015-08-29 15:29:25 -07003776 data->temp_label_num = NCT6791_NUM_LABELS;
David Bartley578ab5f2013-06-24 22:28:28 -07003777
3778 data->REG_CONFIG = NCT6775_REG_CONFIG;
3779 data->REG_VBAT = NCT6775_REG_VBAT;
3780 data->REG_DIODE = NCT6775_REG_DIODE;
3781 data->DIODE_MASK = NCT6775_DIODE_MASK;
3782 data->REG_VIN = NCT6779_REG_IN;
3783 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3784 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3785 data->REG_TARGET = NCT6775_REG_TARGET;
3786 data->REG_FAN = NCT6779_REG_FAN;
3787 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3788 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3789 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3790 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3791 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003792 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3793 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003794 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3795 data->REG_PWM[0] = NCT6775_REG_PWM;
3796 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3797 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003798 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3799 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003800 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3801 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3802 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3803 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3804 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3805 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3806 data->REG_CRITICAL_TEMP_TOLERANCE
3807 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3808 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3809 data->CRITICAL_PWM_ENABLE_MASK
3810 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3811 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3812 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3813 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3814 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003815 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3816 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3817 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3818 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003819 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003820 if (data->kind == nct6791)
3821 data->REG_BEEP = NCT6776_REG_BEEP;
3822 else
3823 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003824
3825 reg_temp = NCT6779_REG_TEMP;
3826 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003827 if (data->kind == nct6791) {
3828 reg_temp_mon = NCT6779_REG_TEMP_MON;
3829 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3830 } else {
3831 reg_temp_mon = NCT6792_REG_TEMP_MON;
3832 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3833 }
David Bartley578ab5f2013-06-24 22:28:28 -07003834 reg_temp_over = NCT6779_REG_TEMP_OVER;
3835 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3836 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3837 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3838 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3839
3840 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003841 default:
3842 return -ENODEV;
3843 }
3844 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003845 data->have_temp = 0;
3846
3847 /*
3848 * On some boards, not all available temperature sources are monitored,
3849 * even though some of the monitoring registers are unused.
3850 * Get list of unused monitoring registers, then detect if any fan
3851 * controls are configured to use unmonitored temperature sources.
3852 * If so, assign the unmonitored temperature sources to available
3853 * monitoring registers.
3854 */
3855 mask = 0;
3856 available = 0;
3857 for (i = 0; i < num_reg_temp; i++) {
3858 if (reg_temp[i] == 0)
3859 continue;
3860
3861 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3862 if (!src || (mask & (1 << src)))
3863 available |= 1 << i;
3864
3865 mask |= 1 << src;
3866 }
3867
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003868 /*
3869 * Now find unmonitored temperature registers and enable monitoring
3870 * if additional monitoring registers are available.
3871 */
3872 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3873 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3874
Guenter Roeckaa136e52012-12-04 03:26:05 -08003875 mask = 0;
3876 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3877 for (i = 0; i < num_reg_temp; i++) {
3878 if (reg_temp[i] == 0)
3879 continue;
3880
3881 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3882 if (!src || (mask & (1 << src)))
3883 continue;
3884
3885 if (src >= data->temp_label_num ||
3886 !strlen(data->temp_label[src])) {
3887 dev_info(dev,
3888 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3889 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3890 continue;
3891 }
3892
3893 mask |= 1 << src;
3894
3895 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3896 if (src <= data->temp_fixed_num) {
3897 data->have_temp |= 1 << (src - 1);
3898 data->have_temp_fixed |= 1 << (src - 1);
3899 data->reg_temp[0][src - 1] = reg_temp[i];
3900 data->reg_temp[1][src - 1] = reg_temp_over[i];
3901 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003902 if (reg_temp_crit_h && reg_temp_crit_h[i])
3903 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3904 else if (reg_temp_crit[src - 1])
3905 data->reg_temp[3][src - 1]
3906 = reg_temp_crit[src - 1];
3907 if (reg_temp_crit_l && reg_temp_crit_l[i])
3908 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003909 data->reg_temp_config[src - 1] = reg_temp_config[i];
3910 data->temp_src[src - 1] = src;
3911 continue;
3912 }
3913
3914 if (s >= NUM_TEMP)
3915 continue;
3916
3917 /* Use dynamic index for other sources */
3918 data->have_temp |= 1 << s;
3919 data->reg_temp[0][s] = reg_temp[i];
3920 data->reg_temp[1][s] = reg_temp_over[i];
3921 data->reg_temp[2][s] = reg_temp_hyst[i];
3922 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003923 if (reg_temp_crit_h && reg_temp_crit_h[i])
3924 data->reg_temp[3][s] = reg_temp_crit_h[i];
3925 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003926 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003927 if (reg_temp_crit_l && reg_temp_crit_l[i])
3928 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003929
3930 data->temp_src[s] = src;
3931 s++;
3932 }
3933
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003934 /*
3935 * Repeat with temperatures used for fan control.
3936 * This set of registers does not support limits.
3937 */
3938 for (i = 0; i < num_reg_temp_mon; i++) {
3939 if (reg_temp_mon[i] == 0)
3940 continue;
3941
3942 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3943 if (!src || (mask & (1 << src)))
3944 continue;
3945
3946 if (src >= data->temp_label_num ||
3947 !strlen(data->temp_label[src])) {
3948 dev_info(dev,
3949 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3950 src, i, data->REG_TEMP_SEL[i],
3951 reg_temp_mon[i]);
3952 continue;
3953 }
3954
3955 mask |= 1 << src;
3956
3957 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3958 if (src <= data->temp_fixed_num) {
3959 if (data->have_temp & (1 << (src - 1)))
3960 continue;
3961 data->have_temp |= 1 << (src - 1);
3962 data->have_temp_fixed |= 1 << (src - 1);
3963 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3964 data->temp_src[src - 1] = src;
3965 continue;
3966 }
3967
3968 if (s >= NUM_TEMP)
3969 continue;
3970
3971 /* Use dynamic index for other sources */
3972 data->have_temp |= 1 << s;
3973 data->reg_temp[0][s] = reg_temp_mon[i];
3974 data->temp_src[s] = src;
3975 s++;
3976 }
3977
Guenter Roeckaa136e52012-12-04 03:26:05 -08003978#ifdef USE_ALTERNATE
3979 /*
3980 * Go through the list of alternate temp registers and enable
3981 * if possible.
3982 * The temperature is already monitored if the respective bit in <mask>
3983 * is set.
3984 */
3985 for (i = 0; i < data->temp_label_num - 1; i++) {
3986 if (!reg_temp_alternate[i])
3987 continue;
3988 if (mask & (1 << (i + 1)))
3989 continue;
3990 if (i < data->temp_fixed_num) {
3991 if (data->have_temp & (1 << i))
3992 continue;
3993 data->have_temp |= 1 << i;
3994 data->have_temp_fixed |= 1 << i;
3995 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003996 if (i < num_reg_temp) {
3997 data->reg_temp[1][i] = reg_temp_over[i];
3998 data->reg_temp[2][i] = reg_temp_hyst[i];
3999 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004000 data->temp_src[i] = i + 1;
4001 continue;
4002 }
4003
4004 if (s >= NUM_TEMP) /* Abort if no more space */
4005 break;
4006
4007 data->have_temp |= 1 << s;
4008 data->reg_temp[0][s] = reg_temp_alternate[i];
4009 data->temp_src[s] = i + 1;
4010 s++;
4011 }
4012#endif /* USE_ALTERNATE */
4013
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004014 /* Initialize the chip */
4015 nct6775_init_device(data);
4016
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004017 err = superio_enter(sio_data->sioreg);
4018 if (err)
4019 return err;
4020
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004021 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4022 switch (data->kind) {
4023 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004024 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004025 break;
4026 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004027 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004028 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004029 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004030 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004031 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004032 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004033 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004034 break;
4035 }
4036
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004037 /*
4038 * Read VID value
4039 * We can get the VID input values directly at logical device D 0xe3.
4040 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004041 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004042 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4043 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4044 data->vrm = vid_which_vrm();
4045 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004046
4047 if (fan_debounce) {
4048 u8 tmp;
4049
4050 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4051 tmp = superio_inb(sio_data->sioreg,
4052 NCT6775_REG_CR_FAN_DEBOUNCE);
4053 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004054 case nct6106:
4055 tmp |= 0xe0;
4056 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004057 case nct6775:
4058 tmp |= 0x1e;
4059 break;
4060 case nct6776:
4061 case nct6779:
4062 tmp |= 0x3e;
4063 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004064 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004065 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004066 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07004067 tmp |= 0x7e;
4068 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004069 }
4070 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4071 tmp);
4072 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4073 data->name);
4074 }
4075
Guenter Roeckdf612d52013-07-08 13:15:04 -07004076 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004077
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004078 superio_exit(sio_data->sioreg);
4079
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004080 /* Read fan clock dividers immediately */
4081 nct6775_init_fan_common(dev, data);
4082
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004083 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004084 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4085 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004086 if (IS_ERR(group))
4087 return PTR_ERR(group);
4088
Axel Lin55bdee62014-07-24 08:59:34 +08004089 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004090
Guenter Roeckf73cf632013-03-18 09:22:50 -07004091 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4092 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004093 if (IS_ERR(group))
4094 return PTR_ERR(group);
4095
Axel Lin55bdee62014-07-24 08:59:34 +08004096 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004097
Guenter Roeckf73cf632013-03-18 09:22:50 -07004098 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4099 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004100 if (IS_ERR(group))
4101 return PTR_ERR(group);
4102
Axel Lin55bdee62014-07-24 08:59:34 +08004103 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004104
Guenter Roeckf73cf632013-03-18 09:22:50 -07004105 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4106 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004107 if (IS_ERR(group))
4108 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004109
Axel Lin55bdee62014-07-24 08:59:34 +08004110 data->groups[num_attr_groups++] = group;
4111 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004112
Guenter Roecka150d952013-07-11 22:55:22 -07004113 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4114 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004115 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004116}
4117
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004118static void nct6791_enable_io_mapping(int sioaddr)
4119{
4120 int val;
4121
4122 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4123 if (val & 0x10) {
4124 pr_info("Enabling hardware monitor logical device mappings.\n");
4125 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4126 val & ~0x10);
4127 }
4128}
4129
Guenter Roeck48e93182015-02-07 08:48:49 -08004130static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004131{
4132 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004133
4134 mutex_lock(&data->update_lock);
4135 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004136 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004137 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4138 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4139 }
4140 mutex_unlock(&data->update_lock);
4141
4142 return 0;
4143}
4144
Guenter Roeck48e93182015-02-07 08:48:49 -08004145static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004146{
4147 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004148 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004149 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004150 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004151
4152 mutex_lock(&data->update_lock);
4153 data->bank = 0xff; /* Force initial bank selection */
4154
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004155 err = superio_enter(sioreg);
4156 if (err)
4157 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004158
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004159 superio_select(sioreg, NCT6775_LD_HWM);
4160 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4161 if (reg != data->sio_reg_enable)
4162 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4163
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004164 if (data->kind == nct6791 || data->kind == nct6792 ||
4165 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004166 nct6791_enable_io_mapping(sioreg);
4167
4168 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004169
Guenter Roeck84d19d92012-12-04 08:01:39 -08004170 /* Restore limits */
4171 for (i = 0; i < data->in_num; i++) {
4172 if (!(data->have_in & (1 << i)))
4173 continue;
4174
4175 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4176 data->in[i][1]);
4177 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4178 data->in[i][2]);
4179 }
4180
Guenter Roeckc409fd42013-04-09 05:04:00 -07004181 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004182 if (!(data->has_fan_min & (1 << i)))
4183 continue;
4184
4185 nct6775_write_value(data, data->REG_FAN_MIN[i],
4186 data->fan_min[i]);
4187 }
4188
4189 for (i = 0; i < NUM_TEMP; i++) {
4190 if (!(data->have_temp & (1 << i)))
4191 continue;
4192
Guenter Roeckc409fd42013-04-09 05:04:00 -07004193 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004194 if (data->reg_temp[j][i])
4195 nct6775_write_temp(data, data->reg_temp[j][i],
4196 data->temp[j][i]);
4197 }
4198
4199 /* Restore other settings */
4200 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004201 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004202 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4203 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4204 }
4205
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004206abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004207 /* Force re-reading all values */
4208 data->valid = false;
4209 mutex_unlock(&data->update_lock);
4210
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004211 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004212}
4213
Guenter Roeck48e93182015-02-07 08:48:49 -08004214static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004215
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004216static struct platform_driver nct6775_driver = {
4217 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004218 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004219 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004220 },
4221 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004222};
4223
4224/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004225static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004226{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004227 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004228 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004229 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230
4231 err = superio_enter(sioaddr);
4232 if (err)
4233 return err;
4234
4235 if (force_id)
4236 val = force_id;
4237 else
4238 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4239 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4240 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004241 case SIO_NCT6106_ID:
4242 sio_data->kind = nct6106;
4243 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004244 case SIO_NCT6775_ID:
4245 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004246 break;
4247 case SIO_NCT6776_ID:
4248 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004249 break;
4250 case SIO_NCT6779_ID:
4251 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004252 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004253 case SIO_NCT6791_ID:
4254 sio_data->kind = nct6791;
4255 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004256 case SIO_NCT6792_ID:
4257 sio_data->kind = nct6792;
4258 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004259 case SIO_NCT6793_ID:
4260 sio_data->kind = nct6793;
4261 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004262 default:
4263 if (val != 0xffff)
4264 pr_debug("unsupported chip ID: 0x%04x\n", val);
4265 superio_exit(sioaddr);
4266 return -ENODEV;
4267 }
4268
4269 /* We have a known chip, find the HWM I/O address */
4270 superio_select(sioaddr, NCT6775_LD_HWM);
4271 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4272 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004273 addr = val & IOREGION_ALIGNMENT;
4274 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004275 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4276 superio_exit(sioaddr);
4277 return -ENODEV;
4278 }
4279
4280 /* Activate logical device if needed */
4281 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4282 if (!(val & 0x01)) {
4283 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4284 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4285 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004286
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004287 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4288 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004289 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004290
4291 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004292 pr_info("Found %s or compatible chip at %#x:%#x\n",
4293 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004294 sio_data->sioreg = sioaddr;
4295
Guenter Roeck698a7c22013-04-05 07:35:25 -07004296 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004297}
4298
4299/*
4300 * when Super-I/O functions move to a separate file, the Super-I/O
4301 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004302 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004303 * must keep track of the device
4304 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004305static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004306
4307static int __init sensors_nct6775_init(void)
4308{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004309 int i, err;
4310 bool found = false;
4311 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004312 struct resource res;
4313 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004314 int sioaddr[2] = { 0x2e, 0x4e };
4315
4316 err = platform_driver_register(&nct6775_driver);
4317 if (err)
4318 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004319
4320 /*
4321 * initialize sio_data->kind and sio_data->sioreg.
4322 *
4323 * when Super-I/O functions move to a separate file, the Super-I/O
4324 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4325 * nct6775 hardware monitor, and call probe()
4326 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004327 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4328 address = nct6775_find(sioaddr[i], &sio_data);
4329 if (address <= 0)
4330 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004331
Guenter Roeck698a7c22013-04-05 07:35:25 -07004332 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004333
Guenter Roeck698a7c22013-04-05 07:35:25 -07004334 pdev[i] = platform_device_alloc(DRVNAME, address);
4335 if (!pdev[i]) {
4336 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004337 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004338 }
4339
4340 err = platform_device_add_data(pdev[i], &sio_data,
4341 sizeof(struct nct6775_sio_data));
4342 if (err)
4343 goto exit_device_put;
4344
4345 memset(&res, 0, sizeof(res));
4346 res.name = DRVNAME;
4347 res.start = address + IOREGION_OFFSET;
4348 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4349 res.flags = IORESOURCE_IO;
4350
4351 err = acpi_check_resource_conflict(&res);
4352 if (err) {
4353 platform_device_put(pdev[i]);
4354 pdev[i] = NULL;
4355 continue;
4356 }
4357
4358 err = platform_device_add_resources(pdev[i], &res, 1);
4359 if (err)
4360 goto exit_device_put;
4361
4362 /* platform_device_add calls probe() */
4363 err = platform_device_add(pdev[i]);
4364 if (err)
4365 goto exit_device_put;
4366 }
4367 if (!found) {
4368 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004369 goto exit_unregister;
4370 }
4371
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004372 return 0;
4373
4374exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004375 platform_device_put(pdev[i]);
4376exit_device_unregister:
4377 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004378 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004379 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004380 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004381exit_unregister:
4382 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004383 return err;
4384}
4385
4386static void __exit sensors_nct6775_exit(void)
4387{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004388 int i;
4389
4390 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4391 if (pdev[i])
4392 platform_device_unregister(pdev[i]);
4393 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004394 platform_driver_unregister(&nct6775_driver);
4395}
4396
4397MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004398MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004399MODULE_LICENSE("GPL");
4400
4401module_init(sensors_nct6775_init);
4402module_exit(sensors_nct6775_exit);