blob: 59ee01f3d022397e638dcecdb2cdd1ce497f6129 [file] [log] [blame]
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001/*
2 * nct6775 - Driver for the hardware monitoring functionality of
3 * Nuvoton NCT677x Super-I/O chips
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from w83627ehf driver
Jean Delvare7c81c60f2014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter 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 Roeck419220d2017-05-17 18:19:18 -070043 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
Guenter Roeck81820052018-02-21 13:09:39 -080044 * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
Guenter Roecke41da282018-09-18 20:48:29 -070045 * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3
Guenter Roeck05996822018-09-19 20:26:16 -070046 * (0xd451)
Guenter Roeck264142b2018-12-26 07:34:31 -080047 * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3
48 * (0xd429)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070049 *
50 * #temp lists the number of monitored temperature sources (first value) plus
51 * the number of directly connectable temperature sensors (second value).
52 */
53
54#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
55
56#include <linux/module.h>
57#include <linux/init.h>
58#include <linux/slab.h>
59#include <linux/jiffies.h>
60#include <linux/platform_device.h>
61#include <linux/hwmon.h>
62#include <linux/hwmon-sysfs.h>
63#include <linux/hwmon-vid.h>
64#include <linux/err.h>
65#include <linux/mutex.h>
66#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070067#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080068#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070069#include <linux/io.h>
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -050070#include <linux/nospec.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070071#include "lm75.h"
72
Guenter Roeckaa136e52012-12-04 03:26:05 -080073#define USE_ALTERNATE
74
Guenter Roeck419220d2017-05-17 18:19:18 -070075enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
Guenter Roeck05996822018-09-19 20:26:16 -070076 nct6795, nct6796, nct6797, nct6798 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070077
78/* used to set data->name = nct6775_device_names[data->sio_kind] */
79static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070080 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070081 "nct6775",
82 "nct6776",
83 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070084 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080085 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070086 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070087 "nct6795",
Guenter Roeck81820052018-02-21 13:09:39 -080088 "nct6796",
Guenter Roecke41da282018-09-18 20:48:29 -070089 "nct6797",
Guenter Roeck05996822018-09-19 20:26:16 -070090 "nct6798",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070091};
92
93static const char * const nct6775_sio_names[] __initconst = {
94 "NCT6106D",
95 "NCT6775F",
96 "NCT6776D/F",
97 "NCT6779D",
98 "NCT6791D",
99 "NCT6792D",
100 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -0700101 "NCT6795D",
Guenter Roeck81820052018-02-21 13:09:39 -0800102 "NCT6796D",
Guenter Roecke41da282018-09-18 20:48:29 -0700103 "NCT6797D",
Guenter Roeck05996822018-09-19 20:26:16 -0700104 "NCT6798D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700105};
106
107static unsigned short force_id;
108module_param(force_id, ushort, 0);
109MODULE_PARM_DESC(force_id, "Override the detected device ID");
110
Guenter Roeck47ece962012-12-04 07:59:32 -0800111static unsigned short fan_debounce;
112module_param(fan_debounce, ushort, 0);
113MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
114
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700115#define DRVNAME "nct6775"
116
117/*
118 * Super-I/O constants and functions
119 */
120
Guenter Roecka6bd5872012-12-04 03:13:34 -0800121#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700122#define NCT6775_LD_HWM 0x0b
123#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700124#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700125
126#define SIO_REG_LDSEL 0x07 /* Logical device select */
127#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
128#define SIO_REG_ENABLE 0x30 /* Logical device enable */
129#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
130
Guenter Roeck6c009502012-07-01 08:23:15 -0700131#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700132#define SIO_NCT6775_ID 0xb470
133#define SIO_NCT6776_ID 0xc330
134#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700135#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800136#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700137#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700138#define SIO_NCT6795_ID 0xd350
Guenter Roeck81820052018-02-21 13:09:39 -0800139#define SIO_NCT6796_ID 0xd420
Guenter Roecke41da282018-09-18 20:48:29 -0700140#define SIO_NCT6797_ID 0xd450
Guenter Roeck264142b2018-12-26 07:34:31 -0800141#define SIO_NCT6798_ID 0xd428
Guenter Roeck05996822018-09-19 20:26:16 -0700142#define SIO_ID_MASK 0xFFF8
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700143
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800144enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
145
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700146static inline void
147superio_outb(int ioreg, int reg, int val)
148{
149 outb(reg, ioreg);
150 outb(val, ioreg + 1);
151}
152
153static inline int
154superio_inb(int ioreg, int reg)
155{
156 outb(reg, ioreg);
157 return inb(ioreg + 1);
158}
159
160static inline void
161superio_select(int ioreg, int ld)
162{
163 outb(SIO_REG_LDSEL, ioreg);
164 outb(ld, ioreg + 1);
165}
166
167static inline int
168superio_enter(int ioreg)
169{
170 /*
171 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
172 */
173 if (!request_muxed_region(ioreg, 2, DRVNAME))
174 return -EBUSY;
175
176 outb(0x87, ioreg);
177 outb(0x87, ioreg);
178
179 return 0;
180}
181
182static inline void
183superio_exit(int ioreg)
184{
185 outb(0xaa, ioreg);
186 outb(0x02, ioreg);
187 outb(0x02, ioreg + 1);
188 release_region(ioreg, 2);
189}
190
191/*
192 * ISA constants
193 */
194
195#define IOREGION_ALIGNMENT (~7)
196#define IOREGION_OFFSET 5
197#define IOREGION_LENGTH 2
198#define ADDR_REG_OFFSET 0
199#define DATA_REG_OFFSET 1
200
201#define NCT6775_REG_BANK 0x4E
202#define NCT6775_REG_CONFIG 0x40
203
204/*
205 * Not currently used:
206 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
207 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
208 * REG_MAN_ID is at port 0x4f
209 * REG_CHIP_ID is at port 0x58
210 */
211
Guenter Roeckaa136e52012-12-04 03:26:05 -0800212#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
213#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
214
Guenter Roeck6c009502012-07-01 08:23:15 -0700215#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700216#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700217
Guenter Roeck81820052018-02-21 13:09:39 -0800218#define NUM_FAN 7
David Bartley578ab5f2013-06-24 22:28:28 -0700219
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700220/* Common and NCT6775 specific data */
221
222/* Voltage min/max registers for nr=7..14 are in bank 5 */
223
224static const u16 NCT6775_REG_IN_MAX[] = {
225 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
226 0x55c, 0x55e, 0x560, 0x562 };
227static const u16 NCT6775_REG_IN_MIN[] = {
228 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
229 0x55d, 0x55f, 0x561, 0x563 };
230static const u16 NCT6775_REG_IN[] = {
231 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
232};
233
234#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800235#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700236#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700237
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800238#define NCT6775_REG_FANDIV1 0x506
239#define NCT6775_REG_FANDIV2 0x507
240
Guenter Roeck47ece962012-12-04 07:59:32 -0800241#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
242
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700243static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
244
Guenter Roeck30846992013-06-24 22:21:59 -0700245/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700246
247static const s8 NCT6775_ALARM_BITS[] = {
248 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
249 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
250 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700251 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700252 -1, -1, -1, /* unused */
253 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
254 12, -1 }; /* intrusion0, intrusion1 */
255
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800256#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800257#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800258#define INTRUSION_ALARM_BASE 30
259
Guenter Roeck30846992013-06-24 22:21:59 -0700260static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
261
262/*
263 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
264 * 30..31 intrusion
265 */
266static const s8 NCT6775_BEEP_BITS[] = {
267 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
268 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
269 21, /* global beep enable */
270 6, 7, 11, 28, -1, /* fan1..fan5 */
271 -1, -1, -1, /* unused */
272 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
273 12, -1 }; /* intrusion0, intrusion1 */
274
275#define BEEP_ENABLE_BASE 15
276
Guenter Roecka6bd5872012-12-04 03:13:34 -0800277static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
278static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
279
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800280/* DC or PWM output fan configuration */
281static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
282static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
283
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800284/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800285
David Bartley578ab5f2013-06-24 22:28:28 -0700286static const u16 NCT6775_REG_TARGET[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800287 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
David Bartley578ab5f2013-06-24 22:28:28 -0700288static const u16 NCT6775_REG_FAN_MODE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800289 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800290static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800291 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800292static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800293 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800294static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800295 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
David Bartley578ab5f2013-06-24 22:28:28 -0700296static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800297 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800298static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
299static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
300
301static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800302 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
David Bartley578ab5f2013-06-24 22:28:28 -0700303static const u16 NCT6775_REG_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800304 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
David Bartley578ab5f2013-06-24 22:28:28 -0700305static const u16 NCT6775_REG_PWM_READ[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800306 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800307
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800308static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
309static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeckc7932792018-09-06 09:47:51 -0700310static const u16 NCT6775_REG_FAN_PULSES[NUM_FAN] = {
311 0x641, 0x642, 0x643, 0x644 };
312static const u16 NCT6775_FAN_PULSE_SHIFT[NUM_FAN] = { };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800313
Guenter Roeckaa136e52012-12-04 03:26:05 -0800314static const u16 NCT6775_REG_TEMP[] = {
315 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
316
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800317static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
318
Guenter Roeckaa136e52012-12-04 03:26:05 -0800319static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
320 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
321static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
322 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
323static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
324 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
325
326static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
327 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
328
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800329static const u16 NCT6775_REG_TEMP_SEL[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800330 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800331
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800332static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700333 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800334static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700335 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800336static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700337 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800338static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700339 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800340static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700341 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800342
Guenter Roeckaa136e52012-12-04 03:26:05 -0800343static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
344
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800345static const u16 NCT6775_REG_AUTO_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800346 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800347static const u16 NCT6775_REG_AUTO_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800348 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800349
350#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
351#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
352
353static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
354
355static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800356 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800357static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800358 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800359
Guenter Roeckaa136e52012-12-04 03:26:05 -0800360static const char *const nct6775_temp_label[] = {
361 "",
362 "SYSTIN",
363 "CPUTIN",
364 "AUXTIN",
365 "AMD SB-TSI",
366 "PECI Agent 0",
367 "PECI Agent 1",
368 "PECI Agent 2",
369 "PECI Agent 3",
370 "PECI Agent 4",
371 "PECI Agent 5",
372 "PECI Agent 6",
373 "PECI Agent 7",
374 "PCH_CHIP_CPU_MAX_TEMP",
375 "PCH_CHIP_TEMP",
376 "PCH_CPU_TEMP",
377 "PCH_MCH_TEMP",
378 "PCH_DIM0_TEMP",
379 "PCH_DIM1_TEMP",
380 "PCH_DIM2_TEMP",
381 "PCH_DIM3_TEMP"
382};
383
Guenter Roeckcc66b302017-05-17 18:05:06 -0700384#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700385#define NCT6775_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800386
Guenter Roeckcc66b302017-05-17 18:05:06 -0700387static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
388 [13] = 0x661,
389 [14] = 0x662,
390 [15] = 0x664,
391};
392
393static const u16 NCT6775_REG_TEMP_CRIT[32] = {
394 [4] = 0xa00,
395 [5] = 0xa01,
396 [6] = 0xa02,
397 [7] = 0xa03,
398 [8] = 0xa04,
399 [9] = 0xa05,
400 [10] = 0xa06,
401 [11] = 0xa07
402};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800403
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700404/* NCT6776 specific data */
405
Guenter Roeck728d2942015-08-31 16:13:47 -0700406/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
407#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
408#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
409
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700410static const s8 NCT6776_ALARM_BITS[] = {
411 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
412 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
413 -1, /* unused */
414 6, 7, 11, 10, 23, /* fan1..fan5 */
415 -1, -1, -1, /* unused */
416 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
417 12, 9 }; /* intrusion0, intrusion1 */
418
Guenter Roeck30846992013-06-24 22:21:59 -0700419static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
420
421static const s8 NCT6776_BEEP_BITS[] = {
422 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
423 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
424 24, /* global beep enable */
425 25, 26, 27, 28, 29, /* fan1..fan5 */
426 -1, -1, -1, /* unused */
427 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
428 30, 31 }; /* intrusion0, intrusion1 */
429
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800430static const u16 NCT6776_REG_TOLERANCE_H[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800431 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800432
David Bartley578ab5f2013-06-24 22:28:28 -0700433static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
434static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800435
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800436static const u16 NCT6776_REG_FAN_MIN[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800437 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
Guenter Roeckc7932792018-09-06 09:47:51 -0700438static const u16 NCT6776_REG_FAN_PULSES[NUM_FAN] = {
439 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800440
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800441static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700442 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800443
Guenter Roeckaa136e52012-12-04 03:26:05 -0800444static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
445 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
446
447static const char *const nct6776_temp_label[] = {
448 "",
449 "SYSTIN",
450 "CPUTIN",
451 "AUXTIN",
452 "SMBUSMASTER 0",
453 "SMBUSMASTER 1",
454 "SMBUSMASTER 2",
455 "SMBUSMASTER 3",
456 "SMBUSMASTER 4",
457 "SMBUSMASTER 5",
458 "SMBUSMASTER 6",
459 "SMBUSMASTER 7",
460 "PECI Agent 0",
461 "PECI Agent 1",
462 "PCH_CHIP_CPU_MAX_TEMP",
463 "PCH_CHIP_TEMP",
464 "PCH_CPU_TEMP",
465 "PCH_MCH_TEMP",
466 "PCH_DIM0_TEMP",
467 "PCH_DIM1_TEMP",
468 "PCH_DIM2_TEMP",
469 "PCH_DIM3_TEMP",
470 "BYTE_TEMP"
471};
472
Guenter Roeckcc66b302017-05-17 18:05:06 -0700473#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700474#define NCT6776_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800475
Guenter Roeckcc66b302017-05-17 18:05:06 -0700476static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
477 [14] = 0x401,
478 [15] = 0x402,
479 [16] = 0x404,
480};
481
482static const u16 NCT6776_REG_TEMP_CRIT[32] = {
483 [11] = 0x709,
484 [12] = 0x70a,
485};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800486
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700487/* NCT6779 specific data */
488
489static const u16 NCT6779_REG_IN[] = {
490 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
491 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
492
493static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
494 0x459, 0x45A, 0x45B, 0x568 };
495
496static const s8 NCT6779_ALARM_BITS[] = {
497 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
498 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
499 -1, /* unused */
500 6, 7, 11, 10, 23, /* fan1..fan5 */
501 -1, -1, -1, /* unused */
502 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
503 12, 9 }; /* intrusion0, intrusion1 */
504
Guenter Roeck30846992013-06-24 22:21:59 -0700505static const s8 NCT6779_BEEP_BITS[] = {
506 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
507 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
508 24, /* global beep enable */
509 25, 26, 27, 28, 29, /* fan1..fan5 */
510 -1, -1, -1, /* unused */
511 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
512 30, 31 }; /* intrusion0, intrusion1 */
513
David Bartley578ab5f2013-06-24 22:28:28 -0700514static const u16 NCT6779_REG_FAN[] = {
Guenter Roeck55066352018-09-17 05:23:58 -0700515 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
Guenter Roeckc7932792018-09-06 09:47:51 -0700516static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
Guenter Roecke41da282018-09-18 20:48:29 -0700517 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800518
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800519static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800520 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700521#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800522static const u16 NCT6779_REG_CRITICAL_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800523 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800524
Guenter Roeckaa136e52012-12-04 03:26:05 -0800525static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800526static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800527static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
528 0x18, 0x152 };
529static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
530 0x3a, 0x153 };
531static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
532 0x39, 0x155 };
533
534static const u16 NCT6779_REG_TEMP_OFFSET[] = {
535 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
536
537static const char *const nct6779_temp_label[] = {
538 "",
539 "SYSTIN",
540 "CPUTIN",
541 "AUXTIN0",
542 "AUXTIN1",
543 "AUXTIN2",
544 "AUXTIN3",
545 "",
546 "SMBUSMASTER 0",
547 "SMBUSMASTER 1",
548 "SMBUSMASTER 2",
549 "SMBUSMASTER 3",
550 "SMBUSMASTER 4",
551 "SMBUSMASTER 5",
552 "SMBUSMASTER 6",
553 "SMBUSMASTER 7",
554 "PECI Agent 0",
555 "PECI Agent 1",
556 "PCH_CHIP_CPU_MAX_TEMP",
557 "PCH_CHIP_TEMP",
558 "PCH_CPU_TEMP",
559 "PCH_MCH_TEMP",
560 "PCH_DIM0_TEMP",
561 "PCH_DIM1_TEMP",
562 "PCH_DIM2_TEMP",
563 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700564 "BYTE_TEMP",
565 "",
566 "",
567 "",
568 "",
569 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800570};
571
Guenter Roeckcc66b302017-05-17 18:05:06 -0700572#define NCT6779_TEMP_MASK 0x07ffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700573#define NCT6779_VIRT_TEMP_MASK 0x00000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700574#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700575#define NCT6791_VIRT_TEMP_MASK 0x80000000
Guenter Roeck9a383712015-08-29 15:29:25 -0700576
Guenter Roeckcc66b302017-05-17 18:05:06 -0700577static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800578 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
579 0, 0, 0, 0, 0, 0, 0, 0,
580 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
581 0x408, 0 };
582
Guenter Roeckcc66b302017-05-17 18:05:06 -0700583static const u16 NCT6779_REG_TEMP_CRIT[32] = {
584 [15] = 0x709,
585 [16] = 0x70a,
586};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800587
David Bartley578ab5f2013-06-24 22:28:28 -0700588/* NCT6791 specific data */
589
590#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
591
Guenter Roecke2617262018-02-21 13:09:36 -0800592static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
593static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
594static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
595static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
596static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
597static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800598
David Bartley578ab5f2013-06-24 22:28:28 -0700599static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
600 0x459, 0x45A, 0x45B, 0x568, 0x45D };
601
602static const s8 NCT6791_ALARM_BITS[] = {
603 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
604 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
605 -1, /* unused */
606 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
607 -1, -1, /* unused */
608 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
609 12, 9 }; /* intrusion0, intrusion1 */
610
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700611/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800612
613static const u16 NCT6792_REG_TEMP_MON[] = {
614 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
615static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
616 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700617
Guenter Roeck50224f42015-10-30 07:52:39 -0700618static const char *const nct6792_temp_label[] = {
619 "",
620 "SYSTIN",
621 "CPUTIN",
622 "AUXTIN0",
623 "AUXTIN1",
624 "AUXTIN2",
625 "AUXTIN3",
626 "",
627 "SMBUSMASTER 0",
628 "SMBUSMASTER 1",
629 "SMBUSMASTER 2",
630 "SMBUSMASTER 3",
631 "SMBUSMASTER 4",
632 "SMBUSMASTER 5",
633 "SMBUSMASTER 6",
634 "SMBUSMASTER 7",
635 "PECI Agent 0",
636 "PECI Agent 1",
637 "PCH_CHIP_CPU_MAX_TEMP",
638 "PCH_CHIP_TEMP",
639 "PCH_CPU_TEMP",
640 "PCH_MCH_TEMP",
641 "PCH_DIM0_TEMP",
642 "PCH_DIM1_TEMP",
643 "PCH_DIM2_TEMP",
644 "PCH_DIM3_TEMP",
645 "BYTE_TEMP",
646 "PECI Agent 0 Calibration",
647 "PECI Agent 1 Calibration",
648 "",
649 "",
650 "Virtual_TEMP"
651};
652
Guenter Roeckcc66b302017-05-17 18:05:06 -0700653#define NCT6792_TEMP_MASK 0x9fffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700654#define NCT6792_VIRT_TEMP_MASK 0x80000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700655
Guenter Roeck50224f42015-10-30 07:52:39 -0700656static const char *const nct6793_temp_label[] = {
657 "",
658 "SYSTIN",
659 "CPUTIN",
660 "AUXTIN0",
661 "AUXTIN1",
662 "AUXTIN2",
663 "AUXTIN3",
664 "",
665 "SMBUSMASTER 0",
666 "SMBUSMASTER 1",
667 "",
668 "",
669 "",
670 "",
671 "",
672 "",
673 "PECI Agent 0",
674 "PECI Agent 1",
675 "PCH_CHIP_CPU_MAX_TEMP",
676 "PCH_CHIP_TEMP",
677 "PCH_CPU_TEMP",
678 "PCH_MCH_TEMP",
679 "Agent0 Dimm0 ",
680 "Agent0 Dimm1",
681 "Agent1 Dimm0",
682 "Agent1 Dimm1",
683 "BYTE_TEMP0",
684 "BYTE_TEMP1",
685 "PECI Agent 0 Calibration",
686 "PECI Agent 1 Calibration",
687 "",
688 "Virtual_TEMP"
689};
690
Guenter Roeckcc66b302017-05-17 18:05:06 -0700691#define NCT6793_TEMP_MASK 0xbfff037e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700692#define NCT6793_VIRT_TEMP_MASK 0x80000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700693
Guenter Roeck419220d2017-05-17 18:19:18 -0700694static const char *const nct6795_temp_label[] = {
695 "",
696 "SYSTIN",
697 "CPUTIN",
698 "AUXTIN0",
699 "AUXTIN1",
700 "AUXTIN2",
701 "AUXTIN3",
702 "",
703 "SMBUSMASTER 0",
704 "SMBUSMASTER 1",
705 "SMBUSMASTER 2",
706 "SMBUSMASTER 3",
707 "SMBUSMASTER 4",
708 "SMBUSMASTER 5",
709 "SMBUSMASTER 6",
710 "SMBUSMASTER 7",
711 "PECI Agent 0",
712 "PECI Agent 1",
713 "PCH_CHIP_CPU_MAX_TEMP",
714 "PCH_CHIP_TEMP",
715 "PCH_CPU_TEMP",
716 "PCH_MCH_TEMP",
Guenter Roeck3be8c9d2018-09-19 21:52:49 -0700717 "Agent0 Dimm0",
718 "Agent0 Dimm1",
719 "Agent1 Dimm0",
720 "Agent1 Dimm1",
Guenter Roeck419220d2017-05-17 18:19:18 -0700721 "BYTE_TEMP0",
722 "BYTE_TEMP1",
723 "PECI Agent 0 Calibration",
724 "PECI Agent 1 Calibration",
725 "",
726 "Virtual_TEMP"
727};
728
729#define NCT6795_TEMP_MASK 0xbfffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700730#define NCT6795_VIRT_TEMP_MASK 0x80000000
Guenter Roeck419220d2017-05-17 18:19:18 -0700731
Guenter Roeck81820052018-02-21 13:09:39 -0800732static const char *const nct6796_temp_label[] = {
733 "",
734 "SYSTIN",
735 "CPUTIN",
736 "AUXTIN0",
737 "AUXTIN1",
738 "AUXTIN2",
739 "AUXTIN3",
740 "AUXTIN4",
741 "SMBUSMASTER 0",
742 "SMBUSMASTER 1",
Guenter Roeck37196ba2018-09-13 19:43:58 -0700743 "Virtual_TEMP",
744 "Virtual_TEMP",
Guenter Roeck81820052018-02-21 13:09:39 -0800745 "",
746 "",
747 "",
748 "",
749 "PECI Agent 0",
750 "PECI Agent 1",
751 "PCH_CHIP_CPU_MAX_TEMP",
752 "PCH_CHIP_TEMP",
753 "PCH_CPU_TEMP",
754 "PCH_MCH_TEMP",
Guenter Roeck3be8c9d2018-09-19 21:52:49 -0700755 "Agent0 Dimm0",
756 "Agent0 Dimm1",
757 "Agent1 Dimm0",
758 "Agent1 Dimm1",
Guenter Roeck81820052018-02-21 13:09:39 -0800759 "BYTE_TEMP0",
760 "BYTE_TEMP1",
761 "PECI Agent 0 Calibration",
762 "PECI Agent 1 Calibration",
763 "",
764 "Virtual_TEMP"
765};
766
Guenter Roeck37196ba2018-09-13 19:43:58 -0700767#define NCT6796_TEMP_MASK 0xbfff0ffe
768#define NCT6796_VIRT_TEMP_MASK 0x80000c00
Guenter Roeck81820052018-02-21 13:09:39 -0800769
Guenter Roeck05996822018-09-19 20:26:16 -0700770static const char *const nct6798_temp_label[] = {
771 "",
772 "SYSTIN",
773 "CPUTIN",
774 "AUXTIN0",
775 "AUXTIN1",
776 "AUXTIN2",
777 "AUXTIN3",
778 "AUXTIN4",
779 "SMBUSMASTER 0",
780 "SMBUSMASTER 1",
781 "Virtual_TEMP",
782 "Virtual_TEMP",
783 "",
784 "",
785 "",
786 "",
787 "PECI Agent 0",
788 "PECI Agent 1",
789 "PCH_CHIP_CPU_MAX_TEMP",
790 "PCH_CHIP_TEMP",
791 "PCH_CPU_TEMP",
792 "PCH_MCH_TEMP",
793 "Agent0 Dimm0",
794 "Agent0 Dimm1",
795 "Agent1 Dimm0",
796 "Agent1 Dimm1",
797 "BYTE_TEMP0",
798 "BYTE_TEMP1",
799 "",
800 "",
801 "",
802 "Virtual_TEMP"
803};
804
805#define NCT6798_TEMP_MASK 0x8fff0ffe
806#define NCT6798_VIRT_TEMP_MASK 0x80000c00
807
Guenter Roeck6c009502012-07-01 08:23:15 -0700808/* NCT6102D/NCT6106D specific data */
809
810#define NCT6106_REG_VBAT 0x318
811#define NCT6106_REG_DIODE 0x319
812#define NCT6106_DIODE_MASK 0x01
813
814static const u16 NCT6106_REG_IN_MAX[] = {
815 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
816static const u16 NCT6106_REG_IN_MIN[] = {
817 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
818static const u16 NCT6106_REG_IN[] = {
819 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
820
821static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800822static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700823static const u16 NCT6106_REG_TEMP_HYST[] = {
824 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
825static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700826 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
827static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
828 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
829static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
830 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700831static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
832static const u16 NCT6106_REG_TEMP_CONFIG[] = {
833 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
834
835static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
836static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
Guenter Roeckc7932792018-09-06 09:47:51 -0700837static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6 };
838static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700839
840static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
841static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
842static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
843static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
844static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
845static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
846static const u16 NCT6106_REG_TEMP_SOURCE[] = {
847 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
848
849static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
850static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
851 0x11b, 0x12b, 0x13b };
852
853static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
854#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
855static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
856
857static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
858static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
859static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
860static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
861static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
862static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
863
864static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
865
866static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
867static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
868static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
869static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
870static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
871static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
872
873static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
874static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
875
876static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
877 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
878
879static const s8 NCT6106_ALARM_BITS[] = {
880 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
881 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
882 -1, /* unused */
883 32, 33, 34, -1, -1, /* fan1..fan5 */
884 -1, -1, -1, /* unused */
885 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
886 48, -1 /* intrusion0, intrusion1 */
887};
888
Guenter Roeck30846992013-06-24 22:21:59 -0700889static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
890 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
891
892static const s8 NCT6106_BEEP_BITS[] = {
893 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
894 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
895 32, /* global beep enable */
896 24, 25, 26, 27, 28, /* fan1..fan5 */
897 -1, -1, -1, /* unused */
898 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
899 34, -1 /* intrusion0, intrusion1 */
900};
901
Guenter Roeckcc66b302017-05-17 18:05:06 -0700902static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
903 [14] = 0x51,
904 [15] = 0x52,
905 [16] = 0x54,
906};
Guenter Roeck6c009502012-07-01 08:23:15 -0700907
Guenter Roeckcc66b302017-05-17 18:05:06 -0700908static const u16 NCT6106_REG_TEMP_CRIT[32] = {
909 [11] = 0x204,
910 [12] = 0x205,
911};
Guenter Roeck6c009502012-07-01 08:23:15 -0700912
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800913static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
914{
915 if (mode == 0 && pwm == 255)
916 return off;
917 return mode + 1;
918}
919
920static int pwm_enable_to_reg(enum pwm_enable mode)
921{
922 if (mode == off)
923 return 0;
924 return mode - 1;
925}
926
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700927/*
928 * Conversions
929 */
930
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800931/* 1 is DC mode, output in ms */
932static unsigned int step_time_from_reg(u8 reg, u8 mode)
933{
934 return mode ? 400 * reg : 100 * reg;
935}
936
937static u8 step_time_to_reg(unsigned int msec, u8 mode)
938{
939 return clamp_val((mode ? (msec + 200) / 400 :
940 (msec + 50) / 100), 1, 255);
941}
942
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800943static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
944{
945 if (reg == 0 || reg == 255)
946 return 0;
947 return 1350000U / (reg << divreg);
948}
949
950static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
951{
952 if ((reg & 0xff1f) == 0xff1f)
953 return 0;
954
955 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
956
957 if (reg == 0)
958 return 0;
959
960 return 1350000U / reg;
961}
962
963static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
964{
965 if (reg == 0 || reg == 0xffff)
966 return 0;
967
968 /*
969 * Even though the registers are 16 bit wide, the fan divisor
970 * still applies.
971 */
972 return 1350000U / (reg << divreg);
973}
974
Guenter Roeckf6de2982018-09-13 20:01:12 -0700975static unsigned int fan_from_reg_rpm(u16 reg, unsigned int divreg)
976{
977 return reg;
978}
979
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800980static u16 fan_to_reg(u32 fan, unsigned int divreg)
981{
982 if (!fan)
983 return 0;
984
985 return (1350000U / fan) >> divreg;
986}
987
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800988static inline unsigned int
989div_from_reg(u8 reg)
990{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700991 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800992}
993
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700994/*
995 * Some of the voltage inputs have internal scaling, the tables below
996 * contain 8 (the ADC LSB in mV) * scaling factor * 100
997 */
998static const u16 scale_in[15] = {
999 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
1000 800, 800
1001};
1002
1003static inline long in_from_reg(u8 reg, u8 nr)
1004{
1005 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
1006}
1007
1008static inline u8 in_to_reg(u32 val, u8 nr)
1009{
1010 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
1011}
1012
1013/*
1014 * Data structures and manipulation thereof
1015 */
1016
1017struct nct6775_data {
1018 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -07001019 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001020 enum kinds kind;
1021 const char *name;
1022
Guenter Roeck615fc8c2013-07-06 09:43:30 -07001023 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001024
Guenter Roeckb7a61352013-04-02 22:14:06 -07001025 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1026 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -08001027 */
1028 u8 temp_src[NUM_TEMP];
1029 u16 reg_temp_config[NUM_TEMP];
1030 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07001031 u32 temp_mask;
Guenter Roeck37196ba2018-09-13 19:43:58 -07001032 u32 virt_temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001033
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001034 u16 REG_CONFIG;
1035 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001036 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07001037 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001038
1039 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07001040 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001041
1042 const u16 *REG_VIN;
1043 const u16 *REG_IN_MINMAX[2];
1044
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001045 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001046 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001047 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001048 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001049 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07001050 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001051 const u16 *REG_FAN_TIME[3];
1052
1053 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001054
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001055 const u8 *REG_PWM_MODE;
1056 const u8 *PWM_MODE_MASK;
1057
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001058 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1059 * [3]=pwm_max, [4]=pwm_step,
1060 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001061 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001062 const u16 *REG_PWM_READ;
1063
Guenter Roeck6c009502012-07-01 08:23:15 -07001064 const u16 *REG_CRITICAL_PWM_ENABLE;
1065 u8 CRITICAL_PWM_ENABLE_MASK;
1066 const u16 *REG_CRITICAL_PWM;
1067
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001068 const u16 *REG_AUTO_TEMP;
1069 const u16 *REG_AUTO_PWM;
1070
1071 const u16 *REG_CRITICAL_TEMP;
1072 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
1073
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001074 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001075 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001076 const u16 *REG_WEIGHT_TEMP_SEL;
1077 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
1078
Guenter Roeckaa136e52012-12-04 03:26:05 -08001079 const u16 *REG_TEMP_OFFSET;
1080
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001081 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07001082 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001083
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001084 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
1085 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
1086
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001087 struct mutex update_lock;
1088 bool valid; /* true if following fields are valid */
1089 unsigned long last_updated; /* In jiffies */
1090
1091 /* Register values */
1092 u8 bank; /* current register bank */
1093 u8 in_num; /* number of in inputs we have */
1094 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -07001095 unsigned int rpm[NUM_FAN];
1096 u16 fan_min[NUM_FAN];
1097 u8 fan_pulses[NUM_FAN];
1098 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001099 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001100 u8 has_fan; /* some fan inputs can be disabled */
1101 u8 has_fan_min; /* some fans don't have min register */
1102 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001103
Guenter Roeck6c009502012-07-01 08:23:15 -07001104 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001105 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001106 u8 temp_fixed_num; /* 3 or 6 */
1107 u8 temp_type[NUM_TEMP_FIXED];
1108 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001109 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1110 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001111 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001112 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001113
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001114 u8 pwm_num; /* number of pwm */
Guenter Roeck57fec3a2018-06-18 09:21:46 -07001115 u8 pwm_mode[NUM_FAN]; /* 0->DC variable voltage,
1116 * 1->PWM variable duty cycle
David Bartley578ab5f2013-06-24 22:28:28 -07001117 */
1118 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001119 /* 0->off
1120 * 1->manual
1121 * 2->thermal cruise mode (also called SmartFan I)
1122 * 3->fan speed cruise mode
1123 * 4->SmartFan III
1124 * 5->enhanced variable thermal cruise (SmartFan IV)
1125 */
David Bartley578ab5f2013-06-24 22:28:28 -07001126 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1127 * [3]=pwm_max, [4]=pwm_step,
1128 * [5]=weight_duty_step, [6]=weight_duty_base
1129 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001130
David Bartley578ab5f2013-06-24 22:28:28 -07001131 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001132 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001133 u32 target_speed[NUM_FAN];
1134 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001135 u8 speed_tolerance_limit;
1136
David Bartley578ab5f2013-06-24 22:28:28 -07001137 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001138 u8 tolerance_mask;
1139
David Bartley578ab5f2013-06-24 22:28:28 -07001140 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001141
1142 /* Automatic fan speed control registers */
1143 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001144 u8 auto_pwm[NUM_FAN][7];
1145 u8 auto_temp[NUM_FAN][7];
1146 u8 pwm_temp_sel[NUM_FAN];
1147 u8 pwm_weight_temp_sel[NUM_FAN];
1148 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1149 * 2->temp_base
1150 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001151
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001152 u8 vid;
1153 u8 vrm;
1154
Guenter Roeckf73cf632013-03-18 09:22:50 -07001155 bool have_vid;
1156
Guenter Roeckaa136e52012-12-04 03:26:05 -08001157 u16 have_temp;
1158 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001159 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001160
Guenter Roeck84d19d92012-12-04 08:01:39 -08001161 /* Remember extra register values over suspend/resume */
1162 u8 vbat;
1163 u8 fandiv1;
1164 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001165 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001166};
1167
1168struct nct6775_sio_data {
1169 int sioreg;
1170 enum kinds kind;
1171};
1172
Guenter Roeckf73cf632013-03-18 09:22:50 -07001173struct sensor_device_template {
1174 struct device_attribute dev_attr;
1175 union {
1176 struct {
1177 u8 nr;
1178 u8 index;
1179 } s;
1180 int index;
1181 } u;
1182 bool s2; /* true if both index and nr are used */
1183};
1184
1185struct sensor_device_attr_u {
1186 union {
1187 struct sensor_device_attribute a1;
1188 struct sensor_device_attribute_2 a2;
1189 } u;
1190 char name[32];
1191};
1192
1193#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1194 .attr = {.name = _template, .mode = _mode }, \
1195 .show = _show, \
1196 .store = _store, \
1197}
1198
1199#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1200 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1201 .u.index = _index, \
1202 .s2 = false }
1203
1204#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1205 _nr, _index) \
1206 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1207 .u.s.index = _index, \
1208 .u.s.nr = _nr, \
1209 .s2 = true }
1210
1211#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1212static struct sensor_device_template sensor_dev_template_##_name \
1213 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1214 _index)
1215
1216#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1217 _nr, _index) \
1218static struct sensor_device_template sensor_dev_template_##_name \
1219 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1220 _nr, _index)
1221
1222struct sensor_template_group {
1223 struct sensor_device_template **templates;
1224 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1225 int base;
1226};
1227
1228static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001229nct6775_create_attr_group(struct device *dev,
1230 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001231 int repeat)
1232{
1233 struct attribute_group *group;
1234 struct sensor_device_attr_u *su;
1235 struct sensor_device_attribute *a;
1236 struct sensor_device_attribute_2 *a2;
1237 struct attribute **attrs;
1238 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001239 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001240
1241 if (repeat <= 0)
1242 return ERR_PTR(-EINVAL);
1243
1244 t = tg->templates;
1245 for (count = 0; *t; t++, count++)
1246 ;
1247
1248 if (count == 0)
1249 return ERR_PTR(-EINVAL);
1250
1251 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1252 if (group == NULL)
1253 return ERR_PTR(-ENOMEM);
1254
Kees Cooka86854d2018-06-12 14:07:58 -07001255 attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001256 GFP_KERNEL);
1257 if (attrs == NULL)
1258 return ERR_PTR(-ENOMEM);
1259
Kees Cooka86854d2018-06-12 14:07:58 -07001260 su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001261 GFP_KERNEL);
1262 if (su == NULL)
1263 return ERR_PTR(-ENOMEM);
1264
1265 group->attrs = attrs;
1266 group->is_visible = tg->is_visible;
1267
1268 for (i = 0; i < repeat; i++) {
1269 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001270 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001271 snprintf(su->name, sizeof(su->name),
1272 (*t)->dev_attr.attr.name, tg->base + i);
1273 if ((*t)->s2) {
1274 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001275 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001276 a2->dev_attr.attr.name = su->name;
1277 a2->nr = (*t)->u.s.nr + i;
1278 a2->index = (*t)->u.s.index;
1279 a2->dev_attr.attr.mode =
1280 (*t)->dev_attr.attr.mode;
1281 a2->dev_attr.show = (*t)->dev_attr.show;
1282 a2->dev_attr.store = (*t)->dev_attr.store;
1283 *attrs = &a2->dev_attr.attr;
1284 } else {
1285 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001286 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001287 a->dev_attr.attr.name = su->name;
1288 a->index = (*t)->u.index + i;
1289 a->dev_attr.attr.mode =
1290 (*t)->dev_attr.attr.mode;
1291 a->dev_attr.show = (*t)->dev_attr.show;
1292 a->dev_attr.store = (*t)->dev_attr.store;
1293 *attrs = &a->dev_attr.attr;
1294 }
1295 attrs++;
1296 su++;
1297 t++;
1298 }
1299 }
1300
Guenter Roeckf73cf632013-03-18 09:22:50 -07001301 return group;
1302}
1303
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001304static bool is_word_sized(struct nct6775_data *data, u16 reg)
1305{
1306 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001307 case nct6106:
1308 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1309 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1310 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001311 case nct6775:
1312 return (((reg & 0xff00) == 0x100 ||
1313 (reg & 0xff00) == 0x200) &&
1314 ((reg & 0x00ff) == 0x50 ||
1315 (reg & 0x00ff) == 0x53 ||
1316 (reg & 0x00ff) == 0x55)) ||
1317 (reg & 0xfff0) == 0x630 ||
1318 reg == 0x640 || reg == 0x642 ||
1319 reg == 0x662 ||
1320 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1321 reg == 0x73 || reg == 0x75 || reg == 0x77;
1322 case nct6776:
1323 return (((reg & 0xff00) == 0x100 ||
1324 (reg & 0xff00) == 0x200) &&
1325 ((reg & 0x00ff) == 0x50 ||
1326 (reg & 0x00ff) == 0x53 ||
1327 (reg & 0x00ff) == 0x55)) ||
1328 (reg & 0xfff0) == 0x630 ||
1329 reg == 0x402 ||
1330 reg == 0x640 || reg == 0x642 ||
1331 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1332 reg == 0x73 || reg == 0x75 || reg == 0x77;
1333 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001334 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001335 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001336 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001337 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001338 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07001339 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07001340 case nct6798:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001341 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
Guenter Roeckf6de2982018-09-13 20:01:12 -07001342 (reg & 0xfff0) == 0x4c0 ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001343 reg == 0x402 ||
1344 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001345 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck55066352018-09-17 05:23:58 -07001346 reg == 0x64c ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001347 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001348 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001349 }
1350 return false;
1351}
1352
1353/*
1354 * On older chips, only registers 0x50-0x5f are banked.
1355 * On more recent chips, all registers are banked.
1356 * Assume that is the case and set the bank number for each access.
1357 * Cache the bank number so it only needs to be set if it changes.
1358 */
1359static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1360{
1361 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001362
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001363 if (data->bank != bank) {
1364 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1365 outb_p(bank, data->addr + DATA_REG_OFFSET);
1366 data->bank = bank;
1367 }
1368}
1369
1370static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1371{
1372 int res, word_sized = is_word_sized(data, reg);
1373
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001374 nct6775_set_bank(data, reg);
1375 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1376 res = inb_p(data->addr + DATA_REG_OFFSET);
1377 if (word_sized) {
1378 outb_p((reg & 0xff) + 1,
1379 data->addr + ADDR_REG_OFFSET);
1380 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1381 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001382 return res;
1383}
1384
1385static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1386{
1387 int word_sized = is_word_sized(data, reg);
1388
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001389 nct6775_set_bank(data, reg);
1390 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1391 if (word_sized) {
1392 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1393 outb_p((reg & 0xff) + 1,
1394 data->addr + ADDR_REG_OFFSET);
1395 }
1396 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001397 return 0;
1398}
1399
Guenter Roeckaa136e52012-12-04 03:26:05 -08001400/* We left-align 8-bit temperature values to make the code simpler */
1401static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1402{
1403 u16 res;
1404
1405 res = nct6775_read_value(data, reg);
1406 if (!is_word_sized(data, reg))
1407 res <<= 8;
1408
1409 return res;
1410}
1411
1412static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1413{
1414 if (!is_word_sized(data, reg))
1415 value >>= 8;
1416 return nct6775_write_value(data, reg, value);
1417}
1418
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001419/* This function assumes that the caller holds data->update_lock */
1420static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1421{
1422 u8 reg;
1423
1424 switch (nr) {
1425 case 0:
1426 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1427 | (data->fan_div[0] & 0x7);
1428 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1429 break;
1430 case 1:
1431 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1432 | ((data->fan_div[1] << 4) & 0x70);
1433 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1434 break;
1435 case 2:
1436 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1437 | (data->fan_div[2] & 0x7);
1438 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1439 break;
1440 case 3:
1441 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1442 | ((data->fan_div[3] << 4) & 0x70);
1443 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1444 break;
1445 }
1446}
1447
1448static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1449{
1450 if (data->kind == nct6775)
1451 nct6775_write_fan_div(data, nr);
1452}
1453
1454static void nct6775_update_fan_div(struct nct6775_data *data)
1455{
1456 u8 i;
1457
1458 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1459 data->fan_div[0] = i & 0x7;
1460 data->fan_div[1] = (i & 0x70) >> 4;
1461 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1462 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001463 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001464 data->fan_div[3] = (i & 0x70) >> 4;
1465}
1466
1467static void nct6775_update_fan_div_common(struct nct6775_data *data)
1468{
1469 if (data->kind == nct6775)
1470 nct6775_update_fan_div(data);
1471}
1472
1473static void nct6775_init_fan_div(struct nct6775_data *data)
1474{
1475 int i;
1476
1477 nct6775_update_fan_div_common(data);
1478 /*
1479 * For all fans, start with highest divider value if the divider
1480 * register is not initialized. This ensures that we get a
1481 * reading from the fan count register, even if it is not optimal.
1482 * We'll compute a better divider later on.
1483 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001484 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001485 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001486 continue;
1487 if (data->fan_div[i] == 0) {
1488 data->fan_div[i] = 7;
1489 nct6775_write_fan_div_common(data, i);
1490 }
1491 }
1492}
1493
1494static void nct6775_init_fan_common(struct device *dev,
1495 struct nct6775_data *data)
1496{
1497 int i;
1498 u8 reg;
1499
1500 if (data->has_fan_div)
1501 nct6775_init_fan_div(data);
1502
1503 /*
1504 * If fan_min is not set (0), set it to 0xff to disable it. This
1505 * prevents the unnecessary warning when fanX_min is reported as 0.
1506 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001507 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001508 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001509 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1510 if (!reg)
1511 nct6775_write_value(data, data->REG_FAN_MIN[i],
1512 data->has_fan_div ? 0xff
1513 : 0xff1f);
1514 }
1515 }
1516}
1517
1518static void nct6775_select_fan_div(struct device *dev,
1519 struct nct6775_data *data, int nr, u16 reg)
1520{
1521 u8 fan_div = data->fan_div[nr];
1522 u16 fan_min;
1523
1524 if (!data->has_fan_div)
1525 return;
1526
1527 /*
1528 * If we failed to measure the fan speed, or the reported value is not
1529 * in the optimal range, and the clock divider can be modified,
1530 * let's try that for next time.
1531 */
1532 if (reg == 0x00 && fan_div < 0x07)
1533 fan_div++;
1534 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1535 fan_div--;
1536
1537 if (fan_div != data->fan_div[nr]) {
1538 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1539 nr + 1, div_from_reg(data->fan_div[nr]),
1540 div_from_reg(fan_div));
1541
1542 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001543 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001544 fan_min = data->fan_min[nr];
1545 if (fan_div > data->fan_div[nr]) {
1546 if (fan_min != 255 && fan_min > 1)
1547 fan_min >>= 1;
1548 } else {
1549 if (fan_min != 255) {
1550 fan_min <<= 1;
1551 if (fan_min > 254)
1552 fan_min = 254;
1553 }
1554 }
1555 if (fan_min != data->fan_min[nr]) {
1556 data->fan_min[nr] = fan_min;
1557 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1558 fan_min);
1559 }
1560 }
1561 data->fan_div[nr] = fan_div;
1562 nct6775_write_fan_div_common(data, nr);
1563 }
1564}
1565
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001566static void nct6775_update_pwm(struct device *dev)
1567{
1568 struct nct6775_data *data = dev_get_drvdata(dev);
1569 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001570 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001571 bool duty_is_dc;
1572
1573 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001574 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001575 continue;
1576
1577 duty_is_dc = data->REG_PWM_MODE[i] &&
1578 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1579 & data->PWM_MODE_MASK[i]);
Guenter Roeck415eb2a2018-03-26 19:50:31 -07001580 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001581
1582 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1583 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1584 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1585 data->pwm[j][i]
1586 = nct6775_read_value(data,
1587 data->REG_PWM[j][i]);
1588 }
1589 }
1590
1591 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1592 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001593
1594 if (!data->temp_tolerance[0][i] ||
1595 data->pwm_enable[i] != speed_cruise)
1596 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1597 if (!data->target_speed_tolerance[i] ||
1598 data->pwm_enable[i] == speed_cruise) {
1599 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001600
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001601 if (data->REG_TOLERANCE_H) {
1602 t |= (nct6775_read_value(data,
1603 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1604 }
1605 data->target_speed_tolerance[i] = t;
1606 }
1607
1608 data->temp_tolerance[1][i] =
1609 nct6775_read_value(data,
1610 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1611
1612 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1613 data->pwm_temp_sel[i] = reg & 0x1f;
1614 /* If fan can stop, report floor as 0 */
1615 if (reg & 0x80)
1616 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001617
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001618 if (!data->REG_WEIGHT_TEMP_SEL[i])
1619 continue;
1620
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001621 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1622 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1623 /* If weight is disabled, report weight source as 0 */
Dan Carpentere3f3d7a2018-09-05 10:46:27 +03001624 if (!(reg & 0x80))
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001625 data->pwm_weight_temp_sel[i] = 0;
1626
1627 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001628 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001629 data->weight_temp[j][i]
1630 = nct6775_read_value(data,
1631 data->REG_WEIGHT_TEMP[j][i]);
1632 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001633 }
1634}
1635
1636static void nct6775_update_pwm_limits(struct device *dev)
1637{
1638 struct nct6775_data *data = dev_get_drvdata(dev);
1639 int i, j;
1640 u8 reg;
1641 u16 reg_t;
1642
1643 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001644 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001645 continue;
1646
Guenter Roeckc409fd42013-04-09 05:04:00 -07001647 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001648 data->fan_time[j][i] =
1649 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1650 }
1651
1652 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1653 /* Update only in matching mode or if never updated */
1654 if (!data->target_temp[i] ||
1655 data->pwm_enable[i] == thermal_cruise)
1656 data->target_temp[i] = reg_t & data->target_temp_mask;
1657 if (!data->target_speed[i] ||
1658 data->pwm_enable[i] == speed_cruise) {
1659 if (data->REG_TOLERANCE_H) {
1660 reg_t |= (nct6775_read_value(data,
1661 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1662 }
1663 data->target_speed[i] = reg_t;
1664 }
1665
1666 for (j = 0; j < data->auto_pwm_num; j++) {
1667 data->auto_pwm[i][j] =
1668 nct6775_read_value(data,
1669 NCT6775_AUTO_PWM(data, i, j));
1670 data->auto_temp[i][j] =
1671 nct6775_read_value(data,
1672 NCT6775_AUTO_TEMP(data, i, j));
1673 }
1674
1675 /* critical auto_pwm temperature data */
1676 data->auto_temp[i][data->auto_pwm_num] =
1677 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1678
1679 switch (data->kind) {
1680 case nct6775:
1681 reg = nct6775_read_value(data,
1682 NCT6775_REG_CRITICAL_ENAB[i]);
1683 data->auto_pwm[i][data->auto_pwm_num] =
1684 (reg & 0x02) ? 0xff : 0x00;
1685 break;
1686 case nct6776:
1687 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1688 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001689 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001690 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001691 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001692 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001693 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001694 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001695 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07001696 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07001697 case nct6798:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001698 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001699 data->REG_CRITICAL_PWM_ENABLE[i]);
1700 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1701 reg = nct6775_read_value(data,
1702 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001703 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001704 reg = 0xff;
1705 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001706 break;
1707 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001708 }
1709}
1710
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001711static struct nct6775_data *nct6775_update_device(struct device *dev)
1712{
1713 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001714 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001715
1716 mutex_lock(&data->update_lock);
1717
Guenter Roeck6445e662013-04-21 09:13:28 -07001718 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001719 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001720 /* Fan clock dividers */
1721 nct6775_update_fan_div_common(data);
1722
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001723 /* Measured voltages and limits */
1724 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001725 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001726 continue;
1727
1728 data->in[i][0] = nct6775_read_value(data,
1729 data->REG_VIN[i]);
1730 data->in[i][1] = nct6775_read_value(data,
1731 data->REG_IN_MINMAX[0][i]);
1732 data->in[i][2] = nct6775_read_value(data,
1733 data->REG_IN_MINMAX[1][i]);
1734 }
1735
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001736 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001737 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001738 u16 reg;
1739
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001740 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001741 continue;
1742
1743 reg = nct6775_read_value(data, data->REG_FAN[i]);
1744 data->rpm[i] = data->fan_from_reg(reg,
1745 data->fan_div[i]);
1746
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001747 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001748 data->fan_min[i] = nct6775_read_value(data,
1749 data->REG_FAN_MIN[i]);
Guenter Roeckc7932792018-09-06 09:47:51 -07001750
1751 if (data->REG_FAN_PULSES[i]) {
1752 data->fan_pulses[i] =
1753 (nct6775_read_value(data,
1754 data->REG_FAN_PULSES[i])
1755 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
1756 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001757
1758 nct6775_select_fan_div(dev, data, i, reg);
1759 }
1760
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001761 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001762 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001763
Guenter Roeckaa136e52012-12-04 03:26:05 -08001764 /* Measured temperatures and limits */
1765 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001766 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001767 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001768 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001769 if (data->reg_temp[j][i])
1770 data->temp[j][i]
1771 = nct6775_read_temp(data,
1772 data->reg_temp[j][i]);
1773 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001774 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001775 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001776 continue;
1777 data->temp_offset[i]
1778 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1779 }
1780
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001781 data->alarms = 0;
1782 for (i = 0; i < NUM_REG_ALARM; i++) {
1783 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001784
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001785 if (!data->REG_ALARM[i])
1786 continue;
1787 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1788 data->alarms |= ((u64)alarm) << (i << 3);
1789 }
1790
Guenter Roeck30846992013-06-24 22:21:59 -07001791 data->beeps = 0;
1792 for (i = 0; i < NUM_REG_BEEP; i++) {
1793 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001794
Guenter Roeck30846992013-06-24 22:21:59 -07001795 if (!data->REG_BEEP[i])
1796 continue;
1797 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1798 data->beeps |= ((u64)beep) << (i << 3);
1799 }
1800
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001801 data->last_updated = jiffies;
1802 data->valid = true;
1803 }
1804
1805 mutex_unlock(&data->update_lock);
1806 return data;
1807}
1808
1809/*
1810 * Sysfs callback functions
1811 */
1812static ssize_t
1813show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1814{
1815 struct nct6775_data *data = nct6775_update_device(dev);
1816 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001817 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001818 int nr = sattr->nr;
1819
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001820 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1821}
1822
1823static ssize_t
1824store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1825 size_t count)
1826{
1827 struct nct6775_data *data = dev_get_drvdata(dev);
1828 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001829 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001830 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001831 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001832 int err;
1833
1834 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001835 if (err < 0)
1836 return err;
1837 mutex_lock(&data->update_lock);
1838 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001839 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001840 data->in[nr][index]);
1841 mutex_unlock(&data->update_lock);
1842 return count;
1843}
1844
1845static ssize_t
1846show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1847{
1848 struct nct6775_data *data = nct6775_update_device(dev);
1849 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1850 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001851
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001852 return sprintf(buf, "%u\n",
1853 (unsigned int)((data->alarms >> nr) & 0x01));
1854}
1855
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001856static int find_temp_source(struct nct6775_data *data, int index, int count)
1857{
1858 int source = data->temp_src[index];
1859 int nr;
1860
1861 for (nr = 0; nr < count; nr++) {
1862 int src;
1863
1864 src = nct6775_read_value(data,
1865 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1866 if (src == source)
1867 return nr;
1868 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001869 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001870}
1871
1872static ssize_t
1873show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1874{
1875 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1876 struct nct6775_data *data = nct6775_update_device(dev);
1877 unsigned int alarm = 0;
1878 int nr;
1879
1880 /*
1881 * For temperatures, there is no fixed mapping from registers to alarm
1882 * bits. Alarm bits are determined by the temperature source mapping.
1883 */
1884 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1885 if (nr >= 0) {
1886 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001887
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001888 alarm = (data->alarms >> bit) & 0x01;
1889 }
1890 return sprintf(buf, "%u\n", alarm);
1891}
1892
Guenter Roeck30846992013-06-24 22:21:59 -07001893static ssize_t
1894show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1895{
1896 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1897 struct nct6775_data *data = nct6775_update_device(dev);
1898 int nr = data->BEEP_BITS[sattr->index];
1899
1900 return sprintf(buf, "%u\n",
1901 (unsigned int)((data->beeps >> nr) & 0x01));
1902}
1903
1904static ssize_t
1905store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1906 size_t count)
1907{
1908 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1909 struct nct6775_data *data = dev_get_drvdata(dev);
1910 int nr = data->BEEP_BITS[sattr->index];
1911 int regindex = nr >> 3;
1912 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001913 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001914
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001915 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001916 if (err < 0)
1917 return err;
1918 if (val > 1)
1919 return -EINVAL;
1920
1921 mutex_lock(&data->update_lock);
1922 if (val)
1923 data->beeps |= (1ULL << nr);
1924 else
1925 data->beeps &= ~(1ULL << nr);
1926 nct6775_write_value(data, data->REG_BEEP[regindex],
1927 (data->beeps >> (regindex << 3)) & 0xff);
1928 mutex_unlock(&data->update_lock);
1929 return count;
1930}
1931
1932static ssize_t
1933show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1934{
1935 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1936 struct nct6775_data *data = nct6775_update_device(dev);
1937 unsigned int beep = 0;
1938 int nr;
1939
1940 /*
1941 * For temperatures, there is no fixed mapping from registers to beep
1942 * enable bits. Beep enable bits are determined by the temperature
1943 * source mapping.
1944 */
1945 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1946 if (nr >= 0) {
1947 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001948
Guenter Roeck30846992013-06-24 22:21:59 -07001949 beep = (data->beeps >> bit) & 0x01;
1950 }
1951 return sprintf(buf, "%u\n", beep);
1952}
1953
1954static ssize_t
1955store_temp_beep(struct device *dev, struct device_attribute *attr,
1956 const char *buf, size_t count)
1957{
1958 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1959 struct nct6775_data *data = dev_get_drvdata(dev);
1960 int nr, bit, regindex;
1961 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001962 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001963
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001964 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001965 if (err < 0)
1966 return err;
1967 if (val > 1)
1968 return -EINVAL;
1969
1970 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1971 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001972 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001973
1974 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1975 regindex = bit >> 3;
1976
1977 mutex_lock(&data->update_lock);
1978 if (val)
1979 data->beeps |= (1ULL << bit);
1980 else
1981 data->beeps &= ~(1ULL << bit);
1982 nct6775_write_value(data, data->REG_BEEP[regindex],
1983 (data->beeps >> (regindex << 3)) & 0xff);
1984 mutex_unlock(&data->update_lock);
1985
1986 return count;
1987}
1988
Guenter Roeckf73cf632013-03-18 09:22:50 -07001989static umode_t nct6775_in_is_visible(struct kobject *kobj,
1990 struct attribute *attr, int index)
1991{
1992 struct device *dev = container_of(kobj, struct device, kobj);
1993 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001994 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001995
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001996 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001997 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001998
Guenter Roeckf73cf632013-03-18 09:22:50 -07001999 return attr->mode;
2000}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002001
Guenter Roeckf73cf632013-03-18 09:22:50 -07002002SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
2003SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002004SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
2005 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002006SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
2007 store_in_reg, 0, 1);
2008SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
2009 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002010
Guenter Roeckf73cf632013-03-18 09:22:50 -07002011/*
2012 * nct6775_in_is_visible uses the index into the following array
2013 * to determine if attributes should be created or not.
2014 * Any change in order or content must be matched.
2015 */
2016static struct sensor_device_template *nct6775_attributes_in_template[] = {
2017 &sensor_dev_template_in_input,
2018 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07002019 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07002020 &sensor_dev_template_in_min,
2021 &sensor_dev_template_in_max,
2022 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002023};
2024
Julia Lawallc60fdf82015-12-12 17:36:39 +01002025static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002026 .templates = nct6775_attributes_in_template,
2027 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002028};
2029
2030static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002031show_fan(struct device *dev, struct device_attribute *attr, char *buf)
2032{
2033 struct nct6775_data *data = nct6775_update_device(dev);
2034 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2035 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002036
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002037 return sprintf(buf, "%d\n", data->rpm[nr]);
2038}
2039
2040static ssize_t
2041show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
2042{
2043 struct nct6775_data *data = nct6775_update_device(dev);
2044 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2045 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002046
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002047 return sprintf(buf, "%d\n",
2048 data->fan_from_reg_min(data->fan_min[nr],
2049 data->fan_div[nr]));
2050}
2051
2052static ssize_t
2053show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
2054{
2055 struct nct6775_data *data = nct6775_update_device(dev);
2056 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2057 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002058
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002059 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
2060}
2061
2062static ssize_t
2063store_fan_min(struct device *dev, struct device_attribute *attr,
2064 const char *buf, size_t count)
2065{
2066 struct nct6775_data *data = dev_get_drvdata(dev);
2067 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2068 int nr = sattr->index;
2069 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002070 unsigned int reg;
2071 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002072 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002073
2074 err = kstrtoul(buf, 10, &val);
2075 if (err < 0)
2076 return err;
2077
2078 mutex_lock(&data->update_lock);
2079 if (!data->has_fan_div) {
2080 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
2081 if (!val) {
2082 val = 0xff1f;
2083 } else {
2084 if (val > 1350000U)
2085 val = 135000U;
2086 val = 1350000U / val;
2087 val = (val & 0x1f) | ((val << 3) & 0xff00);
2088 }
2089 data->fan_min[nr] = val;
2090 goto write_min; /* Leave fan divider alone */
2091 }
2092 if (!val) {
2093 /* No min limit, alarm disabled */
2094 data->fan_min[nr] = 255;
2095 new_div = data->fan_div[nr]; /* No change */
2096 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
2097 goto write_div;
2098 }
2099 reg = 1350000U / val;
2100 if (reg >= 128 * 255) {
2101 /*
2102 * Speed below this value cannot possibly be represented,
2103 * even with the highest divider (128)
2104 */
2105 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002106 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002107 dev_warn(dev,
2108 "fan%u low limit %lu below minimum %u, set to minimum\n",
2109 nr + 1, val, data->fan_from_reg_min(254, 7));
2110 } else if (!reg) {
2111 /*
2112 * Speed above this value cannot possibly be represented,
2113 * even with the lowest divider (1)
2114 */
2115 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002116 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002117 dev_warn(dev,
2118 "fan%u low limit %lu above maximum %u, set to maximum\n",
2119 nr + 1, val, data->fan_from_reg_min(1, 0));
2120 } else {
2121 /*
2122 * Automatically pick the best divider, i.e. the one such
2123 * that the min limit will correspond to a register value
2124 * in the 96..192 range
2125 */
2126 new_div = 0;
2127 while (reg > 192 && new_div < 7) {
2128 reg >>= 1;
2129 new_div++;
2130 }
2131 data->fan_min[nr] = reg;
2132 }
2133
2134write_div:
2135 /*
2136 * Write both the fan clock divider (if it changed) and the new
2137 * fan min (unconditionally)
2138 */
2139 if (new_div != data->fan_div[nr]) {
2140 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2141 nr + 1, div_from_reg(data->fan_div[nr]),
2142 div_from_reg(new_div));
2143 data->fan_div[nr] = new_div;
2144 nct6775_write_fan_div_common(data, nr);
2145 /* Give the chip time to sample a new speed value */
2146 data->last_updated = jiffies;
2147 }
2148
2149write_min:
2150 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2151 mutex_unlock(&data->update_lock);
2152
2153 return count;
2154}
2155
Guenter Roeck5c25d952012-12-11 07:29:06 -08002156static ssize_t
2157show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2158{
2159 struct nct6775_data *data = nct6775_update_device(dev);
2160 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2161 int p = data->fan_pulses[sattr->index];
2162
2163 return sprintf(buf, "%d\n", p ? : 4);
2164}
2165
2166static ssize_t
2167store_fan_pulses(struct device *dev, struct device_attribute *attr,
2168 const char *buf, size_t count)
2169{
2170 struct nct6775_data *data = dev_get_drvdata(dev);
2171 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2172 int nr = sattr->index;
2173 unsigned long val;
2174 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002175 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002176
2177 err = kstrtoul(buf, 10, &val);
2178 if (err < 0)
2179 return err;
2180
2181 if (val > 4)
2182 return -EINVAL;
2183
2184 mutex_lock(&data->update_lock);
2185 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002186 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2187 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2188 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2189 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002190 mutex_unlock(&data->update_lock);
2191
2192 return count;
2193}
2194
Guenter Roeckf73cf632013-03-18 09:22:50 -07002195static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2196 struct attribute *attr, int index)
2197{
2198 struct device *dev = container_of(kobj, struct device, kobj);
2199 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002200 int fan = index / 6; /* fan index */
2201 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002202
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002203 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002204 return 0;
2205
2206 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2207 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002208 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002209 return 0;
Guenter Roeck81820052018-02-21 13:09:39 -08002210 if (nr == 3 && !data->REG_FAN_PULSES[fan])
2211 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002212 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002213 return 0;
2214 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002215 return 0;
2216
2217 return attr->mode;
2218}
2219
2220SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2221SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2222 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002223SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2224 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002225SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2226 store_fan_pulses, 0);
2227SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2228 store_fan_min, 0);
2229SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2230
2231/*
2232 * nct6775_fan_is_visible uses the index into the following array
2233 * to determine if attributes should be created or not.
2234 * Any change in order or content must be matched.
2235 */
2236static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2237 &sensor_dev_template_fan_input,
2238 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002239 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002240 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002241 &sensor_dev_template_fan_min, /* 4 */
2242 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002243 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002244};
2245
Julia Lawallc60fdf82015-12-12 17:36:39 +01002246static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002247 .templates = nct6775_attributes_fan_template,
2248 .is_visible = nct6775_fan_is_visible,
2249 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002250};
2251
2252static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002253show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2254{
2255 struct nct6775_data *data = nct6775_update_device(dev);
2256 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2257 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002258
Guenter Roeckaa136e52012-12-04 03:26:05 -08002259 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2260}
2261
2262static ssize_t
2263show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2264{
2265 struct nct6775_data *data = nct6775_update_device(dev);
2266 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2267 int nr = sattr->nr;
2268 int index = sattr->index;
2269
2270 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2271}
2272
2273static ssize_t
2274store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2275 size_t count)
2276{
2277 struct nct6775_data *data = dev_get_drvdata(dev);
2278 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2279 int nr = sattr->nr;
2280 int index = sattr->index;
2281 int err;
2282 long val;
2283
2284 err = kstrtol(buf, 10, &val);
2285 if (err < 0)
2286 return err;
2287
2288 mutex_lock(&data->update_lock);
2289 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2290 nct6775_write_temp(data, data->reg_temp[index][nr],
2291 data->temp[index][nr]);
2292 mutex_unlock(&data->update_lock);
2293 return count;
2294}
2295
2296static ssize_t
2297show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2298{
2299 struct nct6775_data *data = nct6775_update_device(dev);
2300 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2301
2302 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2303}
2304
2305static ssize_t
2306store_temp_offset(struct device *dev, struct device_attribute *attr,
2307 const char *buf, size_t count)
2308{
2309 struct nct6775_data *data = dev_get_drvdata(dev);
2310 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2311 int nr = sattr->index;
2312 long val;
2313 int err;
2314
2315 err = kstrtol(buf, 10, &val);
2316 if (err < 0)
2317 return err;
2318
2319 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2320
2321 mutex_lock(&data->update_lock);
2322 data->temp_offset[nr] = val;
2323 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2324 mutex_unlock(&data->update_lock);
2325
2326 return count;
2327}
2328
2329static ssize_t
2330show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2331{
2332 struct nct6775_data *data = nct6775_update_device(dev);
2333 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2334 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002335
Guenter Roeckaa136e52012-12-04 03:26:05 -08002336 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2337}
2338
2339static ssize_t
2340store_temp_type(struct device *dev, struct device_attribute *attr,
2341 const char *buf, size_t count)
2342{
2343 struct nct6775_data *data = nct6775_update_device(dev);
2344 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2345 int nr = sattr->index;
2346 unsigned long val;
2347 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002348 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002349
2350 err = kstrtoul(buf, 10, &val);
2351 if (err < 0)
2352 return err;
2353
2354 if (val != 1 && val != 3 && val != 4)
2355 return -EINVAL;
2356
2357 mutex_lock(&data->update_lock);
2358
2359 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002360 vbit = 0x02 << nr;
2361 dbit = data->DIODE_MASK << nr;
2362 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2363 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002364 switch (val) {
2365 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002366 vbat |= vbit;
2367 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002368 break;
2369 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002370 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002371 break;
2372 case 4: /* thermistor */
2373 break;
2374 }
2375 nct6775_write_value(data, data->REG_VBAT, vbat);
2376 nct6775_write_value(data, data->REG_DIODE, diode);
2377
2378 mutex_unlock(&data->update_lock);
2379 return count;
2380}
2381
Guenter Roeckf73cf632013-03-18 09:22:50 -07002382static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2383 struct attribute *attr, int index)
2384{
2385 struct device *dev = container_of(kobj, struct device, kobj);
2386 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002387 int temp = index / 10; /* temp index */
2388 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002389
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002390 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002391 return 0;
2392
Guenter Roeckcc66b302017-05-17 18:05:06 -07002393 if (nr == 1 && !data->temp_label)
2394 return 0;
2395
Guenter Roeckf73cf632013-03-18 09:22:50 -07002396 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2397 return 0; /* alarm */
2398
Guenter Roeck30846992013-06-24 22:21:59 -07002399 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2400 return 0; /* beep */
2401
2402 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002403 return 0;
2404
Guenter Roeck30846992013-06-24 22:21:59 -07002405 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002406 return 0;
2407
Guenter Roeck30846992013-06-24 22:21:59 -07002408 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002409 return 0;
2410
Guenter Roeck30846992013-06-24 22:21:59 -07002411 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002412 return 0;
2413
2414 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002415 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002416 return 0;
2417
2418 return attr->mode;
2419}
2420
2421SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2422SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2423SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2424 store_temp, 0, 1);
2425SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2426 show_temp, store_temp, 0, 2);
2427SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2428 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002429SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2430 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002431SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2432 show_temp_offset, store_temp_offset, 0);
2433SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2434 store_temp_type, 0);
2435SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002436SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2437 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002438
2439/*
2440 * nct6775_temp_is_visible uses the index into the following array
2441 * to determine if attributes should be created or not.
2442 * Any change in order or content must be matched.
2443 */
2444static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2445 &sensor_dev_template_temp_input,
2446 &sensor_dev_template_temp_label,
2447 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002448 &sensor_dev_template_temp_beep, /* 3 */
2449 &sensor_dev_template_temp_max, /* 4 */
2450 &sensor_dev_template_temp_max_hyst, /* 5 */
2451 &sensor_dev_template_temp_crit, /* 6 */
2452 &sensor_dev_template_temp_lcrit, /* 7 */
2453 &sensor_dev_template_temp_offset, /* 8 */
2454 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002455 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002456};
2457
Julia Lawallc60fdf82015-12-12 17:36:39 +01002458static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002459 .templates = nct6775_attributes_temp_template,
2460 .is_visible = nct6775_temp_is_visible,
2461 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002462};
2463
Guenter Roeckaa136e52012-12-04 03:26:05 -08002464static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002465show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2466{
2467 struct nct6775_data *data = nct6775_update_device(dev);
2468 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2469
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002470 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002471}
2472
2473static ssize_t
2474store_pwm_mode(struct device *dev, struct device_attribute *attr,
2475 const char *buf, size_t count)
2476{
2477 struct nct6775_data *data = dev_get_drvdata(dev);
2478 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2479 int nr = sattr->index;
2480 unsigned long val;
2481 int err;
2482 u8 reg;
2483
2484 err = kstrtoul(buf, 10, &val);
2485 if (err < 0)
2486 return err;
2487
2488 if (val > 1)
2489 return -EINVAL;
2490
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002491 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002492 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002493 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002494 return -EINVAL;
2495 return count;
2496 }
2497
2498 mutex_lock(&data->update_lock);
2499 data->pwm_mode[nr] = val;
2500 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2501 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002502 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002503 reg |= data->PWM_MODE_MASK[nr];
2504 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2505 mutex_unlock(&data->update_lock);
2506 return count;
2507}
2508
2509static ssize_t
2510show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2511{
2512 struct nct6775_data *data = nct6775_update_device(dev);
2513 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2514 int nr = sattr->nr;
2515 int index = sattr->index;
2516 int pwm;
2517
2518 /*
2519 * For automatic fan control modes, show current pwm readings.
2520 * Otherwise, show the configured value.
2521 */
2522 if (index == 0 && data->pwm_enable[nr] > manual)
2523 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2524 else
2525 pwm = data->pwm[index][nr];
2526
2527 return sprintf(buf, "%d\n", pwm);
2528}
2529
2530static ssize_t
2531store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2532 size_t count)
2533{
2534 struct nct6775_data *data = dev_get_drvdata(dev);
2535 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2536 int nr = sattr->nr;
2537 int index = sattr->index;
2538 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002539 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2540 int maxval[7]
2541 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002542 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002543 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002544
2545 err = kstrtoul(buf, 10, &val);
2546 if (err < 0)
2547 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002548 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002549
2550 mutex_lock(&data->update_lock);
2551 data->pwm[index][nr] = val;
2552 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002553 if (index == 2) { /* floor: disable if val == 0 */
2554 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2555 reg &= 0x7f;
2556 if (val)
2557 reg |= 0x80;
2558 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2559 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002560 mutex_unlock(&data->update_lock);
2561 return count;
2562}
2563
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002564/* Returns 0 if OK, -EINVAL otherwise */
2565static int check_trip_points(struct nct6775_data *data, int nr)
2566{
2567 int i;
2568
2569 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2570 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2571 return -EINVAL;
2572 }
2573 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2574 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2575 return -EINVAL;
2576 }
2577 /* validate critical temperature and pwm if enabled (pwm > 0) */
2578 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2579 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2580 data->auto_temp[nr][data->auto_pwm_num] ||
2581 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2582 data->auto_pwm[nr][data->auto_pwm_num])
2583 return -EINVAL;
2584 }
2585 return 0;
2586}
2587
2588static void pwm_update_registers(struct nct6775_data *data, int nr)
2589{
2590 u8 reg;
2591
2592 switch (data->pwm_enable[nr]) {
2593 case off:
2594 case manual:
2595 break;
2596 case speed_cruise:
2597 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2598 reg = (reg & ~data->tolerance_mask) |
2599 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2600 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2601 nct6775_write_value(data, data->REG_TARGET[nr],
2602 data->target_speed[nr] & 0xff);
2603 if (data->REG_TOLERANCE_H) {
2604 reg = (data->target_speed[nr] >> 8) & 0x0f;
2605 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2606 nct6775_write_value(data,
2607 data->REG_TOLERANCE_H[nr],
2608 reg);
2609 }
2610 break;
2611 case thermal_cruise:
2612 nct6775_write_value(data, data->REG_TARGET[nr],
2613 data->target_temp[nr]);
Gustavo A. R. Silvaffb32432018-07-02 16:30:17 -05002614 /* fall through */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002615 default:
2616 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2617 reg = (reg & ~data->tolerance_mask) |
2618 data->temp_tolerance[0][nr];
2619 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2620 break;
2621 }
2622}
2623
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002624static ssize_t
2625show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2626{
2627 struct nct6775_data *data = nct6775_update_device(dev);
2628 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2629
2630 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2631}
2632
2633static ssize_t
2634store_pwm_enable(struct device *dev, struct device_attribute *attr,
2635 const char *buf, size_t count)
2636{
2637 struct nct6775_data *data = dev_get_drvdata(dev);
2638 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2639 int nr = sattr->index;
2640 unsigned long val;
2641 int err;
2642 u16 reg;
2643
2644 err = kstrtoul(buf, 10, &val);
2645 if (err < 0)
2646 return err;
2647
2648 if (val > sf4)
2649 return -EINVAL;
2650
2651 if (val == sf3 && data->kind != nct6775)
2652 return -EINVAL;
2653
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002654 if (val == sf4 && check_trip_points(data, nr)) {
2655 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2656 dev_err(dev, "Adjust trip points and try again\n");
2657 return -EINVAL;
2658 }
2659
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002660 mutex_lock(&data->update_lock);
2661 data->pwm_enable[nr] = val;
2662 if (val == off) {
2663 /*
2664 * turn off pwm control: select manual mode, set pwm to maximum
2665 */
2666 data->pwm[0][nr] = 255;
2667 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2668 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002669 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002670 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2671 reg &= 0x0f;
2672 reg |= pwm_enable_to_reg(val) << 4;
2673 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2674 mutex_unlock(&data->update_lock);
2675 return count;
2676}
2677
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002678static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002679show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002680{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002681 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002682
2683 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002684 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002685 continue;
2686 if (src == data->temp_src[i]) {
2687 sel = i + 1;
2688 break;
2689 }
2690 }
2691
2692 return sprintf(buf, "%d\n", sel);
2693}
2694
2695static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002696show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2697{
2698 struct nct6775_data *data = nct6775_update_device(dev);
2699 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2700 int index = sattr->index;
2701
2702 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2703}
2704
2705static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002706store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2707 const char *buf, size_t count)
2708{
2709 struct nct6775_data *data = nct6775_update_device(dev);
2710 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2711 int nr = sattr->index;
2712 unsigned long val;
2713 int err, reg, src;
2714
2715 err = kstrtoul(buf, 10, &val);
2716 if (err < 0)
2717 return err;
2718 if (val == 0 || val > NUM_TEMP)
2719 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002720 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002721 return -EINVAL;
2722
2723 mutex_lock(&data->update_lock);
2724 src = data->temp_src[val - 1];
2725 data->pwm_temp_sel[nr] = src;
2726 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2727 reg &= 0xe0;
2728 reg |= src;
2729 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2730 mutex_unlock(&data->update_lock);
2731
2732 return count;
2733}
2734
2735static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002736show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2737 char *buf)
2738{
2739 struct nct6775_data *data = nct6775_update_device(dev);
2740 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2741 int index = sattr->index;
2742
2743 return show_pwm_temp_sel_common(data, buf,
2744 data->pwm_weight_temp_sel[index]);
2745}
2746
2747static ssize_t
2748store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2749 const char *buf, size_t count)
2750{
2751 struct nct6775_data *data = nct6775_update_device(dev);
2752 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2753 int nr = sattr->index;
2754 unsigned long val;
2755 int err, reg, src;
2756
2757 err = kstrtoul(buf, 10, &val);
2758 if (err < 0)
2759 return err;
2760 if (val > NUM_TEMP)
2761 return -EINVAL;
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -05002762 val = array_index_nospec(val, NUM_TEMP + 1);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002763 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002764 !data->temp_src[val - 1]))
2765 return -EINVAL;
2766
2767 mutex_lock(&data->update_lock);
2768 if (val) {
2769 src = data->temp_src[val - 1];
2770 data->pwm_weight_temp_sel[nr] = src;
2771 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2772 reg &= 0xe0;
2773 reg |= (src | 0x80);
2774 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2775 } else {
2776 data->pwm_weight_temp_sel[nr] = 0;
2777 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2778 reg &= 0x7f;
2779 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2780 }
2781 mutex_unlock(&data->update_lock);
2782
2783 return count;
2784}
2785
2786static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002787show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2788{
2789 struct nct6775_data *data = nct6775_update_device(dev);
2790 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2791
2792 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2793}
2794
2795static ssize_t
2796store_target_temp(struct device *dev, struct device_attribute *attr,
2797 const char *buf, size_t count)
2798{
2799 struct nct6775_data *data = dev_get_drvdata(dev);
2800 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2801 int nr = sattr->index;
2802 unsigned long val;
2803 int err;
2804
2805 err = kstrtoul(buf, 10, &val);
2806 if (err < 0)
2807 return err;
2808
2809 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2810 data->target_temp_mask);
2811
2812 mutex_lock(&data->update_lock);
2813 data->target_temp[nr] = val;
2814 pwm_update_registers(data, nr);
2815 mutex_unlock(&data->update_lock);
2816 return count;
2817}
2818
2819static ssize_t
2820show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2821{
2822 struct nct6775_data *data = nct6775_update_device(dev);
2823 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2824 int nr = sattr->index;
2825
2826 return sprintf(buf, "%d\n",
2827 fan_from_reg16(data->target_speed[nr],
2828 data->fan_div[nr]));
2829}
2830
2831static ssize_t
2832store_target_speed(struct device *dev, struct device_attribute *attr,
2833 const char *buf, size_t count)
2834{
2835 struct nct6775_data *data = dev_get_drvdata(dev);
2836 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2837 int nr = sattr->index;
2838 unsigned long val;
2839 int err;
2840 u16 speed;
2841
2842 err = kstrtoul(buf, 10, &val);
2843 if (err < 0)
2844 return err;
2845
2846 val = clamp_val(val, 0, 1350000U);
2847 speed = fan_to_reg(val, data->fan_div[nr]);
2848
2849 mutex_lock(&data->update_lock);
2850 data->target_speed[nr] = speed;
2851 pwm_update_registers(data, nr);
2852 mutex_unlock(&data->update_lock);
2853 return count;
2854}
2855
2856static ssize_t
2857show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2858 char *buf)
2859{
2860 struct nct6775_data *data = nct6775_update_device(dev);
2861 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2862 int nr = sattr->nr;
2863 int index = sattr->index;
2864
2865 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2866}
2867
2868static ssize_t
2869store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2870 const char *buf, size_t count)
2871{
2872 struct nct6775_data *data = dev_get_drvdata(dev);
2873 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2874 int nr = sattr->nr;
2875 int index = sattr->index;
2876 unsigned long val;
2877 int err;
2878
2879 err = kstrtoul(buf, 10, &val);
2880 if (err < 0)
2881 return err;
2882
2883 /* Limit tolerance as needed */
2884 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2885
2886 mutex_lock(&data->update_lock);
2887 data->temp_tolerance[index][nr] = val;
2888 if (index)
2889 pwm_update_registers(data, nr);
2890 else
2891 nct6775_write_value(data,
2892 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2893 val);
2894 mutex_unlock(&data->update_lock);
2895 return count;
2896}
2897
2898/*
2899 * Fan speed tolerance is a tricky beast, since the associated register is
2900 * a tick counter, but the value is reported and configured as rpm.
2901 * Compute resulting low and high rpm values and report the difference.
Guenter Roeck61b6c662018-09-17 09:24:11 -07002902 * A fan speed tolerance only makes sense if a fan target speed has been
2903 * configured, so only display values other than 0 if that is the case.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002904 */
2905static ssize_t
2906show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2907 char *buf)
2908{
2909 struct nct6775_data *data = nct6775_update_device(dev);
2910 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2911 int nr = sattr->index;
Guenter Roeck61b6c662018-09-17 09:24:11 -07002912 int target = data->target_speed[nr];
2913 int tolerance = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002914
Guenter Roeck61b6c662018-09-17 09:24:11 -07002915 if (target) {
2916 int low = target - data->target_speed_tolerance[nr];
2917 int high = target + data->target_speed_tolerance[nr];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002918
Guenter Roeck61b6c662018-09-17 09:24:11 -07002919 if (low <= 0)
2920 low = 1;
2921 if (high > 0xffff)
2922 high = 0xffff;
2923 if (high < low)
2924 high = low;
2925
2926 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2927 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2928 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002929
2930 return sprintf(buf, "%d\n", tolerance);
2931}
2932
2933static ssize_t
2934store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2935 const char *buf, size_t count)
2936{
2937 struct nct6775_data *data = dev_get_drvdata(dev);
2938 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2939 int nr = sattr->index;
2940 unsigned long val;
2941 int err;
2942 int low, high;
2943
2944 err = kstrtoul(buf, 10, &val);
2945 if (err < 0)
2946 return err;
2947
2948 high = fan_from_reg16(data->target_speed[nr],
2949 data->fan_div[nr]) + val;
2950 low = fan_from_reg16(data->target_speed[nr],
2951 data->fan_div[nr]) - val;
2952 if (low <= 0)
2953 low = 1;
2954 if (high < low)
2955 high = low;
2956
2957 val = (fan_to_reg(low, data->fan_div[nr]) -
2958 fan_to_reg(high, data->fan_div[nr])) / 2;
2959
2960 /* Limit tolerance as needed */
2961 val = clamp_val(val, 0, data->speed_tolerance_limit);
2962
2963 mutex_lock(&data->update_lock);
2964 data->target_speed_tolerance[nr] = val;
2965 pwm_update_registers(data, nr);
2966 mutex_unlock(&data->update_lock);
2967 return count;
2968}
2969
Guenter Roeckf73cf632013-03-18 09:22:50 -07002970SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2971SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2972 store_pwm_mode, 0);
2973SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2974 store_pwm_enable, 0);
2975SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2976 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2977SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2978 show_target_temp, store_target_temp, 0);
2979SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2980 show_target_speed, store_target_speed, 0);
2981SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2982 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002983
2984/* Smart Fan registers */
2985
2986static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002987show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2988{
2989 struct nct6775_data *data = nct6775_update_device(dev);
2990 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2991 int nr = sattr->nr;
2992 int index = sattr->index;
2993
2994 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2995}
2996
2997static ssize_t
2998store_weight_temp(struct device *dev, struct device_attribute *attr,
2999 const char *buf, size_t count)
3000{
3001 struct nct6775_data *data = dev_get_drvdata(dev);
3002 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3003 int nr = sattr->nr;
3004 int index = sattr->index;
3005 unsigned long val;
3006 int err;
3007
3008 err = kstrtoul(buf, 10, &val);
3009 if (err < 0)
3010 return err;
3011
3012 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
3013
3014 mutex_lock(&data->update_lock);
3015 data->weight_temp[index][nr] = val;
3016 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
3017 mutex_unlock(&data->update_lock);
3018 return count;
3019}
3020
Guenter Roeckf73cf632013-03-18 09:22:50 -07003021SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
3022 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
3023SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
3024 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
3025SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
3026 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
3027SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
3028 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
3029SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
3030 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
3031SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
3032 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003033
3034static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003035show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
3036{
3037 struct nct6775_data *data = nct6775_update_device(dev);
3038 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3039 int nr = sattr->nr;
3040 int index = sattr->index;
3041
3042 return sprintf(buf, "%d\n",
3043 step_time_from_reg(data->fan_time[index][nr],
3044 data->pwm_mode[nr]));
3045}
3046
3047static ssize_t
3048store_fan_time(struct device *dev, struct device_attribute *attr,
3049 const char *buf, size_t count)
3050{
3051 struct nct6775_data *data = dev_get_drvdata(dev);
3052 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3053 int nr = sattr->nr;
3054 int index = sattr->index;
3055 unsigned long val;
3056 int err;
3057
3058 err = kstrtoul(buf, 10, &val);
3059 if (err < 0)
3060 return err;
3061
3062 val = step_time_to_reg(val, data->pwm_mode[nr]);
3063 mutex_lock(&data->update_lock);
3064 data->fan_time[index][nr] = val;
3065 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
3066 mutex_unlock(&data->update_lock);
3067 return count;
3068}
3069
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003070static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003071show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3072{
3073 struct nct6775_data *data = nct6775_update_device(dev);
3074 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3075
3076 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3077}
3078
3079static ssize_t
3080store_auto_pwm(struct device *dev, struct device_attribute *attr,
3081 const char *buf, size_t count)
3082{
3083 struct nct6775_data *data = dev_get_drvdata(dev);
3084 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3085 int nr = sattr->nr;
3086 int point = sattr->index;
3087 unsigned long val;
3088 int err;
3089 u8 reg;
3090
3091 err = kstrtoul(buf, 10, &val);
3092 if (err < 0)
3093 return err;
3094 if (val > 255)
3095 return -EINVAL;
3096
3097 if (point == data->auto_pwm_num) {
3098 if (data->kind != nct6775 && !val)
3099 return -EINVAL;
3100 if (data->kind != nct6779 && val)
3101 val = 0xff;
3102 }
3103
3104 mutex_lock(&data->update_lock);
3105 data->auto_pwm[nr][point] = val;
3106 if (point < data->auto_pwm_num) {
3107 nct6775_write_value(data,
3108 NCT6775_AUTO_PWM(data, nr, point),
3109 data->auto_pwm[nr][point]);
3110 } else {
3111 switch (data->kind) {
3112 case nct6775:
3113 /* disable if needed (pwm == 0) */
3114 reg = nct6775_read_value(data,
3115 NCT6775_REG_CRITICAL_ENAB[nr]);
3116 if (val)
3117 reg |= 0x02;
3118 else
3119 reg &= ~0x02;
3120 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3121 reg);
3122 break;
3123 case nct6776:
3124 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003125 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003126 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003127 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003128 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003129 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003130 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003131 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07003132 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07003133 case nct6798:
Guenter Roeck6c009502012-07-01 08:23:15 -07003134 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003135 val);
3136 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003137 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003138 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003139 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003140 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003141 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003142 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003143 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003144 reg);
3145 break;
3146 }
3147 }
3148 mutex_unlock(&data->update_lock);
3149 return count;
3150}
3151
3152static ssize_t
3153show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3154{
3155 struct nct6775_data *data = nct6775_update_device(dev);
3156 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3157 int nr = sattr->nr;
3158 int point = sattr->index;
3159
3160 /*
3161 * We don't know for sure if the temperature is signed or unsigned.
3162 * Assume it is unsigned.
3163 */
3164 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3165}
3166
3167static ssize_t
3168store_auto_temp(struct device *dev, struct device_attribute *attr,
3169 const char *buf, size_t count)
3170{
3171 struct nct6775_data *data = dev_get_drvdata(dev);
3172 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3173 int nr = sattr->nr;
3174 int point = sattr->index;
3175 unsigned long val;
3176 int err;
3177
3178 err = kstrtoul(buf, 10, &val);
3179 if (err)
3180 return err;
3181 if (val > 255000)
3182 return -EINVAL;
3183
3184 mutex_lock(&data->update_lock);
3185 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3186 if (point < data->auto_pwm_num) {
3187 nct6775_write_value(data,
3188 NCT6775_AUTO_TEMP(data, nr, point),
3189 data->auto_temp[nr][point]);
3190 } else {
3191 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3192 data->auto_temp[nr][point]);
3193 }
3194 mutex_unlock(&data->update_lock);
3195 return count;
3196}
3197
Guenter Roeckf73cf632013-03-18 09:22:50 -07003198static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3199 struct attribute *attr, int index)
3200{
3201 struct device *dev = container_of(kobj, struct device, kobj);
3202 struct nct6775_data *data = dev_get_drvdata(dev);
3203 int pwm = index / 36; /* pwm index */
3204 int nr = index % 36; /* attribute index */
3205
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003206 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003207 return 0;
3208
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003209 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3210 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3211 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003212 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3213 return 0;
3214 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3215 return 0;
3216 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3217 return 0;
3218
3219 if (nr >= 22 && nr <= 35) { /* auto point */
3220 int api = (nr - 22) / 2; /* auto point index */
3221
3222 if (api > data->auto_pwm_num)
3223 return 0;
3224 }
3225 return attr->mode;
3226}
3227
3228SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3229 show_fan_time, store_fan_time, 0, 0);
3230SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3231 show_fan_time, store_fan_time, 0, 1);
3232SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3233 show_fan_time, store_fan_time, 0, 2);
3234SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3235 store_pwm, 0, 1);
3236SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3237 store_pwm, 0, 2);
3238SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3239 show_temp_tolerance, store_temp_tolerance, 0, 0);
3240SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3241 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3242 0, 1);
3243
3244SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3245 0, 3);
3246
3247SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3248 store_pwm, 0, 4);
3249
3250SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3251 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3252SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3253 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3254
3255SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3256 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3257SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3258 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3259
3260SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3261 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3262SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3263 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3264
3265SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3266 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3267SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3268 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3269
3270SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3271 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3272SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3273 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3274
3275SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3276 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3277SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3278 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3279
3280SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3281 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3282SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3283 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3284
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003285/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003286 * nct6775_pwm_is_visible uses the index into the following array
3287 * to determine if attributes should be created or not.
3288 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003289 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003290static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3291 &sensor_dev_template_pwm,
3292 &sensor_dev_template_pwm_mode,
3293 &sensor_dev_template_pwm_enable,
3294 &sensor_dev_template_pwm_temp_sel,
3295 &sensor_dev_template_pwm_temp_tolerance,
3296 &sensor_dev_template_pwm_crit_temp_tolerance,
3297 &sensor_dev_template_pwm_target_temp,
3298 &sensor_dev_template_fan_target,
3299 &sensor_dev_template_fan_tolerance,
3300 &sensor_dev_template_pwm_stop_time,
3301 &sensor_dev_template_pwm_step_up_time,
3302 &sensor_dev_template_pwm_step_down_time,
3303 &sensor_dev_template_pwm_start,
3304 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003305 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003306 &sensor_dev_template_pwm_weight_temp_step,
3307 &sensor_dev_template_pwm_weight_temp_step_tol,
3308 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003309 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003310 &sensor_dev_template_pwm_max, /* 19 */
3311 &sensor_dev_template_pwm_step, /* 20 */
3312 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3313 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3314 &sensor_dev_template_pwm_auto_point1_temp,
3315 &sensor_dev_template_pwm_auto_point2_pwm,
3316 &sensor_dev_template_pwm_auto_point2_temp,
3317 &sensor_dev_template_pwm_auto_point3_pwm,
3318 &sensor_dev_template_pwm_auto_point3_temp,
3319 &sensor_dev_template_pwm_auto_point4_pwm,
3320 &sensor_dev_template_pwm_auto_point4_temp,
3321 &sensor_dev_template_pwm_auto_point5_pwm,
3322 &sensor_dev_template_pwm_auto_point5_temp,
3323 &sensor_dev_template_pwm_auto_point6_pwm,
3324 &sensor_dev_template_pwm_auto_point6_temp,
3325 &sensor_dev_template_pwm_auto_point7_pwm,
3326 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003327
Guenter Roeckf73cf632013-03-18 09:22:50 -07003328 NULL
3329};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003330
Julia Lawallc60fdf82015-12-12 17:36:39 +01003331static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003332 .templates = nct6775_attributes_pwm_template,
3333 .is_visible = nct6775_pwm_is_visible,
3334 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003335};
3336
3337static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003338cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003339{
3340 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003341
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003342 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3343}
3344
Julia Lawall93d72ac2016-12-22 13:05:23 +01003345static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003346
Guenter Roecka6bd5872012-12-04 03:13:34 -08003347/* Case open detection */
3348
3349static ssize_t
3350clear_caseopen(struct device *dev, struct device_attribute *attr,
3351 const char *buf, size_t count)
3352{
3353 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003354 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3355 unsigned long val;
3356 u8 reg;
3357 int ret;
3358
3359 if (kstrtoul(buf, 10, &val) || val != 0)
3360 return -EINVAL;
3361
3362 mutex_lock(&data->update_lock);
3363
3364 /*
3365 * Use CR registers to clear caseopen status.
3366 * The CR registers are the same for all chips, and not all chips
3367 * support clearing the caseopen status through "regular" registers.
3368 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003369 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003370 if (ret) {
3371 count = ret;
3372 goto error;
3373 }
3374
Guenter Roeckdf612d52013-07-08 13:15:04 -07003375 superio_select(data->sioreg, NCT6775_LD_ACPI);
3376 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003377 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003378 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003379 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003380 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3381 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003382
3383 data->valid = false; /* Force cache refresh */
3384error:
3385 mutex_unlock(&data->update_lock);
3386 return count;
3387}
3388
Guenter Roeckf73cf632013-03-18 09:22:50 -07003389static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3390 clear_caseopen, INTRUSION_ALARM_BASE);
3391static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3392 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003393static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3394 store_beep, INTRUSION_ALARM_BASE);
3395static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3396 store_beep, INTRUSION_ALARM_BASE + 1);
3397static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3398 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003399
3400static umode_t nct6775_other_is_visible(struct kobject *kobj,
3401 struct attribute *attr, int index)
3402{
3403 struct device *dev = container_of(kobj, struct device, kobj);
3404 struct nct6775_data *data = dev_get_drvdata(dev);
3405
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003406 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003407 return 0;
3408
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003409 if (index == 1 || index == 2) {
3410 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003411 return 0;
3412 }
3413
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003414 if (index == 3 || index == 4) {
3415 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003416 return 0;
3417 }
3418
Guenter Roeckf73cf632013-03-18 09:22:50 -07003419 return attr->mode;
3420}
3421
3422/*
3423 * nct6775_other_is_visible uses the index into the following array
3424 * to determine if attributes should be created or not.
3425 * Any change in order or content must be matched.
3426 */
3427static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003428 &dev_attr_cpu0_vid.attr, /* 0 */
3429 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3430 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3431 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3432 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3433 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003434
3435 NULL
3436};
3437
3438static const struct attribute_group nct6775_group_other = {
3439 .attrs = nct6775_attributes_other,
3440 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003441};
3442
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003443static inline void nct6775_init_device(struct nct6775_data *data)
3444{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003445 int i;
3446 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003447
3448 /* Start monitoring if needed */
3449 if (data->REG_CONFIG) {
3450 tmp = nct6775_read_value(data, data->REG_CONFIG);
3451 if (!(tmp & 0x01))
3452 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3453 }
3454
Guenter Roeckaa136e52012-12-04 03:26:05 -08003455 /* Enable temperature sensors if needed */
3456 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003457 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003458 continue;
3459 if (!data->reg_temp_config[i])
3460 continue;
3461 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3462 if (tmp & 0x01)
3463 nct6775_write_value(data, data->reg_temp_config[i],
3464 tmp & 0xfe);
3465 }
3466
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003467 /* Enable VBAT monitoring if needed */
3468 tmp = nct6775_read_value(data, data->REG_VBAT);
3469 if (!(tmp & 0x01))
3470 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003471
3472 diode = nct6775_read_value(data, data->REG_DIODE);
3473
3474 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003475 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003476 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003477 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3478 data->temp_type[i]
3479 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003480 else /* thermistor */
3481 data->temp_type[i] = 4;
3482 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003483}
3484
Guenter Roeckf73cf632013-03-18 09:22:50 -07003485static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003486nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003487{
Guenter Roeck1b206242018-02-21 13:09:38 -08003488 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003489 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003490 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003491 bool pwm6pin = false, pwm7pin = false;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003492 int sioreg = data->sioreg;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003493
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003494 /* Store SIO_REG_ENABLE for use during resume */
3495 superio_select(sioreg, NCT6775_LD_HWM);
3496 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3497
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003498 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3499 if (data->kind == nct6775) {
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003500 int cr2c = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003501
Guenter Roecka6c54f22018-09-18 09:34:06 -07003502 fan3pin = cr2c & BIT(6);
3503 pwm3pin = cr2c & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003504
3505 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003506 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003507 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003508 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003509 const char *board_vendor, *board_name;
3510
3511 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3512 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3513
3514 if (board_name && board_vendor &&
3515 !strcmp(board_vendor, "ASRock")) {
3516 /*
3517 * Auxiliary fan monitoring is not enabled on ASRock
3518 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3519 * Observed with BIOS version 2.00.
3520 */
3521 if (!strcmp(board_name, "Z77 Pro4-M")) {
3522 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3523 data->sio_reg_enable |= 0xe0;
3524 superio_outb(sioreg, SIO_REG_ENABLE,
3525 data->sio_reg_enable);
3526 }
3527 }
3528 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003529
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003530 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003531 fan3pin = gpok;
3532 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003533 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003534
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003535 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003536 fan4pin = gpok;
3537 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003538 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003539
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003540 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003541 fan5pin = gpok;
3542 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003543 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003544
3545 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003546 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003547 } else if (data->kind == nct6106) {
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003548 int cr24 = superio_inb(sioreg, 0x24);
3549
Guenter Roecka6c54f22018-09-18 09:34:06 -07003550 fan3pin = !(cr24 & 0x80);
3551 pwm3pin = cr24 & 0x08;
Guenter Roeck81820052018-02-21 13:09:39 -08003552 } else {
Guenter Roecke41da282018-09-18 20:48:29 -07003553 /*
3554 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
Guenter Roeck05996822018-09-19 20:26:16 -07003555 * NCT6797D, NCT6798D
Guenter Roecke41da282018-09-18 20:48:29 -07003556 */
3557 int cr1a = superio_inb(sioreg, 0x1a);
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003558 int cr1b = superio_inb(sioreg, 0x1b);
3559 int cr1c = superio_inb(sioreg, 0x1c);
3560 int cr1d = superio_inb(sioreg, 0x1d);
3561 int cr2a = superio_inb(sioreg, 0x2a);
3562 int cr2b = superio_inb(sioreg, 0x2b);
3563 int cr2d = superio_inb(sioreg, 0x2d);
3564 int cr2f = superio_inb(sioreg, 0x2f);
3565 bool dsw_en = cr2f & BIT(3);
Guenter Roecke41da282018-09-18 20:48:29 -07003566 bool ddr4_en = cr2f & BIT(4);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003567 int cre0;
Guenter Roeck2d888c52018-09-18 09:49:29 -07003568 int creb;
3569 int cred;
3570
3571 superio_select(sioreg, NCT6775_LD_12);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003572 cre0 = superio_inb(sioreg, 0xe0);
Guenter Roeck2d888c52018-09-18 09:49:29 -07003573 creb = superio_inb(sioreg, 0xeb);
3574 cred = superio_inb(sioreg, 0xed);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003575
Guenter Roecka6c54f22018-09-18 09:34:06 -07003576 fan3pin = !(cr1c & BIT(5));
3577 fan4pin = !(cr1c & BIT(6));
3578 fan5pin = !(cr1c & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003579
Guenter Roecka6c54f22018-09-18 09:34:06 -07003580 pwm3pin = !(cr1c & BIT(0));
3581 pwm4pin = !(cr1c & BIT(1));
3582 pwm5pin = !(cr1c & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003583
Guenter Roecke5c85222017-05-17 18:09:41 -07003584 switch (data->kind) {
3585 case nct6791:
Guenter Roecka6c54f22018-09-18 09:34:06 -07003586 fan6pin = cr2d & BIT(1);
3587 pwm6pin = cr2d & BIT(0);
Guenter Roecke5c85222017-05-17 18:09:41 -07003588 break;
Guenter Roeck7dcdbde2018-09-18 10:52:55 -07003589 case nct6792:
3590 fan6pin = !dsw_en && (cr2d & BIT(1));
3591 pwm6pin = !dsw_en && (cr2d & BIT(0));
3592 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003593 case nct6793:
Guenter Roeck2d999252018-09-18 11:03:25 -07003594 fan5pin |= cr1b & BIT(5);
3595 fan5pin |= creb & BIT(5);
3596
Guenter Roeck2a2ec4a2019-01-27 16:08:00 -08003597 fan6pin = !dsw_en && (cr2d & BIT(1));
3598 fan6pin |= creb & BIT(3);
Guenter Roeck2d999252018-09-18 11:03:25 -07003599
3600 pwm5pin |= cr2d & BIT(7);
3601 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3602
3603 pwm6pin = !dsw_en && (cr2d & BIT(0));
3604 pwm6pin |= creb & BIT(2);
3605 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003606 case nct6795:
Guenter Roeckb75a8062018-09-18 11:18:30 -07003607 fan5pin |= cr1b & BIT(5);
3608 fan5pin |= creb & BIT(5);
3609
3610 fan6pin = (cr2a & BIT(4)) &&
3611 (!dsw_en || (cred & BIT(4)));
3612 fan6pin |= creb & BIT(3);
3613
3614 pwm5pin |= cr2d & BIT(7);
3615 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3616
3617 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3618 pwm6pin |= creb & BIT(2);
3619 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003620 case nct6796:
Guenter Roecka4e0a082018-09-18 09:53:06 -07003621 fan5pin |= cr1b & BIT(5);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003622 fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
3623 fan5pin |= creb & BIT(5);
Guenter Roecke5c85222017-05-17 18:09:41 -07003624
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003625 fan6pin = (cr2a & BIT(4)) &&
Guenter Roeck2d999252018-09-18 11:03:25 -07003626 (!dsw_en || (cred & BIT(4)));
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003627 fan6pin |= creb & BIT(3);
Guenter Roeck81820052018-02-21 13:09:39 -08003628
Guenter Roeckb75a8062018-09-18 11:18:30 -07003629 fan7pin = !(cr2b & BIT(2));
Guenter Roeck81820052018-02-21 13:09:39 -08003630
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003631 pwm5pin |= cr2d & BIT(7);
3632 pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
3633 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3634
3635 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3636 pwm6pin |= creb & BIT(2);
3637
3638 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
Guenter Roecke5c85222017-05-17 18:09:41 -07003639 break;
Guenter Roecke41da282018-09-18 20:48:29 -07003640 case nct6797:
3641 fan5pin |= !ddr4_en && (cr1b & BIT(5));
3642 fan5pin |= creb & BIT(5);
3643
3644 fan6pin = cr2a & BIT(4);
3645 fan6pin |= creb & BIT(3);
3646
3647 fan7pin = cr1a & BIT(1);
3648
3649 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3650 pwm5pin |= !ddr4_en && (cr2d & BIT(7));
3651
3652 pwm6pin = creb & BIT(2);
3653 pwm6pin |= cred & BIT(2);
3654
3655 pwm7pin = cr1d & BIT(4);
3656 break;
Guenter Roeck05996822018-09-19 20:26:16 -07003657 case nct6798:
3658 fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
3659 fan6pin |= cr2a & BIT(4);
3660 fan6pin |= creb & BIT(5);
3661
3662 fan7pin = cr1b & BIT(5);
3663 fan7pin |= !(cr2b & BIT(2));
3664 fan7pin |= creb & BIT(3);
3665
3666 pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
3667 pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3));
3668 pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3669
3670 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
3671 pwm7pin |= cr2d & BIT(7);
3672 pwm7pin |= creb & BIT(2);
3673 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003674 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003675 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003676 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003677
3678 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003679 }
3680
David Bartley578ab5f2013-06-24 22:28:28 -07003681 /* fan 1 and 2 (0x03) are always present */
3682 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003683 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003684 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003685 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003686 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003687 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003688}
3689
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003690static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3691 int *available, int *mask)
3692{
3693 int i;
3694 u8 src;
3695
3696 for (i = 0; i < data->pwm_num && *available; i++) {
3697 int index;
3698
3699 if (!regp[i])
3700 continue;
3701 src = nct6775_read_value(data, regp[i]);
3702 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003703 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003704 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003705 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003706 continue;
3707
3708 index = __ffs(*available);
3709 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003710 *available &= ~BIT(index);
3711 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003712 }
3713}
3714
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003715static int nct6775_probe(struct platform_device *pdev)
3716{
3717 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003718 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003719 struct nct6775_data *data;
3720 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003721 int i, s, err = 0;
3722 int src, mask, available;
3723 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003724 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003725 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003726 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003727 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003728 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003729 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003730 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003731
3732 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3733 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3734 DRVNAME))
3735 return -EBUSY;
3736
3737 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3738 GFP_KERNEL);
3739 if (!data)
3740 return -ENOMEM;
3741
3742 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003743 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003744 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003745 mutex_init(&data->update_lock);
3746 data->name = nct6775_device_names[data->kind];
3747 data->bank = 0xff; /* Force initial bank selection */
3748 platform_set_drvdata(pdev, data);
3749
3750 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003751 case nct6106:
3752 data->in_num = 9;
3753 data->pwm_num = 3;
3754 data->auto_pwm_num = 4;
3755 data->temp_fixed_num = 3;
3756 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003757 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003758
3759 data->fan_from_reg = fan_from_reg13;
3760 data->fan_from_reg_min = fan_from_reg13;
3761
3762 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003763 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003764 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003765
3766 data->REG_VBAT = NCT6106_REG_VBAT;
3767 data->REG_DIODE = NCT6106_REG_DIODE;
3768 data->DIODE_MASK = NCT6106_DIODE_MASK;
3769 data->REG_VIN = NCT6106_REG_IN;
3770 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3771 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3772 data->REG_TARGET = NCT6106_REG_TARGET;
3773 data->REG_FAN = NCT6106_REG_FAN;
3774 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3775 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3776 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3777 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3778 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3779 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3780 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3781 data->REG_PWM[0] = NCT6106_REG_PWM;
3782 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3783 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3784 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3785 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3786 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3787 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3788 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3789 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3790 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3791 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3792 data->REG_CRITICAL_TEMP_TOLERANCE
3793 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3794 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3795 data->CRITICAL_PWM_ENABLE_MASK
3796 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3797 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3798 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3799 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3800 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3801 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3802 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3803 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3804 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3805 data->REG_ALARM = NCT6106_REG_ALARM;
3806 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003807 data->REG_BEEP = NCT6106_REG_BEEP;
3808 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003809
3810 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003811 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003812 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003813 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003814 reg_temp_over = NCT6106_REG_TEMP_OVER;
3815 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3816 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3817 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3818 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003819 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3820 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003821
3822 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003823 case nct6775:
3824 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003825 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003826 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003827 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003828 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003829 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003830 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003831
3832 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003833 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003834
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003835 data->fan_from_reg = fan_from_reg16;
3836 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003837 data->target_temp_mask = 0x7f;
3838 data->tolerance_mask = 0x0f;
3839 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003840
Guenter Roeckaa136e52012-12-04 03:26:05 -08003841 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003842 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003843 data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003844
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003845 data->REG_CONFIG = NCT6775_REG_CONFIG;
3846 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003847 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003848 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003849 data->REG_VIN = NCT6775_REG_IN;
3850 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3851 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003852 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003853 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003854 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003855 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003856 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003857 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003858 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3859 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3860 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003861 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003862 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3863 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3864 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3865 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003866 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003867 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3868 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3869 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003870 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3871 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3872 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3873 data->REG_CRITICAL_TEMP_TOLERANCE
3874 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003875 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3876 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003877 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003878 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3879 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3880 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3881 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003882 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003883 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003884
3885 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003886 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003887 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003888 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003889 reg_temp_over = NCT6775_REG_TEMP_OVER;
3890 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3891 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3892 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3893 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3894
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003895 break;
3896 case nct6776:
3897 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003898 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003899 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003900 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003901 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003902 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003903 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003904
3905 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003906 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003907
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003908 data->fan_from_reg = fan_from_reg13;
3909 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003910 data->target_temp_mask = 0xff;
3911 data->tolerance_mask = 0x07;
3912 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003913
Guenter Roeckaa136e52012-12-04 03:26:05 -08003914 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003915 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003916 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003917
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003918 data->REG_CONFIG = NCT6775_REG_CONFIG;
3919 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003920 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003921 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003922 data->REG_VIN = NCT6775_REG_IN;
3923 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3924 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003925 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003926 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003927 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003928 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003929 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003930 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003931 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003932 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3933 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003934 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003935 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003936 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3937 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003938 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3939 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003940 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3941 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3942 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003943 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3944 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3945 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3946 data->REG_CRITICAL_TEMP_TOLERANCE
3947 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003948 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3949 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003950 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003951 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3952 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3953 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3954 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003955 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003956 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003957
3958 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003959 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003960 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003961 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003962 reg_temp_over = NCT6775_REG_TEMP_OVER;
3963 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3964 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3965 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3966 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3967
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003968 break;
3969 case nct6779:
3970 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003971 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003972 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003973 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003974 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003975 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003976 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003977
3978 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003979 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003980
Guenter Roeckf6de2982018-09-13 20:01:12 -07003981 data->fan_from_reg = fan_from_reg_rpm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003982 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003983 data->target_temp_mask = 0xff;
3984 data->tolerance_mask = 0x07;
3985 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003986
Guenter Roeckaa136e52012-12-04 03:26:05 -08003987 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003988 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003989 data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003990
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003991 data->REG_CONFIG = NCT6775_REG_CONFIG;
3992 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003993 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003994 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003995 data->REG_VIN = NCT6779_REG_IN;
3996 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3997 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003998 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003999 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004000 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004001 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004002 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004003 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004004 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004005 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4006 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004007 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004008 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004009 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4010 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004011 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4012 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004013 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4014 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4015 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004016 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4017 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4018 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4019 data->REG_CRITICAL_TEMP_TOLERANCE
4020 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004021 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4022 data->CRITICAL_PWM_ENABLE_MASK
4023 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4024 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004025 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4026 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004027 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004028 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4029 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4030 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4031 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004032 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004033 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004034
4035 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004036 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004037 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004038 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004039 reg_temp_over = NCT6779_REG_TEMP_OVER;
4040 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4041 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4042 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4043 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4044
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004045 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004046 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004047 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004048 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004049 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004050 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004051 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004052 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004053 data->in_num = 15;
Guenter Roecke41da282018-09-18 20:48:29 -07004054 data->pwm_num = (data->kind == nct6796 ||
Guenter Roeck05996822018-09-19 20:26:16 -07004055 data->kind == nct6797 ||
4056 data->kind == nct6798) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07004057 data->auto_pwm_num = 4;
4058 data->has_fan_div = false;
4059 data->temp_fixed_num = 6;
4060 data->num_temp_alarms = 2;
4061 data->num_temp_beeps = 2;
4062
4063 data->ALARM_BITS = NCT6791_ALARM_BITS;
4064 data->BEEP_BITS = NCT6779_BEEP_BITS;
4065
Guenter Roeckf6de2982018-09-13 20:01:12 -07004066 data->fan_from_reg = fan_from_reg_rpm;
David Bartley578ab5f2013-06-24 22:28:28 -07004067 data->fan_from_reg_min = fan_from_reg13;
4068 data->target_temp_mask = 0xff;
4069 data->tolerance_mask = 0x07;
4070 data->speed_tolerance_limit = 63;
4071
Guenter Roeck50224f42015-10-30 07:52:39 -07004072 switch (data->kind) {
4073 default:
4074 case nct6791:
4075 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004076 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004077 data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004078 break;
4079 case nct6792:
4080 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004081 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004082 data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004083 break;
4084 case nct6793:
4085 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004086 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004087 data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004088 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004089 case nct6795:
Guenter Roecke41da282018-09-18 20:48:29 -07004090 case nct6797:
Guenter Roeck419220d2017-05-17 18:19:18 -07004091 data->temp_label = nct6795_temp_label;
4092 data->temp_mask = NCT6795_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004093 data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
Guenter Roeck419220d2017-05-17 18:19:18 -07004094 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004095 case nct6796:
4096 data->temp_label = nct6796_temp_label;
4097 data->temp_mask = NCT6796_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004098 data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
Guenter Roeck81820052018-02-21 13:09:39 -08004099 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004100 case nct6798:
4101 data->temp_label = nct6798_temp_label;
4102 data->temp_mask = NCT6798_TEMP_MASK;
4103 data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
4104 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07004105 }
David Bartley578ab5f2013-06-24 22:28:28 -07004106
4107 data->REG_CONFIG = NCT6775_REG_CONFIG;
4108 data->REG_VBAT = NCT6775_REG_VBAT;
4109 data->REG_DIODE = NCT6775_REG_DIODE;
4110 data->DIODE_MASK = NCT6775_DIODE_MASK;
4111 data->REG_VIN = NCT6779_REG_IN;
4112 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4113 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
4114 data->REG_TARGET = NCT6775_REG_TARGET;
4115 data->REG_FAN = NCT6779_REG_FAN;
4116 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
4117 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
4118 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
4119 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
4120 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004121 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4122 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07004123 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
4124 data->REG_PWM[0] = NCT6775_REG_PWM;
4125 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4126 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004127 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
4128 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004129 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4130 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4131 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
4132 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4133 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4134 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4135 data->REG_CRITICAL_TEMP_TOLERANCE
4136 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
4137 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4138 data->CRITICAL_PWM_ENABLE_MASK
4139 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4140 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
4141 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4142 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4143 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004144 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4145 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4146 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4147 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004148 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004149 if (data->kind == nct6791)
4150 data->REG_BEEP = NCT6776_REG_BEEP;
4151 else
4152 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004153
4154 reg_temp = NCT6779_REG_TEMP;
4155 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004156 if (data->kind == nct6791) {
4157 reg_temp_mon = NCT6779_REG_TEMP_MON;
4158 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4159 } else {
4160 reg_temp_mon = NCT6792_REG_TEMP_MON;
4161 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4162 }
David Bartley578ab5f2013-06-24 22:28:28 -07004163 reg_temp_over = NCT6779_REG_TEMP_OVER;
4164 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4165 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4166 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4167 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4168
4169 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004170 default:
4171 return -ENODEV;
4172 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004173 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004174 data->have_temp = 0;
4175
4176 /*
4177 * On some boards, not all available temperature sources are monitored,
4178 * even though some of the monitoring registers are unused.
4179 * Get list of unused monitoring registers, then detect if any fan
4180 * controls are configured to use unmonitored temperature sources.
4181 * If so, assign the unmonitored temperature sources to available
4182 * monitoring registers.
4183 */
4184 mask = 0;
4185 available = 0;
4186 for (i = 0; i < num_reg_temp; i++) {
4187 if (reg_temp[i] == 0)
4188 continue;
4189
4190 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004191 if (!src || (mask & BIT(src)))
4192 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004193
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004194 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004195 }
4196
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004197 /*
4198 * Now find unmonitored temperature registers and enable monitoring
4199 * if additional monitoring registers are available.
4200 */
4201 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4202 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4203
Guenter Roeckaa136e52012-12-04 03:26:05 -08004204 mask = 0;
4205 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4206 for (i = 0; i < num_reg_temp; i++) {
4207 if (reg_temp[i] == 0)
4208 continue;
4209
4210 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004211 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004212 continue;
4213
Guenter Roeckcc66b302017-05-17 18:05:06 -07004214 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004215 dev_info(dev,
4216 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4217 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4218 continue;
4219 }
4220
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004221 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004222
4223 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4224 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004225 data->have_temp |= BIT(src - 1);
4226 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004227 data->reg_temp[0][src - 1] = reg_temp[i];
4228 data->reg_temp[1][src - 1] = reg_temp_over[i];
4229 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004230 if (reg_temp_crit_h && reg_temp_crit_h[i])
4231 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4232 else if (reg_temp_crit[src - 1])
4233 data->reg_temp[3][src - 1]
4234 = reg_temp_crit[src - 1];
4235 if (reg_temp_crit_l && reg_temp_crit_l[i])
4236 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004237 data->reg_temp_config[src - 1] = reg_temp_config[i];
4238 data->temp_src[src - 1] = src;
4239 continue;
4240 }
4241
4242 if (s >= NUM_TEMP)
4243 continue;
4244
4245 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004246 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004247 data->reg_temp[0][s] = reg_temp[i];
4248 data->reg_temp[1][s] = reg_temp_over[i];
4249 data->reg_temp[2][s] = reg_temp_hyst[i];
4250 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004251 if (reg_temp_crit_h && reg_temp_crit_h[i])
4252 data->reg_temp[3][s] = reg_temp_crit_h[i];
4253 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004254 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004255 if (reg_temp_crit_l && reg_temp_crit_l[i])
4256 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004257
4258 data->temp_src[s] = src;
4259 s++;
4260 }
4261
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004262 /*
4263 * Repeat with temperatures used for fan control.
4264 * This set of registers does not support limits.
4265 */
4266 for (i = 0; i < num_reg_temp_mon; i++) {
4267 if (reg_temp_mon[i] == 0)
4268 continue;
4269
4270 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004271 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004272 continue;
4273
Guenter Roeckcc66b302017-05-17 18:05:06 -07004274 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004275 dev_info(dev,
4276 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4277 src, i, data->REG_TEMP_SEL[i],
4278 reg_temp_mon[i]);
4279 continue;
4280 }
4281
Guenter Roeck7ce41902016-09-11 12:42:52 -07004282 /*
4283 * For virtual temperature sources, the 'virtual' temperature
4284 * for each fan reflects a different temperature, and there
4285 * are no duplicates.
4286 */
Guenter Roeck37196ba2018-09-13 19:43:58 -07004287 if (!(data->virt_temp_mask & BIT(src))) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004288 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004289 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004290 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004291 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004292
4293 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4294 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004295 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004296 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004297 data->have_temp |= BIT(src - 1);
4298 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004299 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4300 data->temp_src[src - 1] = src;
4301 continue;
4302 }
4303
4304 if (s >= NUM_TEMP)
4305 continue;
4306
4307 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004308 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004309 data->reg_temp[0][s] = reg_temp_mon[i];
4310 data->temp_src[s] = src;
4311 s++;
4312 }
4313
Guenter Roeckaa136e52012-12-04 03:26:05 -08004314#ifdef USE_ALTERNATE
4315 /*
4316 * Go through the list of alternate temp registers and enable
4317 * if possible.
4318 * The temperature is already monitored if the respective bit in <mask>
4319 * is set.
4320 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004321 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004322 if (!(data->temp_mask & BIT(i + 1)))
4323 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004324 if (!reg_temp_alternate[i])
4325 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004326 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004327 continue;
4328 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004329 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004330 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004331 data->have_temp |= BIT(i);
4332 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004333 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004334 if (i < num_reg_temp) {
4335 data->reg_temp[1][i] = reg_temp_over[i];
4336 data->reg_temp[2][i] = reg_temp_hyst[i];
4337 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004338 data->temp_src[i] = i + 1;
4339 continue;
4340 }
4341
4342 if (s >= NUM_TEMP) /* Abort if no more space */
4343 break;
4344
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004345 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004346 data->reg_temp[0][s] = reg_temp_alternate[i];
4347 data->temp_src[s] = i + 1;
4348 s++;
4349 }
4350#endif /* USE_ALTERNATE */
4351
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004352 /* Initialize the chip */
4353 nct6775_init_device(data);
4354
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004355 err = superio_enter(sio_data->sioreg);
4356 if (err)
4357 return err;
4358
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004359 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4360 switch (data->kind) {
4361 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004362 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004363 break;
4364 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004365 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004366 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004367 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004368 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004369 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004370 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004371 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004372 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004373 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004374 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004375 case nct6798:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004376 break;
4377 }
4378
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004379 /*
4380 * Read VID value
4381 * We can get the VID input values directly at logical device D 0xe3.
4382 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004383 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004384 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4385 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4386 data->vrm = vid_which_vrm();
4387 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004388
4389 if (fan_debounce) {
4390 u8 tmp;
4391
4392 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4393 tmp = superio_inb(sio_data->sioreg,
4394 NCT6775_REG_CR_FAN_DEBOUNCE);
4395 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004396 case nct6106:
4397 tmp |= 0xe0;
4398 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004399 case nct6775:
4400 tmp |= 0x1e;
4401 break;
4402 case nct6776:
4403 case nct6779:
4404 tmp |= 0x3e;
4405 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004406 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004407 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004408 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004409 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004410 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004411 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004412 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004413 tmp |= 0x7e;
4414 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004415 }
4416 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4417 tmp);
4418 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4419 data->name);
4420 }
4421
Guenter Roeckdf612d52013-07-08 13:15:04 -07004422 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004423
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004424 superio_exit(sio_data->sioreg);
4425
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004426 /* Read fan clock dividers immediately */
4427 nct6775_init_fan_common(dev, data);
4428
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004429 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004430 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4431 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004432 if (IS_ERR(group))
4433 return PTR_ERR(group);
4434
Axel Lin55bdee62014-07-24 08:59:34 +08004435 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004436
Guenter Roeckf73cf632013-03-18 09:22:50 -07004437 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4438 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004439 if (IS_ERR(group))
4440 return PTR_ERR(group);
4441
Axel Lin55bdee62014-07-24 08:59:34 +08004442 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004443
Guenter Roeckf73cf632013-03-18 09:22:50 -07004444 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4445 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004446 if (IS_ERR(group))
4447 return PTR_ERR(group);
4448
Axel Lin55bdee62014-07-24 08:59:34 +08004449 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004450
Guenter Roeckf73cf632013-03-18 09:22:50 -07004451 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4452 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004453 if (IS_ERR(group))
4454 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004455
Axel Lin55bdee62014-07-24 08:59:34 +08004456 data->groups[num_attr_groups++] = group;
4457 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004458
Guenter Roecka150d952013-07-11 22:55:22 -07004459 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4460 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004461 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004462}
4463
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004464static void nct6791_enable_io_mapping(int sioaddr)
4465{
4466 int val;
4467
4468 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4469 if (val & 0x10) {
4470 pr_info("Enabling hardware monitor logical device mappings.\n");
4471 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4472 val & ~0x10);
4473 }
4474}
4475
Guenter Roeck48e93182015-02-07 08:48:49 -08004476static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004477{
4478 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004479
4480 mutex_lock(&data->update_lock);
4481 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004482 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004483 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4484 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4485 }
4486 mutex_unlock(&data->update_lock);
4487
4488 return 0;
4489}
4490
Guenter Roeck48e93182015-02-07 08:48:49 -08004491static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004492{
4493 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004494 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004495 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004496 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004497
4498 mutex_lock(&data->update_lock);
4499 data->bank = 0xff; /* Force initial bank selection */
4500
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004501 err = superio_enter(sioreg);
4502 if (err)
4503 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004504
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004505 superio_select(sioreg, NCT6775_LD_HWM);
4506 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4507 if (reg != data->sio_reg_enable)
4508 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4509
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004510 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004511 data->kind == nct6793 || data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004512 data->kind == nct6796 || data->kind == nct6797 ||
4513 data->kind == nct6798)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004514 nct6791_enable_io_mapping(sioreg);
4515
4516 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004517
Guenter Roeck84d19d92012-12-04 08:01:39 -08004518 /* Restore limits */
4519 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004520 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004521 continue;
4522
4523 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4524 data->in[i][1]);
4525 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4526 data->in[i][2]);
4527 }
4528
Guenter Roeckc409fd42013-04-09 05:04:00 -07004529 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004530 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004531 continue;
4532
4533 nct6775_write_value(data, data->REG_FAN_MIN[i],
4534 data->fan_min[i]);
4535 }
4536
4537 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004538 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004539 continue;
4540
Guenter Roeckc409fd42013-04-09 05:04:00 -07004541 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004542 if (data->reg_temp[j][i])
4543 nct6775_write_temp(data, data->reg_temp[j][i],
4544 data->temp[j][i]);
4545 }
4546
4547 /* Restore other settings */
4548 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004549 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004550 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4551 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4552 }
4553
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004554abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004555 /* Force re-reading all values */
4556 data->valid = false;
4557 mutex_unlock(&data->update_lock);
4558
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004559 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004560}
4561
Guenter Roeck48e93182015-02-07 08:48:49 -08004562static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004563
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004564static struct platform_driver nct6775_driver = {
4565 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004566 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004567 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004568 },
4569 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004570};
4571
4572/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004573static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004574{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004575 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004576 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004577 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004578
4579 err = superio_enter(sioaddr);
4580 if (err)
4581 return err;
4582
Guenter Roeckfc72af32016-08-03 22:07:18 -07004583 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4584 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4585 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004586 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004587
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004588 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004589 case SIO_NCT6106_ID:
4590 sio_data->kind = nct6106;
4591 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004592 case SIO_NCT6775_ID:
4593 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004594 break;
4595 case SIO_NCT6776_ID:
4596 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004597 break;
4598 case SIO_NCT6779_ID:
4599 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004600 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004601 case SIO_NCT6791_ID:
4602 sio_data->kind = nct6791;
4603 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004604 case SIO_NCT6792_ID:
4605 sio_data->kind = nct6792;
4606 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004607 case SIO_NCT6793_ID:
4608 sio_data->kind = nct6793;
4609 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004610 case SIO_NCT6795_ID:
4611 sio_data->kind = nct6795;
4612 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004613 case SIO_NCT6796_ID:
4614 sio_data->kind = nct6796;
4615 break;
Guenter Roecke41da282018-09-18 20:48:29 -07004616 case SIO_NCT6797_ID:
4617 sio_data->kind = nct6797;
4618 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004619 case SIO_NCT6798_ID:
4620 sio_data->kind = nct6798;
4621 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004622 default:
4623 if (val != 0xffff)
4624 pr_debug("unsupported chip ID: 0x%04x\n", val);
4625 superio_exit(sioaddr);
4626 return -ENODEV;
4627 }
4628
4629 /* We have a known chip, find the HWM I/O address */
4630 superio_select(sioaddr, NCT6775_LD_HWM);
4631 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4632 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004633 addr = val & IOREGION_ALIGNMENT;
4634 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004635 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4636 superio_exit(sioaddr);
4637 return -ENODEV;
4638 }
4639
4640 /* Activate logical device if needed */
4641 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4642 if (!(val & 0x01)) {
4643 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4644 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4645 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004646
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004647 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004648 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004649 sio_data->kind == nct6796 || sio_data->kind == nct6797 ||
4650 sio_data->kind == nct6798)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004651 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004652
4653 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004654 pr_info("Found %s or compatible chip at %#x:%#x\n",
4655 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004656 sio_data->sioreg = sioaddr;
4657
Guenter Roeck698a7c22013-04-05 07:35:25 -07004658 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004659}
4660
4661/*
4662 * when Super-I/O functions move to a separate file, the Super-I/O
4663 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004664 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004665 * must keep track of the device
4666 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004667static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004668
4669static int __init sensors_nct6775_init(void)
4670{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004671 int i, err;
4672 bool found = false;
4673 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004674 struct resource res;
4675 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004676 int sioaddr[2] = { 0x2e, 0x4e };
4677
4678 err = platform_driver_register(&nct6775_driver);
4679 if (err)
4680 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004681
4682 /*
4683 * initialize sio_data->kind and sio_data->sioreg.
4684 *
4685 * when Super-I/O functions move to a separate file, the Super-I/O
4686 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4687 * nct6775 hardware monitor, and call probe()
4688 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004689 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4690 address = nct6775_find(sioaddr[i], &sio_data);
4691 if (address <= 0)
4692 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004693
Guenter Roeck698a7c22013-04-05 07:35:25 -07004694 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004695
Guenter Roeck698a7c22013-04-05 07:35:25 -07004696 pdev[i] = platform_device_alloc(DRVNAME, address);
4697 if (!pdev[i]) {
4698 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004699 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004700 }
4701
4702 err = platform_device_add_data(pdev[i], &sio_data,
4703 sizeof(struct nct6775_sio_data));
4704 if (err)
4705 goto exit_device_put;
4706
4707 memset(&res, 0, sizeof(res));
4708 res.name = DRVNAME;
4709 res.start = address + IOREGION_OFFSET;
4710 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4711 res.flags = IORESOURCE_IO;
4712
4713 err = acpi_check_resource_conflict(&res);
4714 if (err) {
4715 platform_device_put(pdev[i]);
4716 pdev[i] = NULL;
4717 continue;
4718 }
4719
4720 err = platform_device_add_resources(pdev[i], &res, 1);
4721 if (err)
4722 goto exit_device_put;
4723
4724 /* platform_device_add calls probe() */
4725 err = platform_device_add(pdev[i]);
4726 if (err)
4727 goto exit_device_put;
4728 }
4729 if (!found) {
4730 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004731 goto exit_unregister;
4732 }
4733
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004734 return 0;
4735
4736exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004737 platform_device_put(pdev[i]);
4738exit_device_unregister:
4739 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004740 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004741 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004742 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004743exit_unregister:
4744 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004745 return err;
4746}
4747
4748static void __exit sensors_nct6775_exit(void)
4749{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004750 int i;
4751
4752 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4753 if (pdev[i])
4754 platform_device_unregister(pdev[i]);
4755 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004756 platform_driver_unregister(&nct6775_driver);
4757}
4758
4759MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004760MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004761MODULE_LICENSE("GPL");
4762
4763module_init(sensors_nct6775_init);
4764module_exit(sensors_nct6775_exit);