blob: bd1c4772994aa932ea826db20ee7c3216f198fb8 [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 Roeck9de2e2e2012-05-20 19:29:48 -070045 *
46 * #temp lists the number of monitored temperature sources (first value) plus
47 * the number of directly connectable temperature sensors (second value).
48 */
49
50#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51
52#include <linux/module.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/jiffies.h>
56#include <linux/platform_device.h>
57#include <linux/hwmon.h>
58#include <linux/hwmon-sysfs.h>
59#include <linux/hwmon-vid.h>
60#include <linux/err.h>
61#include <linux/mutex.h>
62#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070063#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080064#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070065#include <linux/io.h>
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -050066#include <linux/nospec.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070067#include "lm75.h"
68
Guenter Roeckaa136e52012-12-04 03:26:05 -080069#define USE_ALTERNATE
70
Guenter Roeck419220d2017-05-17 18:19:18 -070071enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
Guenter Roeck81820052018-02-21 13:09:39 -080072 nct6795, nct6796 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070073
74/* used to set data->name = nct6775_device_names[data->sio_kind] */
75static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070076 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070077 "nct6775",
78 "nct6776",
79 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070080 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080081 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070082 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070083 "nct6795",
Guenter Roeck81820052018-02-21 13:09:39 -080084 "nct6796",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070085};
86
87static const char * const nct6775_sio_names[] __initconst = {
88 "NCT6106D",
89 "NCT6775F",
90 "NCT6776D/F",
91 "NCT6779D",
92 "NCT6791D",
93 "NCT6792D",
94 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -070095 "NCT6795D",
Guenter Roeck81820052018-02-21 13:09:39 -080096 "NCT6796D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070097};
98
99static unsigned short force_id;
100module_param(force_id, ushort, 0);
101MODULE_PARM_DESC(force_id, "Override the detected device ID");
102
Guenter Roeck47ece962012-12-04 07:59:32 -0800103static unsigned short fan_debounce;
104module_param(fan_debounce, ushort, 0);
105MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
106
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700107#define DRVNAME "nct6775"
108
109/*
110 * Super-I/O constants and functions
111 */
112
Guenter Roecka6bd5872012-12-04 03:13:34 -0800113#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114#define NCT6775_LD_HWM 0x0b
115#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700116#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700117
118#define SIO_REG_LDSEL 0x07 /* Logical device select */
119#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
120#define SIO_REG_ENABLE 0x30 /* Logical device enable */
121#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
122
Guenter Roeck6c009502012-07-01 08:23:15 -0700123#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700124#define SIO_NCT6775_ID 0xb470
125#define SIO_NCT6776_ID 0xc330
126#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700127#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800128#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700129#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700130#define SIO_NCT6795_ID 0xd350
Guenter Roeck81820052018-02-21 13:09:39 -0800131#define SIO_NCT6796_ID 0xd420
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700132#define SIO_ID_MASK 0xFFF0
133
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800134enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
135
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700136static inline void
137superio_outb(int ioreg, int reg, int val)
138{
139 outb(reg, ioreg);
140 outb(val, ioreg + 1);
141}
142
143static inline int
144superio_inb(int ioreg, int reg)
145{
146 outb(reg, ioreg);
147 return inb(ioreg + 1);
148}
149
150static inline void
151superio_select(int ioreg, int ld)
152{
153 outb(SIO_REG_LDSEL, ioreg);
154 outb(ld, ioreg + 1);
155}
156
157static inline int
158superio_enter(int ioreg)
159{
160 /*
161 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
162 */
163 if (!request_muxed_region(ioreg, 2, DRVNAME))
164 return -EBUSY;
165
166 outb(0x87, ioreg);
167 outb(0x87, ioreg);
168
169 return 0;
170}
171
172static inline void
173superio_exit(int ioreg)
174{
175 outb(0xaa, ioreg);
176 outb(0x02, ioreg);
177 outb(0x02, ioreg + 1);
178 release_region(ioreg, 2);
179}
180
181/*
182 * ISA constants
183 */
184
185#define IOREGION_ALIGNMENT (~7)
186#define IOREGION_OFFSET 5
187#define IOREGION_LENGTH 2
188#define ADDR_REG_OFFSET 0
189#define DATA_REG_OFFSET 1
190
191#define NCT6775_REG_BANK 0x4E
192#define NCT6775_REG_CONFIG 0x40
193
194/*
195 * Not currently used:
196 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
197 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
198 * REG_MAN_ID is at port 0x4f
199 * REG_CHIP_ID is at port 0x58
200 */
201
Guenter Roeckaa136e52012-12-04 03:26:05 -0800202#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
203#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
204
Guenter Roeck6c009502012-07-01 08:23:15 -0700205#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700206#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700207
Guenter Roeck81820052018-02-21 13:09:39 -0800208#define NUM_FAN 7
David Bartley578ab5f2013-06-24 22:28:28 -0700209
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700210/* Common and NCT6775 specific data */
211
212/* Voltage min/max registers for nr=7..14 are in bank 5 */
213
214static const u16 NCT6775_REG_IN_MAX[] = {
215 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
216 0x55c, 0x55e, 0x560, 0x562 };
217static const u16 NCT6775_REG_IN_MIN[] = {
218 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
219 0x55d, 0x55f, 0x561, 0x563 };
220static const u16 NCT6775_REG_IN[] = {
221 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
222};
223
224#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800225#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700226#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700227
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800228#define NCT6775_REG_FANDIV1 0x506
229#define NCT6775_REG_FANDIV2 0x507
230
Guenter Roeck47ece962012-12-04 07:59:32 -0800231#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
232
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700233static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
234
Guenter Roeck30846992013-06-24 22:21:59 -0700235/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700236
237static const s8 NCT6775_ALARM_BITS[] = {
238 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
239 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
240 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700241 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700242 -1, -1, -1, /* unused */
243 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
244 12, -1 }; /* intrusion0, intrusion1 */
245
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800246#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800247#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800248#define INTRUSION_ALARM_BASE 30
249
Guenter Roeck30846992013-06-24 22:21:59 -0700250static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
251
252/*
253 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
254 * 30..31 intrusion
255 */
256static const s8 NCT6775_BEEP_BITS[] = {
257 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
258 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
259 21, /* global beep enable */
260 6, 7, 11, 28, -1, /* fan1..fan5 */
261 -1, -1, -1, /* unused */
262 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
263 12, -1 }; /* intrusion0, intrusion1 */
264
265#define BEEP_ENABLE_BASE 15
266
Guenter Roecka6bd5872012-12-04 03:13:34 -0800267static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
268static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
269
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800270/* DC or PWM output fan configuration */
271static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
272static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
273
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800274/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800275
David Bartley578ab5f2013-06-24 22:28:28 -0700276static const u16 NCT6775_REG_TARGET[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800277 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
David Bartley578ab5f2013-06-24 22:28:28 -0700278static const u16 NCT6775_REG_FAN_MODE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800279 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800280static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800281 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800282static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800283 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800284static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800285 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
David Bartley578ab5f2013-06-24 22:28:28 -0700286static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800287 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800288static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
289static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
290
291static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800292 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
David Bartley578ab5f2013-06-24 22:28:28 -0700293static const u16 NCT6775_REG_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800294 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
David Bartley578ab5f2013-06-24 22:28:28 -0700295static const u16 NCT6775_REG_PWM_READ[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800296 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800297
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800298static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
299static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeckc7932792018-09-06 09:47:51 -0700300static const u16 NCT6775_REG_FAN_PULSES[NUM_FAN] = {
301 0x641, 0x642, 0x643, 0x644 };
302static const u16 NCT6775_FAN_PULSE_SHIFT[NUM_FAN] = { };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800303
Guenter Roeckaa136e52012-12-04 03:26:05 -0800304static const u16 NCT6775_REG_TEMP[] = {
305 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
306
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800307static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
308
Guenter Roeckaa136e52012-12-04 03:26:05 -0800309static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
310 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
311static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
312 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
313static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
314 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
315
316static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
317 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
318
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800319static const u16 NCT6775_REG_TEMP_SEL[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800320 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800321
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800322static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700323 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800324static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700325 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800326static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700327 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800328static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700329 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800330static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700331 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800332
Guenter Roeckaa136e52012-12-04 03:26:05 -0800333static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
334
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800335static const u16 NCT6775_REG_AUTO_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800336 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800337static const u16 NCT6775_REG_AUTO_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800338 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800339
340#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
341#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
342
343static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
344
345static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800346 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800347static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800348 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800349
Guenter Roeckaa136e52012-12-04 03:26:05 -0800350static const char *const nct6775_temp_label[] = {
351 "",
352 "SYSTIN",
353 "CPUTIN",
354 "AUXTIN",
355 "AMD SB-TSI",
356 "PECI Agent 0",
357 "PECI Agent 1",
358 "PECI Agent 2",
359 "PECI Agent 3",
360 "PECI Agent 4",
361 "PECI Agent 5",
362 "PECI Agent 6",
363 "PECI Agent 7",
364 "PCH_CHIP_CPU_MAX_TEMP",
365 "PCH_CHIP_TEMP",
366 "PCH_CPU_TEMP",
367 "PCH_MCH_TEMP",
368 "PCH_DIM0_TEMP",
369 "PCH_DIM1_TEMP",
370 "PCH_DIM2_TEMP",
371 "PCH_DIM3_TEMP"
372};
373
Guenter Roeckcc66b302017-05-17 18:05:06 -0700374#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700375#define NCT6775_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800376
Guenter Roeckcc66b302017-05-17 18:05:06 -0700377static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
378 [13] = 0x661,
379 [14] = 0x662,
380 [15] = 0x664,
381};
382
383static const u16 NCT6775_REG_TEMP_CRIT[32] = {
384 [4] = 0xa00,
385 [5] = 0xa01,
386 [6] = 0xa02,
387 [7] = 0xa03,
388 [8] = 0xa04,
389 [9] = 0xa05,
390 [10] = 0xa06,
391 [11] = 0xa07
392};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800393
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700394/* NCT6776 specific data */
395
Guenter Roeck728d2942015-08-31 16:13:47 -0700396/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
397#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
398#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
399
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700400static const s8 NCT6776_ALARM_BITS[] = {
401 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
402 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
403 -1, /* unused */
404 6, 7, 11, 10, 23, /* fan1..fan5 */
405 -1, -1, -1, /* unused */
406 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
407 12, 9 }; /* intrusion0, intrusion1 */
408
Guenter Roeck30846992013-06-24 22:21:59 -0700409static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
410
411static const s8 NCT6776_BEEP_BITS[] = {
412 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
413 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
414 24, /* global beep enable */
415 25, 26, 27, 28, 29, /* fan1..fan5 */
416 -1, -1, -1, /* unused */
417 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
418 30, 31 }; /* intrusion0, intrusion1 */
419
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800420static const u16 NCT6776_REG_TOLERANCE_H[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800421 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800422
David Bartley578ab5f2013-06-24 22:28:28 -0700423static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
424static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800425
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800426static const u16 NCT6776_REG_FAN_MIN[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800427 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
Guenter Roeckc7932792018-09-06 09:47:51 -0700428static const u16 NCT6776_REG_FAN_PULSES[NUM_FAN] = {
429 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800430
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800431static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700432 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800433
Guenter Roeckaa136e52012-12-04 03:26:05 -0800434static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
435 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
436
437static const char *const nct6776_temp_label[] = {
438 "",
439 "SYSTIN",
440 "CPUTIN",
441 "AUXTIN",
442 "SMBUSMASTER 0",
443 "SMBUSMASTER 1",
444 "SMBUSMASTER 2",
445 "SMBUSMASTER 3",
446 "SMBUSMASTER 4",
447 "SMBUSMASTER 5",
448 "SMBUSMASTER 6",
449 "SMBUSMASTER 7",
450 "PECI Agent 0",
451 "PECI Agent 1",
452 "PCH_CHIP_CPU_MAX_TEMP",
453 "PCH_CHIP_TEMP",
454 "PCH_CPU_TEMP",
455 "PCH_MCH_TEMP",
456 "PCH_DIM0_TEMP",
457 "PCH_DIM1_TEMP",
458 "PCH_DIM2_TEMP",
459 "PCH_DIM3_TEMP",
460 "BYTE_TEMP"
461};
462
Guenter Roeckcc66b302017-05-17 18:05:06 -0700463#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700464#define NCT6776_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800465
Guenter Roeckcc66b302017-05-17 18:05:06 -0700466static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
467 [14] = 0x401,
468 [15] = 0x402,
469 [16] = 0x404,
470};
471
472static const u16 NCT6776_REG_TEMP_CRIT[32] = {
473 [11] = 0x709,
474 [12] = 0x70a,
475};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800476
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700477/* NCT6779 specific data */
478
479static const u16 NCT6779_REG_IN[] = {
480 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
481 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
482
483static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
484 0x459, 0x45A, 0x45B, 0x568 };
485
486static const s8 NCT6779_ALARM_BITS[] = {
487 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
488 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
489 -1, /* unused */
490 6, 7, 11, 10, 23, /* fan1..fan5 */
491 -1, -1, -1, /* unused */
492 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
493 12, 9 }; /* intrusion0, intrusion1 */
494
Guenter Roeck30846992013-06-24 22:21:59 -0700495static const s8 NCT6779_BEEP_BITS[] = {
496 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
497 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
498 24, /* global beep enable */
499 25, 26, 27, 28, 29, /* fan1..fan5 */
500 -1, -1, -1, /* unused */
501 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
502 30, 31 }; /* intrusion0, intrusion1 */
503
David Bartley578ab5f2013-06-24 22:28:28 -0700504static const u16 NCT6779_REG_FAN[] = {
Guenter Roeck55066352018-09-17 05:23:58 -0700505 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
Guenter Roeckc7932792018-09-06 09:47:51 -0700506static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
507 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800508
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800509static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800510 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700511#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800512static const u16 NCT6779_REG_CRITICAL_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800513 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800514
Guenter Roeckaa136e52012-12-04 03:26:05 -0800515static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800516static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800517static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
518 0x18, 0x152 };
519static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
520 0x3a, 0x153 };
521static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
522 0x39, 0x155 };
523
524static const u16 NCT6779_REG_TEMP_OFFSET[] = {
525 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
526
527static const char *const nct6779_temp_label[] = {
528 "",
529 "SYSTIN",
530 "CPUTIN",
531 "AUXTIN0",
532 "AUXTIN1",
533 "AUXTIN2",
534 "AUXTIN3",
535 "",
536 "SMBUSMASTER 0",
537 "SMBUSMASTER 1",
538 "SMBUSMASTER 2",
539 "SMBUSMASTER 3",
540 "SMBUSMASTER 4",
541 "SMBUSMASTER 5",
542 "SMBUSMASTER 6",
543 "SMBUSMASTER 7",
544 "PECI Agent 0",
545 "PECI Agent 1",
546 "PCH_CHIP_CPU_MAX_TEMP",
547 "PCH_CHIP_TEMP",
548 "PCH_CPU_TEMP",
549 "PCH_MCH_TEMP",
550 "PCH_DIM0_TEMP",
551 "PCH_DIM1_TEMP",
552 "PCH_DIM2_TEMP",
553 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700554 "BYTE_TEMP",
555 "",
556 "",
557 "",
558 "",
559 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800560};
561
Guenter Roeckcc66b302017-05-17 18:05:06 -0700562#define NCT6779_TEMP_MASK 0x07ffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700563#define NCT6779_VIRT_TEMP_MASK 0x00000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700564#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700565#define NCT6791_VIRT_TEMP_MASK 0x80000000
Guenter Roeck9a383712015-08-29 15:29:25 -0700566
Guenter Roeckcc66b302017-05-17 18:05:06 -0700567static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800568 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
569 0, 0, 0, 0, 0, 0, 0, 0,
570 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
571 0x408, 0 };
572
Guenter Roeckcc66b302017-05-17 18:05:06 -0700573static const u16 NCT6779_REG_TEMP_CRIT[32] = {
574 [15] = 0x709,
575 [16] = 0x70a,
576};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800577
David Bartley578ab5f2013-06-24 22:28:28 -0700578/* NCT6791 specific data */
579
580#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
581
Guenter Roecke2617262018-02-21 13:09:36 -0800582static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
583static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
584static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
585static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
586static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
587static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800588
David Bartley578ab5f2013-06-24 22:28:28 -0700589static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
590 0x459, 0x45A, 0x45B, 0x568, 0x45D };
591
592static const s8 NCT6791_ALARM_BITS[] = {
593 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
594 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
595 -1, /* unused */
596 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
597 -1, -1, /* unused */
598 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
599 12, 9 }; /* intrusion0, intrusion1 */
600
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700601/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800602
603static const u16 NCT6792_REG_TEMP_MON[] = {
604 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
605static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
606 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700607
Guenter Roeck50224f42015-10-30 07:52:39 -0700608static const char *const nct6792_temp_label[] = {
609 "",
610 "SYSTIN",
611 "CPUTIN",
612 "AUXTIN0",
613 "AUXTIN1",
614 "AUXTIN2",
615 "AUXTIN3",
616 "",
617 "SMBUSMASTER 0",
618 "SMBUSMASTER 1",
619 "SMBUSMASTER 2",
620 "SMBUSMASTER 3",
621 "SMBUSMASTER 4",
622 "SMBUSMASTER 5",
623 "SMBUSMASTER 6",
624 "SMBUSMASTER 7",
625 "PECI Agent 0",
626 "PECI Agent 1",
627 "PCH_CHIP_CPU_MAX_TEMP",
628 "PCH_CHIP_TEMP",
629 "PCH_CPU_TEMP",
630 "PCH_MCH_TEMP",
631 "PCH_DIM0_TEMP",
632 "PCH_DIM1_TEMP",
633 "PCH_DIM2_TEMP",
634 "PCH_DIM3_TEMP",
635 "BYTE_TEMP",
636 "PECI Agent 0 Calibration",
637 "PECI Agent 1 Calibration",
638 "",
639 "",
640 "Virtual_TEMP"
641};
642
Guenter Roeckcc66b302017-05-17 18:05:06 -0700643#define NCT6792_TEMP_MASK 0x9fffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700644#define NCT6792_VIRT_TEMP_MASK 0x80000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700645
Guenter Roeck50224f42015-10-30 07:52:39 -0700646static const char *const nct6793_temp_label[] = {
647 "",
648 "SYSTIN",
649 "CPUTIN",
650 "AUXTIN0",
651 "AUXTIN1",
652 "AUXTIN2",
653 "AUXTIN3",
654 "",
655 "SMBUSMASTER 0",
656 "SMBUSMASTER 1",
657 "",
658 "",
659 "",
660 "",
661 "",
662 "",
663 "PECI Agent 0",
664 "PECI Agent 1",
665 "PCH_CHIP_CPU_MAX_TEMP",
666 "PCH_CHIP_TEMP",
667 "PCH_CPU_TEMP",
668 "PCH_MCH_TEMP",
669 "Agent0 Dimm0 ",
670 "Agent0 Dimm1",
671 "Agent1 Dimm0",
672 "Agent1 Dimm1",
673 "BYTE_TEMP0",
674 "BYTE_TEMP1",
675 "PECI Agent 0 Calibration",
676 "PECI Agent 1 Calibration",
677 "",
678 "Virtual_TEMP"
679};
680
Guenter Roeckcc66b302017-05-17 18:05:06 -0700681#define NCT6793_TEMP_MASK 0xbfff037e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700682#define NCT6793_VIRT_TEMP_MASK 0x80000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700683
Guenter Roeck419220d2017-05-17 18:19:18 -0700684static const char *const nct6795_temp_label[] = {
685 "",
686 "SYSTIN",
687 "CPUTIN",
688 "AUXTIN0",
689 "AUXTIN1",
690 "AUXTIN2",
691 "AUXTIN3",
692 "",
693 "SMBUSMASTER 0",
694 "SMBUSMASTER 1",
695 "SMBUSMASTER 2",
696 "SMBUSMASTER 3",
697 "SMBUSMASTER 4",
698 "SMBUSMASTER 5",
699 "SMBUSMASTER 6",
700 "SMBUSMASTER 7",
701 "PECI Agent 0",
702 "PECI Agent 1",
703 "PCH_CHIP_CPU_MAX_TEMP",
704 "PCH_CHIP_TEMP",
705 "PCH_CPU_TEMP",
706 "PCH_MCH_TEMP",
707 "PCH_DIM0_TEMP",
708 "PCH_DIM1_TEMP",
709 "PCH_DIM2_TEMP",
710 "PCH_DIM3_TEMP",
711 "BYTE_TEMP0",
712 "BYTE_TEMP1",
713 "PECI Agent 0 Calibration",
714 "PECI Agent 1 Calibration",
715 "",
716 "Virtual_TEMP"
717};
718
719#define NCT6795_TEMP_MASK 0xbfffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700720#define NCT6795_VIRT_TEMP_MASK 0x80000000
Guenter Roeck419220d2017-05-17 18:19:18 -0700721
Guenter Roeck81820052018-02-21 13:09:39 -0800722static const char *const nct6796_temp_label[] = {
723 "",
724 "SYSTIN",
725 "CPUTIN",
726 "AUXTIN0",
727 "AUXTIN1",
728 "AUXTIN2",
729 "AUXTIN3",
730 "AUXTIN4",
731 "SMBUSMASTER 0",
732 "SMBUSMASTER 1",
Guenter Roeck37196ba2018-09-13 19:43:58 -0700733 "Virtual_TEMP",
734 "Virtual_TEMP",
Guenter Roeck81820052018-02-21 13:09:39 -0800735 "",
736 "",
737 "",
738 "",
739 "PECI Agent 0",
740 "PECI Agent 1",
741 "PCH_CHIP_CPU_MAX_TEMP",
742 "PCH_CHIP_TEMP",
743 "PCH_CPU_TEMP",
744 "PCH_MCH_TEMP",
745 "PCH_DIM0_TEMP",
746 "PCH_DIM1_TEMP",
747 "PCH_DIM2_TEMP",
748 "PCH_DIM3_TEMP",
749 "BYTE_TEMP0",
750 "BYTE_TEMP1",
751 "PECI Agent 0 Calibration",
752 "PECI Agent 1 Calibration",
753 "",
754 "Virtual_TEMP"
755};
756
Guenter Roeck37196ba2018-09-13 19:43:58 -0700757#define NCT6796_TEMP_MASK 0xbfff0ffe
758#define NCT6796_VIRT_TEMP_MASK 0x80000c00
Guenter Roeck81820052018-02-21 13:09:39 -0800759
Guenter Roeck6c009502012-07-01 08:23:15 -0700760/* NCT6102D/NCT6106D specific data */
761
762#define NCT6106_REG_VBAT 0x318
763#define NCT6106_REG_DIODE 0x319
764#define NCT6106_DIODE_MASK 0x01
765
766static const u16 NCT6106_REG_IN_MAX[] = {
767 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
768static const u16 NCT6106_REG_IN_MIN[] = {
769 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
770static const u16 NCT6106_REG_IN[] = {
771 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
772
773static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800774static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700775static const u16 NCT6106_REG_TEMP_HYST[] = {
776 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
777static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700778 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
779static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
780 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
781static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
782 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700783static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
784static const u16 NCT6106_REG_TEMP_CONFIG[] = {
785 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
786
787static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
788static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
Guenter Roeckc7932792018-09-06 09:47:51 -0700789static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6 };
790static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700791
792static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
793static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
794static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
795static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
796static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
797static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
798static const u16 NCT6106_REG_TEMP_SOURCE[] = {
799 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
800
801static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
802static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
803 0x11b, 0x12b, 0x13b };
804
805static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
806#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
807static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
808
809static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
810static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
811static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
812static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
813static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
814static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
815
816static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
817
818static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
819static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
820static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
821static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
822static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
823static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
824
825static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
826static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
827
828static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
829 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
830
831static const s8 NCT6106_ALARM_BITS[] = {
832 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
833 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
834 -1, /* unused */
835 32, 33, 34, -1, -1, /* fan1..fan5 */
836 -1, -1, -1, /* unused */
837 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
838 48, -1 /* intrusion0, intrusion1 */
839};
840
Guenter Roeck30846992013-06-24 22:21:59 -0700841static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
842 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
843
844static const s8 NCT6106_BEEP_BITS[] = {
845 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
846 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
847 32, /* global beep enable */
848 24, 25, 26, 27, 28, /* fan1..fan5 */
849 -1, -1, -1, /* unused */
850 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
851 34, -1 /* intrusion0, intrusion1 */
852};
853
Guenter Roeckcc66b302017-05-17 18:05:06 -0700854static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
855 [14] = 0x51,
856 [15] = 0x52,
857 [16] = 0x54,
858};
Guenter Roeck6c009502012-07-01 08:23:15 -0700859
Guenter Roeckcc66b302017-05-17 18:05:06 -0700860static const u16 NCT6106_REG_TEMP_CRIT[32] = {
861 [11] = 0x204,
862 [12] = 0x205,
863};
Guenter Roeck6c009502012-07-01 08:23:15 -0700864
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800865static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
866{
867 if (mode == 0 && pwm == 255)
868 return off;
869 return mode + 1;
870}
871
872static int pwm_enable_to_reg(enum pwm_enable mode)
873{
874 if (mode == off)
875 return 0;
876 return mode - 1;
877}
878
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700879/*
880 * Conversions
881 */
882
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800883/* 1 is DC mode, output in ms */
884static unsigned int step_time_from_reg(u8 reg, u8 mode)
885{
886 return mode ? 400 * reg : 100 * reg;
887}
888
889static u8 step_time_to_reg(unsigned int msec, u8 mode)
890{
891 return clamp_val((mode ? (msec + 200) / 400 :
892 (msec + 50) / 100), 1, 255);
893}
894
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800895static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
896{
897 if (reg == 0 || reg == 255)
898 return 0;
899 return 1350000U / (reg << divreg);
900}
901
902static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
903{
904 if ((reg & 0xff1f) == 0xff1f)
905 return 0;
906
907 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
908
909 if (reg == 0)
910 return 0;
911
912 return 1350000U / reg;
913}
914
915static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
916{
917 if (reg == 0 || reg == 0xffff)
918 return 0;
919
920 /*
921 * Even though the registers are 16 bit wide, the fan divisor
922 * still applies.
923 */
924 return 1350000U / (reg << divreg);
925}
926
Guenter Roeckf6de2982018-09-13 20:01:12 -0700927static unsigned int fan_from_reg_rpm(u16 reg, unsigned int divreg)
928{
929 return reg;
930}
931
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800932static u16 fan_to_reg(u32 fan, unsigned int divreg)
933{
934 if (!fan)
935 return 0;
936
937 return (1350000U / fan) >> divreg;
938}
939
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800940static inline unsigned int
941div_from_reg(u8 reg)
942{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700943 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800944}
945
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700946/*
947 * Some of the voltage inputs have internal scaling, the tables below
948 * contain 8 (the ADC LSB in mV) * scaling factor * 100
949 */
950static const u16 scale_in[15] = {
951 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
952 800, 800
953};
954
955static inline long in_from_reg(u8 reg, u8 nr)
956{
957 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
958}
959
960static inline u8 in_to_reg(u32 val, u8 nr)
961{
962 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
963}
964
965/*
966 * Data structures and manipulation thereof
967 */
968
969struct nct6775_data {
970 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700971 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700972 enum kinds kind;
973 const char *name;
974
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700975 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700976
Guenter Roeckb7a61352013-04-02 22:14:06 -0700977 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
978 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800979 */
980 u8 temp_src[NUM_TEMP];
981 u16 reg_temp_config[NUM_TEMP];
982 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700983 u32 temp_mask;
Guenter Roeck37196ba2018-09-13 19:43:58 -0700984 u32 virt_temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800985
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700986 u16 REG_CONFIG;
987 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800988 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700989 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700990
991 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700992 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700993
994 const u16 *REG_VIN;
995 const u16 *REG_IN_MINMAX[2];
996
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800997 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800998 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800999 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001000 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001001 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07001002 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001003 const u16 *REG_FAN_TIME[3];
1004
1005 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001006
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001007 const u8 *REG_PWM_MODE;
1008 const u8 *PWM_MODE_MASK;
1009
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001010 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1011 * [3]=pwm_max, [4]=pwm_step,
1012 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001013 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001014 const u16 *REG_PWM_READ;
1015
Guenter Roeck6c009502012-07-01 08:23:15 -07001016 const u16 *REG_CRITICAL_PWM_ENABLE;
1017 u8 CRITICAL_PWM_ENABLE_MASK;
1018 const u16 *REG_CRITICAL_PWM;
1019
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001020 const u16 *REG_AUTO_TEMP;
1021 const u16 *REG_AUTO_PWM;
1022
1023 const u16 *REG_CRITICAL_TEMP;
1024 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
1025
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001026 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001027 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001028 const u16 *REG_WEIGHT_TEMP_SEL;
1029 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
1030
Guenter Roeckaa136e52012-12-04 03:26:05 -08001031 const u16 *REG_TEMP_OFFSET;
1032
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001033 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07001034 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001035
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001036 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
1037 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
1038
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001039 struct mutex update_lock;
1040 bool valid; /* true if following fields are valid */
1041 unsigned long last_updated; /* In jiffies */
1042
1043 /* Register values */
1044 u8 bank; /* current register bank */
1045 u8 in_num; /* number of in inputs we have */
1046 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -07001047 unsigned int rpm[NUM_FAN];
1048 u16 fan_min[NUM_FAN];
1049 u8 fan_pulses[NUM_FAN];
1050 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001051 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001052 u8 has_fan; /* some fan inputs can be disabled */
1053 u8 has_fan_min; /* some fans don't have min register */
1054 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001055
Guenter Roeck6c009502012-07-01 08:23:15 -07001056 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001057 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001058 u8 temp_fixed_num; /* 3 or 6 */
1059 u8 temp_type[NUM_TEMP_FIXED];
1060 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001061 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1062 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001063 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001064 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001065
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001066 u8 pwm_num; /* number of pwm */
Guenter Roeck57fec3a2018-06-18 09:21:46 -07001067 u8 pwm_mode[NUM_FAN]; /* 0->DC variable voltage,
1068 * 1->PWM variable duty cycle
David Bartley578ab5f2013-06-24 22:28:28 -07001069 */
1070 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001071 /* 0->off
1072 * 1->manual
1073 * 2->thermal cruise mode (also called SmartFan I)
1074 * 3->fan speed cruise mode
1075 * 4->SmartFan III
1076 * 5->enhanced variable thermal cruise (SmartFan IV)
1077 */
David Bartley578ab5f2013-06-24 22:28:28 -07001078 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1079 * [3]=pwm_max, [4]=pwm_step,
1080 * [5]=weight_duty_step, [6]=weight_duty_base
1081 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001082
David Bartley578ab5f2013-06-24 22:28:28 -07001083 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001084 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001085 u32 target_speed[NUM_FAN];
1086 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001087 u8 speed_tolerance_limit;
1088
David Bartley578ab5f2013-06-24 22:28:28 -07001089 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001090 u8 tolerance_mask;
1091
David Bartley578ab5f2013-06-24 22:28:28 -07001092 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001093
1094 /* Automatic fan speed control registers */
1095 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001096 u8 auto_pwm[NUM_FAN][7];
1097 u8 auto_temp[NUM_FAN][7];
1098 u8 pwm_temp_sel[NUM_FAN];
1099 u8 pwm_weight_temp_sel[NUM_FAN];
1100 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1101 * 2->temp_base
1102 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001103
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001104 u8 vid;
1105 u8 vrm;
1106
Guenter Roeckf73cf632013-03-18 09:22:50 -07001107 bool have_vid;
1108
Guenter Roeckaa136e52012-12-04 03:26:05 -08001109 u16 have_temp;
1110 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001111 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001112
Guenter Roeck84d19d92012-12-04 08:01:39 -08001113 /* Remember extra register values over suspend/resume */
1114 u8 vbat;
1115 u8 fandiv1;
1116 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001117 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001118};
1119
1120struct nct6775_sio_data {
1121 int sioreg;
1122 enum kinds kind;
1123};
1124
Guenter Roeckf73cf632013-03-18 09:22:50 -07001125struct sensor_device_template {
1126 struct device_attribute dev_attr;
1127 union {
1128 struct {
1129 u8 nr;
1130 u8 index;
1131 } s;
1132 int index;
1133 } u;
1134 bool s2; /* true if both index and nr are used */
1135};
1136
1137struct sensor_device_attr_u {
1138 union {
1139 struct sensor_device_attribute a1;
1140 struct sensor_device_attribute_2 a2;
1141 } u;
1142 char name[32];
1143};
1144
1145#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1146 .attr = {.name = _template, .mode = _mode }, \
1147 .show = _show, \
1148 .store = _store, \
1149}
1150
1151#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1152 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1153 .u.index = _index, \
1154 .s2 = false }
1155
1156#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1157 _nr, _index) \
1158 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1159 .u.s.index = _index, \
1160 .u.s.nr = _nr, \
1161 .s2 = true }
1162
1163#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1164static struct sensor_device_template sensor_dev_template_##_name \
1165 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1166 _index)
1167
1168#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1169 _nr, _index) \
1170static struct sensor_device_template sensor_dev_template_##_name \
1171 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1172 _nr, _index)
1173
1174struct sensor_template_group {
1175 struct sensor_device_template **templates;
1176 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1177 int base;
1178};
1179
1180static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001181nct6775_create_attr_group(struct device *dev,
1182 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001183 int repeat)
1184{
1185 struct attribute_group *group;
1186 struct sensor_device_attr_u *su;
1187 struct sensor_device_attribute *a;
1188 struct sensor_device_attribute_2 *a2;
1189 struct attribute **attrs;
1190 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001191 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001192
1193 if (repeat <= 0)
1194 return ERR_PTR(-EINVAL);
1195
1196 t = tg->templates;
1197 for (count = 0; *t; t++, count++)
1198 ;
1199
1200 if (count == 0)
1201 return ERR_PTR(-EINVAL);
1202
1203 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1204 if (group == NULL)
1205 return ERR_PTR(-ENOMEM);
1206
Kees Cooka86854d2018-06-12 14:07:58 -07001207 attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001208 GFP_KERNEL);
1209 if (attrs == NULL)
1210 return ERR_PTR(-ENOMEM);
1211
Kees Cooka86854d2018-06-12 14:07:58 -07001212 su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001213 GFP_KERNEL);
1214 if (su == NULL)
1215 return ERR_PTR(-ENOMEM);
1216
1217 group->attrs = attrs;
1218 group->is_visible = tg->is_visible;
1219
1220 for (i = 0; i < repeat; i++) {
1221 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001222 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001223 snprintf(su->name, sizeof(su->name),
1224 (*t)->dev_attr.attr.name, tg->base + i);
1225 if ((*t)->s2) {
1226 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001227 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001228 a2->dev_attr.attr.name = su->name;
1229 a2->nr = (*t)->u.s.nr + i;
1230 a2->index = (*t)->u.s.index;
1231 a2->dev_attr.attr.mode =
1232 (*t)->dev_attr.attr.mode;
1233 a2->dev_attr.show = (*t)->dev_attr.show;
1234 a2->dev_attr.store = (*t)->dev_attr.store;
1235 *attrs = &a2->dev_attr.attr;
1236 } else {
1237 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001238 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001239 a->dev_attr.attr.name = su->name;
1240 a->index = (*t)->u.index + i;
1241 a->dev_attr.attr.mode =
1242 (*t)->dev_attr.attr.mode;
1243 a->dev_attr.show = (*t)->dev_attr.show;
1244 a->dev_attr.store = (*t)->dev_attr.store;
1245 *attrs = &a->dev_attr.attr;
1246 }
1247 attrs++;
1248 su++;
1249 t++;
1250 }
1251 }
1252
Guenter Roeckf73cf632013-03-18 09:22:50 -07001253 return group;
1254}
1255
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001256static bool is_word_sized(struct nct6775_data *data, u16 reg)
1257{
1258 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001259 case nct6106:
1260 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1261 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1262 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001263 case nct6775:
1264 return (((reg & 0xff00) == 0x100 ||
1265 (reg & 0xff00) == 0x200) &&
1266 ((reg & 0x00ff) == 0x50 ||
1267 (reg & 0x00ff) == 0x53 ||
1268 (reg & 0x00ff) == 0x55)) ||
1269 (reg & 0xfff0) == 0x630 ||
1270 reg == 0x640 || reg == 0x642 ||
1271 reg == 0x662 ||
1272 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1273 reg == 0x73 || reg == 0x75 || reg == 0x77;
1274 case nct6776:
1275 return (((reg & 0xff00) == 0x100 ||
1276 (reg & 0xff00) == 0x200) &&
1277 ((reg & 0x00ff) == 0x50 ||
1278 (reg & 0x00ff) == 0x53 ||
1279 (reg & 0x00ff) == 0x55)) ||
1280 (reg & 0xfff0) == 0x630 ||
1281 reg == 0x402 ||
1282 reg == 0x640 || reg == 0x642 ||
1283 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1284 reg == 0x73 || reg == 0x75 || reg == 0x77;
1285 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001286 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001287 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001288 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001289 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001290 case nct6796:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001291 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
Guenter Roeckf6de2982018-09-13 20:01:12 -07001292 (reg & 0xfff0) == 0x4c0 ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001293 reg == 0x402 ||
1294 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001295 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck55066352018-09-17 05:23:58 -07001296 reg == 0x64c ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001297 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001298 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001299 }
1300 return false;
1301}
1302
1303/*
1304 * On older chips, only registers 0x50-0x5f are banked.
1305 * On more recent chips, all registers are banked.
1306 * Assume that is the case and set the bank number for each access.
1307 * Cache the bank number so it only needs to be set if it changes.
1308 */
1309static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1310{
1311 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001312
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001313 if (data->bank != bank) {
1314 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1315 outb_p(bank, data->addr + DATA_REG_OFFSET);
1316 data->bank = bank;
1317 }
1318}
1319
1320static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1321{
1322 int res, word_sized = is_word_sized(data, reg);
1323
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001324 nct6775_set_bank(data, reg);
1325 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1326 res = inb_p(data->addr + DATA_REG_OFFSET);
1327 if (word_sized) {
1328 outb_p((reg & 0xff) + 1,
1329 data->addr + ADDR_REG_OFFSET);
1330 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1331 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001332 return res;
1333}
1334
1335static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1336{
1337 int word_sized = is_word_sized(data, reg);
1338
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001339 nct6775_set_bank(data, reg);
1340 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1341 if (word_sized) {
1342 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1343 outb_p((reg & 0xff) + 1,
1344 data->addr + ADDR_REG_OFFSET);
1345 }
1346 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001347 return 0;
1348}
1349
Guenter Roeckaa136e52012-12-04 03:26:05 -08001350/* We left-align 8-bit temperature values to make the code simpler */
1351static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1352{
1353 u16 res;
1354
1355 res = nct6775_read_value(data, reg);
1356 if (!is_word_sized(data, reg))
1357 res <<= 8;
1358
1359 return res;
1360}
1361
1362static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1363{
1364 if (!is_word_sized(data, reg))
1365 value >>= 8;
1366 return nct6775_write_value(data, reg, value);
1367}
1368
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001369/* This function assumes that the caller holds data->update_lock */
1370static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1371{
1372 u8 reg;
1373
1374 switch (nr) {
1375 case 0:
1376 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1377 | (data->fan_div[0] & 0x7);
1378 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1379 break;
1380 case 1:
1381 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1382 | ((data->fan_div[1] << 4) & 0x70);
1383 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1384 break;
1385 case 2:
1386 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1387 | (data->fan_div[2] & 0x7);
1388 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1389 break;
1390 case 3:
1391 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1392 | ((data->fan_div[3] << 4) & 0x70);
1393 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1394 break;
1395 }
1396}
1397
1398static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1399{
1400 if (data->kind == nct6775)
1401 nct6775_write_fan_div(data, nr);
1402}
1403
1404static void nct6775_update_fan_div(struct nct6775_data *data)
1405{
1406 u8 i;
1407
1408 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1409 data->fan_div[0] = i & 0x7;
1410 data->fan_div[1] = (i & 0x70) >> 4;
1411 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1412 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001413 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001414 data->fan_div[3] = (i & 0x70) >> 4;
1415}
1416
1417static void nct6775_update_fan_div_common(struct nct6775_data *data)
1418{
1419 if (data->kind == nct6775)
1420 nct6775_update_fan_div(data);
1421}
1422
1423static void nct6775_init_fan_div(struct nct6775_data *data)
1424{
1425 int i;
1426
1427 nct6775_update_fan_div_common(data);
1428 /*
1429 * For all fans, start with highest divider value if the divider
1430 * register is not initialized. This ensures that we get a
1431 * reading from the fan count register, even if it is not optimal.
1432 * We'll compute a better divider later on.
1433 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001434 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001435 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001436 continue;
1437 if (data->fan_div[i] == 0) {
1438 data->fan_div[i] = 7;
1439 nct6775_write_fan_div_common(data, i);
1440 }
1441 }
1442}
1443
1444static void nct6775_init_fan_common(struct device *dev,
1445 struct nct6775_data *data)
1446{
1447 int i;
1448 u8 reg;
1449
1450 if (data->has_fan_div)
1451 nct6775_init_fan_div(data);
1452
1453 /*
1454 * If fan_min is not set (0), set it to 0xff to disable it. This
1455 * prevents the unnecessary warning when fanX_min is reported as 0.
1456 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001457 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001458 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001459 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1460 if (!reg)
1461 nct6775_write_value(data, data->REG_FAN_MIN[i],
1462 data->has_fan_div ? 0xff
1463 : 0xff1f);
1464 }
1465 }
1466}
1467
1468static void nct6775_select_fan_div(struct device *dev,
1469 struct nct6775_data *data, int nr, u16 reg)
1470{
1471 u8 fan_div = data->fan_div[nr];
1472 u16 fan_min;
1473
1474 if (!data->has_fan_div)
1475 return;
1476
1477 /*
1478 * If we failed to measure the fan speed, or the reported value is not
1479 * in the optimal range, and the clock divider can be modified,
1480 * let's try that for next time.
1481 */
1482 if (reg == 0x00 && fan_div < 0x07)
1483 fan_div++;
1484 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1485 fan_div--;
1486
1487 if (fan_div != data->fan_div[nr]) {
1488 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1489 nr + 1, div_from_reg(data->fan_div[nr]),
1490 div_from_reg(fan_div));
1491
1492 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001493 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001494 fan_min = data->fan_min[nr];
1495 if (fan_div > data->fan_div[nr]) {
1496 if (fan_min != 255 && fan_min > 1)
1497 fan_min >>= 1;
1498 } else {
1499 if (fan_min != 255) {
1500 fan_min <<= 1;
1501 if (fan_min > 254)
1502 fan_min = 254;
1503 }
1504 }
1505 if (fan_min != data->fan_min[nr]) {
1506 data->fan_min[nr] = fan_min;
1507 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1508 fan_min);
1509 }
1510 }
1511 data->fan_div[nr] = fan_div;
1512 nct6775_write_fan_div_common(data, nr);
1513 }
1514}
1515
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001516static void nct6775_update_pwm(struct device *dev)
1517{
1518 struct nct6775_data *data = dev_get_drvdata(dev);
1519 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001520 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001521 bool duty_is_dc;
1522
1523 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001524 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001525 continue;
1526
1527 duty_is_dc = data->REG_PWM_MODE[i] &&
1528 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1529 & data->PWM_MODE_MASK[i]);
Guenter Roeck415eb2a2018-03-26 19:50:31 -07001530 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001531
1532 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1533 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1534 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1535 data->pwm[j][i]
1536 = nct6775_read_value(data,
1537 data->REG_PWM[j][i]);
1538 }
1539 }
1540
1541 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1542 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001543
1544 if (!data->temp_tolerance[0][i] ||
1545 data->pwm_enable[i] != speed_cruise)
1546 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1547 if (!data->target_speed_tolerance[i] ||
1548 data->pwm_enable[i] == speed_cruise) {
1549 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001550
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001551 if (data->REG_TOLERANCE_H) {
1552 t |= (nct6775_read_value(data,
1553 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1554 }
1555 data->target_speed_tolerance[i] = t;
1556 }
1557
1558 data->temp_tolerance[1][i] =
1559 nct6775_read_value(data,
1560 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1561
1562 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1563 data->pwm_temp_sel[i] = reg & 0x1f;
1564 /* If fan can stop, report floor as 0 */
1565 if (reg & 0x80)
1566 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001567
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001568 if (!data->REG_WEIGHT_TEMP_SEL[i])
1569 continue;
1570
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001571 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1572 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1573 /* If weight is disabled, report weight source as 0 */
Dan Carpentere3f3d7a2018-09-05 10:46:27 +03001574 if (!(reg & 0x80))
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001575 data->pwm_weight_temp_sel[i] = 0;
1576
1577 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001578 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001579 data->weight_temp[j][i]
1580 = nct6775_read_value(data,
1581 data->REG_WEIGHT_TEMP[j][i]);
1582 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001583 }
1584}
1585
1586static void nct6775_update_pwm_limits(struct device *dev)
1587{
1588 struct nct6775_data *data = dev_get_drvdata(dev);
1589 int i, j;
1590 u8 reg;
1591 u16 reg_t;
1592
1593 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001594 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001595 continue;
1596
Guenter Roeckc409fd42013-04-09 05:04:00 -07001597 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001598 data->fan_time[j][i] =
1599 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1600 }
1601
1602 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1603 /* Update only in matching mode or if never updated */
1604 if (!data->target_temp[i] ||
1605 data->pwm_enable[i] == thermal_cruise)
1606 data->target_temp[i] = reg_t & data->target_temp_mask;
1607 if (!data->target_speed[i] ||
1608 data->pwm_enable[i] == speed_cruise) {
1609 if (data->REG_TOLERANCE_H) {
1610 reg_t |= (nct6775_read_value(data,
1611 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1612 }
1613 data->target_speed[i] = reg_t;
1614 }
1615
1616 for (j = 0; j < data->auto_pwm_num; j++) {
1617 data->auto_pwm[i][j] =
1618 nct6775_read_value(data,
1619 NCT6775_AUTO_PWM(data, i, j));
1620 data->auto_temp[i][j] =
1621 nct6775_read_value(data,
1622 NCT6775_AUTO_TEMP(data, i, j));
1623 }
1624
1625 /* critical auto_pwm temperature data */
1626 data->auto_temp[i][data->auto_pwm_num] =
1627 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1628
1629 switch (data->kind) {
1630 case nct6775:
1631 reg = nct6775_read_value(data,
1632 NCT6775_REG_CRITICAL_ENAB[i]);
1633 data->auto_pwm[i][data->auto_pwm_num] =
1634 (reg & 0x02) ? 0xff : 0x00;
1635 break;
1636 case nct6776:
1637 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1638 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001639 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001640 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001641 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001642 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001643 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001644 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001645 case nct6796:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001646 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001647 data->REG_CRITICAL_PWM_ENABLE[i]);
1648 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1649 reg = nct6775_read_value(data,
1650 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001651 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001652 reg = 0xff;
1653 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001654 break;
1655 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001656 }
1657}
1658
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001659static struct nct6775_data *nct6775_update_device(struct device *dev)
1660{
1661 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001662 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001663
1664 mutex_lock(&data->update_lock);
1665
Guenter Roeck6445e662013-04-21 09:13:28 -07001666 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001667 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001668 /* Fan clock dividers */
1669 nct6775_update_fan_div_common(data);
1670
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001671 /* Measured voltages and limits */
1672 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001673 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001674 continue;
1675
1676 data->in[i][0] = nct6775_read_value(data,
1677 data->REG_VIN[i]);
1678 data->in[i][1] = nct6775_read_value(data,
1679 data->REG_IN_MINMAX[0][i]);
1680 data->in[i][2] = nct6775_read_value(data,
1681 data->REG_IN_MINMAX[1][i]);
1682 }
1683
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001684 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001685 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001686 u16 reg;
1687
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001688 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001689 continue;
1690
1691 reg = nct6775_read_value(data, data->REG_FAN[i]);
1692 data->rpm[i] = data->fan_from_reg(reg,
1693 data->fan_div[i]);
1694
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001695 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001696 data->fan_min[i] = nct6775_read_value(data,
1697 data->REG_FAN_MIN[i]);
Guenter Roeckc7932792018-09-06 09:47:51 -07001698
1699 if (data->REG_FAN_PULSES[i]) {
1700 data->fan_pulses[i] =
1701 (nct6775_read_value(data,
1702 data->REG_FAN_PULSES[i])
1703 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
1704 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001705
1706 nct6775_select_fan_div(dev, data, i, reg);
1707 }
1708
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001709 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001710 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001711
Guenter Roeckaa136e52012-12-04 03:26:05 -08001712 /* Measured temperatures and limits */
1713 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001714 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001715 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001716 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001717 if (data->reg_temp[j][i])
1718 data->temp[j][i]
1719 = nct6775_read_temp(data,
1720 data->reg_temp[j][i]);
1721 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001722 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001723 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001724 continue;
1725 data->temp_offset[i]
1726 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1727 }
1728
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001729 data->alarms = 0;
1730 for (i = 0; i < NUM_REG_ALARM; i++) {
1731 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001732
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001733 if (!data->REG_ALARM[i])
1734 continue;
1735 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1736 data->alarms |= ((u64)alarm) << (i << 3);
1737 }
1738
Guenter Roeck30846992013-06-24 22:21:59 -07001739 data->beeps = 0;
1740 for (i = 0; i < NUM_REG_BEEP; i++) {
1741 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001742
Guenter Roeck30846992013-06-24 22:21:59 -07001743 if (!data->REG_BEEP[i])
1744 continue;
1745 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1746 data->beeps |= ((u64)beep) << (i << 3);
1747 }
1748
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001749 data->last_updated = jiffies;
1750 data->valid = true;
1751 }
1752
1753 mutex_unlock(&data->update_lock);
1754 return data;
1755}
1756
1757/*
1758 * Sysfs callback functions
1759 */
1760static ssize_t
1761show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1762{
1763 struct nct6775_data *data = nct6775_update_device(dev);
1764 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001765 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001766 int nr = sattr->nr;
1767
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001768 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1769}
1770
1771static ssize_t
1772store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1773 size_t count)
1774{
1775 struct nct6775_data *data = dev_get_drvdata(dev);
1776 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001777 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001778 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001779 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001780 int err;
1781
1782 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001783 if (err < 0)
1784 return err;
1785 mutex_lock(&data->update_lock);
1786 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001787 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001788 data->in[nr][index]);
1789 mutex_unlock(&data->update_lock);
1790 return count;
1791}
1792
1793static ssize_t
1794show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1795{
1796 struct nct6775_data *data = nct6775_update_device(dev);
1797 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1798 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001799
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001800 return sprintf(buf, "%u\n",
1801 (unsigned int)((data->alarms >> nr) & 0x01));
1802}
1803
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001804static int find_temp_source(struct nct6775_data *data, int index, int count)
1805{
1806 int source = data->temp_src[index];
1807 int nr;
1808
1809 for (nr = 0; nr < count; nr++) {
1810 int src;
1811
1812 src = nct6775_read_value(data,
1813 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1814 if (src == source)
1815 return nr;
1816 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001817 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001818}
1819
1820static ssize_t
1821show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1822{
1823 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1824 struct nct6775_data *data = nct6775_update_device(dev);
1825 unsigned int alarm = 0;
1826 int nr;
1827
1828 /*
1829 * For temperatures, there is no fixed mapping from registers to alarm
1830 * bits. Alarm bits are determined by the temperature source mapping.
1831 */
1832 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1833 if (nr >= 0) {
1834 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001835
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001836 alarm = (data->alarms >> bit) & 0x01;
1837 }
1838 return sprintf(buf, "%u\n", alarm);
1839}
1840
Guenter Roeck30846992013-06-24 22:21:59 -07001841static ssize_t
1842show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1843{
1844 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1845 struct nct6775_data *data = nct6775_update_device(dev);
1846 int nr = data->BEEP_BITS[sattr->index];
1847
1848 return sprintf(buf, "%u\n",
1849 (unsigned int)((data->beeps >> nr) & 0x01));
1850}
1851
1852static ssize_t
1853store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1854 size_t count)
1855{
1856 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1857 struct nct6775_data *data = dev_get_drvdata(dev);
1858 int nr = data->BEEP_BITS[sattr->index];
1859 int regindex = nr >> 3;
1860 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001861 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001862
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001863 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001864 if (err < 0)
1865 return err;
1866 if (val > 1)
1867 return -EINVAL;
1868
1869 mutex_lock(&data->update_lock);
1870 if (val)
1871 data->beeps |= (1ULL << nr);
1872 else
1873 data->beeps &= ~(1ULL << nr);
1874 nct6775_write_value(data, data->REG_BEEP[regindex],
1875 (data->beeps >> (regindex << 3)) & 0xff);
1876 mutex_unlock(&data->update_lock);
1877 return count;
1878}
1879
1880static ssize_t
1881show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1882{
1883 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1884 struct nct6775_data *data = nct6775_update_device(dev);
1885 unsigned int beep = 0;
1886 int nr;
1887
1888 /*
1889 * For temperatures, there is no fixed mapping from registers to beep
1890 * enable bits. Beep enable bits are determined by the temperature
1891 * source mapping.
1892 */
1893 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1894 if (nr >= 0) {
1895 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001896
Guenter Roeck30846992013-06-24 22:21:59 -07001897 beep = (data->beeps >> bit) & 0x01;
1898 }
1899 return sprintf(buf, "%u\n", beep);
1900}
1901
1902static ssize_t
1903store_temp_beep(struct device *dev, struct device_attribute *attr,
1904 const char *buf, size_t count)
1905{
1906 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1907 struct nct6775_data *data = dev_get_drvdata(dev);
1908 int nr, bit, regindex;
1909 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001910 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001911
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001912 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001913 if (err < 0)
1914 return err;
1915 if (val > 1)
1916 return -EINVAL;
1917
1918 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1919 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001920 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001921
1922 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1923 regindex = bit >> 3;
1924
1925 mutex_lock(&data->update_lock);
1926 if (val)
1927 data->beeps |= (1ULL << bit);
1928 else
1929 data->beeps &= ~(1ULL << bit);
1930 nct6775_write_value(data, data->REG_BEEP[regindex],
1931 (data->beeps >> (regindex << 3)) & 0xff);
1932 mutex_unlock(&data->update_lock);
1933
1934 return count;
1935}
1936
Guenter Roeckf73cf632013-03-18 09:22:50 -07001937static umode_t nct6775_in_is_visible(struct kobject *kobj,
1938 struct attribute *attr, int index)
1939{
1940 struct device *dev = container_of(kobj, struct device, kobj);
1941 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001942 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001943
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001944 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001945 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001946
Guenter Roeckf73cf632013-03-18 09:22:50 -07001947 return attr->mode;
1948}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001949
Guenter Roeckf73cf632013-03-18 09:22:50 -07001950SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1951SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001952SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1953 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001954SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1955 store_in_reg, 0, 1);
1956SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1957 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001958
Guenter Roeckf73cf632013-03-18 09:22:50 -07001959/*
1960 * nct6775_in_is_visible uses the index into the following array
1961 * to determine if attributes should be created or not.
1962 * Any change in order or content must be matched.
1963 */
1964static struct sensor_device_template *nct6775_attributes_in_template[] = {
1965 &sensor_dev_template_in_input,
1966 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001967 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001968 &sensor_dev_template_in_min,
1969 &sensor_dev_template_in_max,
1970 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001971};
1972
Julia Lawallc60fdf82015-12-12 17:36:39 +01001973static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001974 .templates = nct6775_attributes_in_template,
1975 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001976};
1977
1978static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001979show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1980{
1981 struct nct6775_data *data = nct6775_update_device(dev);
1982 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1983 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001984
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001985 return sprintf(buf, "%d\n", data->rpm[nr]);
1986}
1987
1988static ssize_t
1989show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1990{
1991 struct nct6775_data *data = nct6775_update_device(dev);
1992 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1993 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001994
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001995 return sprintf(buf, "%d\n",
1996 data->fan_from_reg_min(data->fan_min[nr],
1997 data->fan_div[nr]));
1998}
1999
2000static ssize_t
2001show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
2002{
2003 struct nct6775_data *data = nct6775_update_device(dev);
2004 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2005 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002006
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002007 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
2008}
2009
2010static ssize_t
2011store_fan_min(struct device *dev, struct device_attribute *attr,
2012 const char *buf, size_t count)
2013{
2014 struct nct6775_data *data = dev_get_drvdata(dev);
2015 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2016 int nr = sattr->index;
2017 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002018 unsigned int reg;
2019 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002020 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002021
2022 err = kstrtoul(buf, 10, &val);
2023 if (err < 0)
2024 return err;
2025
2026 mutex_lock(&data->update_lock);
2027 if (!data->has_fan_div) {
2028 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
2029 if (!val) {
2030 val = 0xff1f;
2031 } else {
2032 if (val > 1350000U)
2033 val = 135000U;
2034 val = 1350000U / val;
2035 val = (val & 0x1f) | ((val << 3) & 0xff00);
2036 }
2037 data->fan_min[nr] = val;
2038 goto write_min; /* Leave fan divider alone */
2039 }
2040 if (!val) {
2041 /* No min limit, alarm disabled */
2042 data->fan_min[nr] = 255;
2043 new_div = data->fan_div[nr]; /* No change */
2044 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
2045 goto write_div;
2046 }
2047 reg = 1350000U / val;
2048 if (reg >= 128 * 255) {
2049 /*
2050 * Speed below this value cannot possibly be represented,
2051 * even with the highest divider (128)
2052 */
2053 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002054 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002055 dev_warn(dev,
2056 "fan%u low limit %lu below minimum %u, set to minimum\n",
2057 nr + 1, val, data->fan_from_reg_min(254, 7));
2058 } else if (!reg) {
2059 /*
2060 * Speed above this value cannot possibly be represented,
2061 * even with the lowest divider (1)
2062 */
2063 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002064 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002065 dev_warn(dev,
2066 "fan%u low limit %lu above maximum %u, set to maximum\n",
2067 nr + 1, val, data->fan_from_reg_min(1, 0));
2068 } else {
2069 /*
2070 * Automatically pick the best divider, i.e. the one such
2071 * that the min limit will correspond to a register value
2072 * in the 96..192 range
2073 */
2074 new_div = 0;
2075 while (reg > 192 && new_div < 7) {
2076 reg >>= 1;
2077 new_div++;
2078 }
2079 data->fan_min[nr] = reg;
2080 }
2081
2082write_div:
2083 /*
2084 * Write both the fan clock divider (if it changed) and the new
2085 * fan min (unconditionally)
2086 */
2087 if (new_div != data->fan_div[nr]) {
2088 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2089 nr + 1, div_from_reg(data->fan_div[nr]),
2090 div_from_reg(new_div));
2091 data->fan_div[nr] = new_div;
2092 nct6775_write_fan_div_common(data, nr);
2093 /* Give the chip time to sample a new speed value */
2094 data->last_updated = jiffies;
2095 }
2096
2097write_min:
2098 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2099 mutex_unlock(&data->update_lock);
2100
2101 return count;
2102}
2103
Guenter Roeck5c25d952012-12-11 07:29:06 -08002104static ssize_t
2105show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2106{
2107 struct nct6775_data *data = nct6775_update_device(dev);
2108 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2109 int p = data->fan_pulses[sattr->index];
2110
2111 return sprintf(buf, "%d\n", p ? : 4);
2112}
2113
2114static ssize_t
2115store_fan_pulses(struct device *dev, struct device_attribute *attr,
2116 const char *buf, size_t count)
2117{
2118 struct nct6775_data *data = dev_get_drvdata(dev);
2119 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2120 int nr = sattr->index;
2121 unsigned long val;
2122 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002123 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002124
2125 err = kstrtoul(buf, 10, &val);
2126 if (err < 0)
2127 return err;
2128
2129 if (val > 4)
2130 return -EINVAL;
2131
2132 mutex_lock(&data->update_lock);
2133 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002134 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2135 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2136 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2137 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002138 mutex_unlock(&data->update_lock);
2139
2140 return count;
2141}
2142
Guenter Roeckf73cf632013-03-18 09:22:50 -07002143static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2144 struct attribute *attr, int index)
2145{
2146 struct device *dev = container_of(kobj, struct device, kobj);
2147 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002148 int fan = index / 6; /* fan index */
2149 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002150
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002151 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002152 return 0;
2153
2154 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2155 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002156 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002157 return 0;
Guenter Roeck81820052018-02-21 13:09:39 -08002158 if (nr == 3 && !data->REG_FAN_PULSES[fan])
2159 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002160 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002161 return 0;
2162 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002163 return 0;
2164
2165 return attr->mode;
2166}
2167
2168SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2169SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2170 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002171SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2172 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002173SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2174 store_fan_pulses, 0);
2175SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2176 store_fan_min, 0);
2177SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2178
2179/*
2180 * nct6775_fan_is_visible uses the index into the following array
2181 * to determine if attributes should be created or not.
2182 * Any change in order or content must be matched.
2183 */
2184static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2185 &sensor_dev_template_fan_input,
2186 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002187 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002188 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002189 &sensor_dev_template_fan_min, /* 4 */
2190 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002191 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002192};
2193
Julia Lawallc60fdf82015-12-12 17:36:39 +01002194static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002195 .templates = nct6775_attributes_fan_template,
2196 .is_visible = nct6775_fan_is_visible,
2197 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002198};
2199
2200static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002201show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2202{
2203 struct nct6775_data *data = nct6775_update_device(dev);
2204 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2205 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002206
Guenter Roeckaa136e52012-12-04 03:26:05 -08002207 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2208}
2209
2210static ssize_t
2211show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2212{
2213 struct nct6775_data *data = nct6775_update_device(dev);
2214 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2215 int nr = sattr->nr;
2216 int index = sattr->index;
2217
2218 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2219}
2220
2221static ssize_t
2222store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2223 size_t count)
2224{
2225 struct nct6775_data *data = dev_get_drvdata(dev);
2226 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2227 int nr = sattr->nr;
2228 int index = sattr->index;
2229 int err;
2230 long val;
2231
2232 err = kstrtol(buf, 10, &val);
2233 if (err < 0)
2234 return err;
2235
2236 mutex_lock(&data->update_lock);
2237 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2238 nct6775_write_temp(data, data->reg_temp[index][nr],
2239 data->temp[index][nr]);
2240 mutex_unlock(&data->update_lock);
2241 return count;
2242}
2243
2244static ssize_t
2245show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2246{
2247 struct nct6775_data *data = nct6775_update_device(dev);
2248 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2249
2250 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2251}
2252
2253static ssize_t
2254store_temp_offset(struct device *dev, struct device_attribute *attr,
2255 const char *buf, size_t count)
2256{
2257 struct nct6775_data *data = dev_get_drvdata(dev);
2258 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2259 int nr = sattr->index;
2260 long val;
2261 int err;
2262
2263 err = kstrtol(buf, 10, &val);
2264 if (err < 0)
2265 return err;
2266
2267 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2268
2269 mutex_lock(&data->update_lock);
2270 data->temp_offset[nr] = val;
2271 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2272 mutex_unlock(&data->update_lock);
2273
2274 return count;
2275}
2276
2277static ssize_t
2278show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2279{
2280 struct nct6775_data *data = nct6775_update_device(dev);
2281 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2282 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002283
Guenter Roeckaa136e52012-12-04 03:26:05 -08002284 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2285}
2286
2287static ssize_t
2288store_temp_type(struct device *dev, struct device_attribute *attr,
2289 const char *buf, size_t count)
2290{
2291 struct nct6775_data *data = nct6775_update_device(dev);
2292 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2293 int nr = sattr->index;
2294 unsigned long val;
2295 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002296 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002297
2298 err = kstrtoul(buf, 10, &val);
2299 if (err < 0)
2300 return err;
2301
2302 if (val != 1 && val != 3 && val != 4)
2303 return -EINVAL;
2304
2305 mutex_lock(&data->update_lock);
2306
2307 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002308 vbit = 0x02 << nr;
2309 dbit = data->DIODE_MASK << nr;
2310 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2311 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002312 switch (val) {
2313 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002314 vbat |= vbit;
2315 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002316 break;
2317 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002318 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002319 break;
2320 case 4: /* thermistor */
2321 break;
2322 }
2323 nct6775_write_value(data, data->REG_VBAT, vbat);
2324 nct6775_write_value(data, data->REG_DIODE, diode);
2325
2326 mutex_unlock(&data->update_lock);
2327 return count;
2328}
2329
Guenter Roeckf73cf632013-03-18 09:22:50 -07002330static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2331 struct attribute *attr, int index)
2332{
2333 struct device *dev = container_of(kobj, struct device, kobj);
2334 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002335 int temp = index / 10; /* temp index */
2336 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002337
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002338 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002339 return 0;
2340
Guenter Roeckcc66b302017-05-17 18:05:06 -07002341 if (nr == 1 && !data->temp_label)
2342 return 0;
2343
Guenter Roeckf73cf632013-03-18 09:22:50 -07002344 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2345 return 0; /* alarm */
2346
Guenter Roeck30846992013-06-24 22:21:59 -07002347 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2348 return 0; /* beep */
2349
2350 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002351 return 0;
2352
Guenter Roeck30846992013-06-24 22:21:59 -07002353 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002354 return 0;
2355
Guenter Roeck30846992013-06-24 22:21:59 -07002356 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002357 return 0;
2358
Guenter Roeck30846992013-06-24 22:21:59 -07002359 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002360 return 0;
2361
2362 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002363 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002364 return 0;
2365
2366 return attr->mode;
2367}
2368
2369SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2370SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2371SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2372 store_temp, 0, 1);
2373SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2374 show_temp, store_temp, 0, 2);
2375SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2376 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002377SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2378 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002379SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2380 show_temp_offset, store_temp_offset, 0);
2381SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2382 store_temp_type, 0);
2383SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002384SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2385 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002386
2387/*
2388 * nct6775_temp_is_visible uses the index into the following array
2389 * to determine if attributes should be created or not.
2390 * Any change in order or content must be matched.
2391 */
2392static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2393 &sensor_dev_template_temp_input,
2394 &sensor_dev_template_temp_label,
2395 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002396 &sensor_dev_template_temp_beep, /* 3 */
2397 &sensor_dev_template_temp_max, /* 4 */
2398 &sensor_dev_template_temp_max_hyst, /* 5 */
2399 &sensor_dev_template_temp_crit, /* 6 */
2400 &sensor_dev_template_temp_lcrit, /* 7 */
2401 &sensor_dev_template_temp_offset, /* 8 */
2402 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002403 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002404};
2405
Julia Lawallc60fdf82015-12-12 17:36:39 +01002406static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002407 .templates = nct6775_attributes_temp_template,
2408 .is_visible = nct6775_temp_is_visible,
2409 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002410};
2411
Guenter Roeckaa136e52012-12-04 03:26:05 -08002412static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002413show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2414{
2415 struct nct6775_data *data = nct6775_update_device(dev);
2416 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2417
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002418 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002419}
2420
2421static ssize_t
2422store_pwm_mode(struct device *dev, struct device_attribute *attr,
2423 const char *buf, size_t count)
2424{
2425 struct nct6775_data *data = dev_get_drvdata(dev);
2426 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2427 int nr = sattr->index;
2428 unsigned long val;
2429 int err;
2430 u8 reg;
2431
2432 err = kstrtoul(buf, 10, &val);
2433 if (err < 0)
2434 return err;
2435
2436 if (val > 1)
2437 return -EINVAL;
2438
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002439 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002440 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002441 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002442 return -EINVAL;
2443 return count;
2444 }
2445
2446 mutex_lock(&data->update_lock);
2447 data->pwm_mode[nr] = val;
2448 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2449 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002450 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002451 reg |= data->PWM_MODE_MASK[nr];
2452 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2453 mutex_unlock(&data->update_lock);
2454 return count;
2455}
2456
2457static ssize_t
2458show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2459{
2460 struct nct6775_data *data = nct6775_update_device(dev);
2461 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2462 int nr = sattr->nr;
2463 int index = sattr->index;
2464 int pwm;
2465
2466 /*
2467 * For automatic fan control modes, show current pwm readings.
2468 * Otherwise, show the configured value.
2469 */
2470 if (index == 0 && data->pwm_enable[nr] > manual)
2471 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2472 else
2473 pwm = data->pwm[index][nr];
2474
2475 return sprintf(buf, "%d\n", pwm);
2476}
2477
2478static ssize_t
2479store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2480 size_t count)
2481{
2482 struct nct6775_data *data = dev_get_drvdata(dev);
2483 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2484 int nr = sattr->nr;
2485 int index = sattr->index;
2486 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002487 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2488 int maxval[7]
2489 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002490 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002491 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002492
2493 err = kstrtoul(buf, 10, &val);
2494 if (err < 0)
2495 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002496 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002497
2498 mutex_lock(&data->update_lock);
2499 data->pwm[index][nr] = val;
2500 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002501 if (index == 2) { /* floor: disable if val == 0 */
2502 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2503 reg &= 0x7f;
2504 if (val)
2505 reg |= 0x80;
2506 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2507 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002508 mutex_unlock(&data->update_lock);
2509 return count;
2510}
2511
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002512/* Returns 0 if OK, -EINVAL otherwise */
2513static int check_trip_points(struct nct6775_data *data, int nr)
2514{
2515 int i;
2516
2517 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2518 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2519 return -EINVAL;
2520 }
2521 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2522 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2523 return -EINVAL;
2524 }
2525 /* validate critical temperature and pwm if enabled (pwm > 0) */
2526 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2527 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2528 data->auto_temp[nr][data->auto_pwm_num] ||
2529 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2530 data->auto_pwm[nr][data->auto_pwm_num])
2531 return -EINVAL;
2532 }
2533 return 0;
2534}
2535
2536static void pwm_update_registers(struct nct6775_data *data, int nr)
2537{
2538 u8 reg;
2539
2540 switch (data->pwm_enable[nr]) {
2541 case off:
2542 case manual:
2543 break;
2544 case speed_cruise:
2545 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2546 reg = (reg & ~data->tolerance_mask) |
2547 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2548 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2549 nct6775_write_value(data, data->REG_TARGET[nr],
2550 data->target_speed[nr] & 0xff);
2551 if (data->REG_TOLERANCE_H) {
2552 reg = (data->target_speed[nr] >> 8) & 0x0f;
2553 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2554 nct6775_write_value(data,
2555 data->REG_TOLERANCE_H[nr],
2556 reg);
2557 }
2558 break;
2559 case thermal_cruise:
2560 nct6775_write_value(data, data->REG_TARGET[nr],
2561 data->target_temp[nr]);
Gustavo A. R. Silvaffb32432018-07-02 16:30:17 -05002562 /* fall through */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002563 default:
2564 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2565 reg = (reg & ~data->tolerance_mask) |
2566 data->temp_tolerance[0][nr];
2567 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2568 break;
2569 }
2570}
2571
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002572static ssize_t
2573show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2574{
2575 struct nct6775_data *data = nct6775_update_device(dev);
2576 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2577
2578 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2579}
2580
2581static ssize_t
2582store_pwm_enable(struct device *dev, struct device_attribute *attr,
2583 const char *buf, size_t count)
2584{
2585 struct nct6775_data *data = dev_get_drvdata(dev);
2586 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2587 int nr = sattr->index;
2588 unsigned long val;
2589 int err;
2590 u16 reg;
2591
2592 err = kstrtoul(buf, 10, &val);
2593 if (err < 0)
2594 return err;
2595
2596 if (val > sf4)
2597 return -EINVAL;
2598
2599 if (val == sf3 && data->kind != nct6775)
2600 return -EINVAL;
2601
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002602 if (val == sf4 && check_trip_points(data, nr)) {
2603 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2604 dev_err(dev, "Adjust trip points and try again\n");
2605 return -EINVAL;
2606 }
2607
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002608 mutex_lock(&data->update_lock);
2609 data->pwm_enable[nr] = val;
2610 if (val == off) {
2611 /*
2612 * turn off pwm control: select manual mode, set pwm to maximum
2613 */
2614 data->pwm[0][nr] = 255;
2615 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2616 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002617 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002618 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2619 reg &= 0x0f;
2620 reg |= pwm_enable_to_reg(val) << 4;
2621 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2622 mutex_unlock(&data->update_lock);
2623 return count;
2624}
2625
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002626static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002627show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002628{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002629 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002630
2631 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002632 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002633 continue;
2634 if (src == data->temp_src[i]) {
2635 sel = i + 1;
2636 break;
2637 }
2638 }
2639
2640 return sprintf(buf, "%d\n", sel);
2641}
2642
2643static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002644show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2645{
2646 struct nct6775_data *data = nct6775_update_device(dev);
2647 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2648 int index = sattr->index;
2649
2650 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2651}
2652
2653static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002654store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2655 const char *buf, size_t count)
2656{
2657 struct nct6775_data *data = nct6775_update_device(dev);
2658 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2659 int nr = sattr->index;
2660 unsigned long val;
2661 int err, reg, src;
2662
2663 err = kstrtoul(buf, 10, &val);
2664 if (err < 0)
2665 return err;
2666 if (val == 0 || val > NUM_TEMP)
2667 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002668 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002669 return -EINVAL;
2670
2671 mutex_lock(&data->update_lock);
2672 src = data->temp_src[val - 1];
2673 data->pwm_temp_sel[nr] = src;
2674 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2675 reg &= 0xe0;
2676 reg |= src;
2677 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2678 mutex_unlock(&data->update_lock);
2679
2680 return count;
2681}
2682
2683static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002684show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2685 char *buf)
2686{
2687 struct nct6775_data *data = nct6775_update_device(dev);
2688 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2689 int index = sattr->index;
2690
2691 return show_pwm_temp_sel_common(data, buf,
2692 data->pwm_weight_temp_sel[index]);
2693}
2694
2695static ssize_t
2696store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2697 const char *buf, size_t count)
2698{
2699 struct nct6775_data *data = nct6775_update_device(dev);
2700 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2701 int nr = sattr->index;
2702 unsigned long val;
2703 int err, reg, src;
2704
2705 err = kstrtoul(buf, 10, &val);
2706 if (err < 0)
2707 return err;
2708 if (val > NUM_TEMP)
2709 return -EINVAL;
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -05002710 val = array_index_nospec(val, NUM_TEMP + 1);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002711 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002712 !data->temp_src[val - 1]))
2713 return -EINVAL;
2714
2715 mutex_lock(&data->update_lock);
2716 if (val) {
2717 src = data->temp_src[val - 1];
2718 data->pwm_weight_temp_sel[nr] = src;
2719 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2720 reg &= 0xe0;
2721 reg |= (src | 0x80);
2722 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2723 } else {
2724 data->pwm_weight_temp_sel[nr] = 0;
2725 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2726 reg &= 0x7f;
2727 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2728 }
2729 mutex_unlock(&data->update_lock);
2730
2731 return count;
2732}
2733
2734static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002735show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2736{
2737 struct nct6775_data *data = nct6775_update_device(dev);
2738 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2739
2740 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2741}
2742
2743static ssize_t
2744store_target_temp(struct device *dev, struct device_attribute *attr,
2745 const char *buf, size_t count)
2746{
2747 struct nct6775_data *data = dev_get_drvdata(dev);
2748 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2749 int nr = sattr->index;
2750 unsigned long val;
2751 int err;
2752
2753 err = kstrtoul(buf, 10, &val);
2754 if (err < 0)
2755 return err;
2756
2757 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2758 data->target_temp_mask);
2759
2760 mutex_lock(&data->update_lock);
2761 data->target_temp[nr] = val;
2762 pwm_update_registers(data, nr);
2763 mutex_unlock(&data->update_lock);
2764 return count;
2765}
2766
2767static ssize_t
2768show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2769{
2770 struct nct6775_data *data = nct6775_update_device(dev);
2771 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2772 int nr = sattr->index;
2773
2774 return sprintf(buf, "%d\n",
2775 fan_from_reg16(data->target_speed[nr],
2776 data->fan_div[nr]));
2777}
2778
2779static ssize_t
2780store_target_speed(struct device *dev, struct device_attribute *attr,
2781 const char *buf, size_t count)
2782{
2783 struct nct6775_data *data = dev_get_drvdata(dev);
2784 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2785 int nr = sattr->index;
2786 unsigned long val;
2787 int err;
2788 u16 speed;
2789
2790 err = kstrtoul(buf, 10, &val);
2791 if (err < 0)
2792 return err;
2793
2794 val = clamp_val(val, 0, 1350000U);
2795 speed = fan_to_reg(val, data->fan_div[nr]);
2796
2797 mutex_lock(&data->update_lock);
2798 data->target_speed[nr] = speed;
2799 pwm_update_registers(data, nr);
2800 mutex_unlock(&data->update_lock);
2801 return count;
2802}
2803
2804static ssize_t
2805show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2806 char *buf)
2807{
2808 struct nct6775_data *data = nct6775_update_device(dev);
2809 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2810 int nr = sattr->nr;
2811 int index = sattr->index;
2812
2813 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2814}
2815
2816static ssize_t
2817store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2818 const char *buf, size_t count)
2819{
2820 struct nct6775_data *data = dev_get_drvdata(dev);
2821 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2822 int nr = sattr->nr;
2823 int index = sattr->index;
2824 unsigned long val;
2825 int err;
2826
2827 err = kstrtoul(buf, 10, &val);
2828 if (err < 0)
2829 return err;
2830
2831 /* Limit tolerance as needed */
2832 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2833
2834 mutex_lock(&data->update_lock);
2835 data->temp_tolerance[index][nr] = val;
2836 if (index)
2837 pwm_update_registers(data, nr);
2838 else
2839 nct6775_write_value(data,
2840 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2841 val);
2842 mutex_unlock(&data->update_lock);
2843 return count;
2844}
2845
2846/*
2847 * Fan speed tolerance is a tricky beast, since the associated register is
2848 * a tick counter, but the value is reported and configured as rpm.
2849 * Compute resulting low and high rpm values and report the difference.
Guenter Roeck61b6c662018-09-17 09:24:11 -07002850 * A fan speed tolerance only makes sense if a fan target speed has been
2851 * configured, so only display values other than 0 if that is the case.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002852 */
2853static ssize_t
2854show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2855 char *buf)
2856{
2857 struct nct6775_data *data = nct6775_update_device(dev);
2858 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2859 int nr = sattr->index;
Guenter Roeck61b6c662018-09-17 09:24:11 -07002860 int target = data->target_speed[nr];
2861 int tolerance = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002862
Guenter Roeck61b6c662018-09-17 09:24:11 -07002863 if (target) {
2864 int low = target - data->target_speed_tolerance[nr];
2865 int high = target + data->target_speed_tolerance[nr];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002866
Guenter Roeck61b6c662018-09-17 09:24:11 -07002867 if (low <= 0)
2868 low = 1;
2869 if (high > 0xffff)
2870 high = 0xffff;
2871 if (high < low)
2872 high = low;
2873
2874 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2875 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2876 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002877
2878 return sprintf(buf, "%d\n", tolerance);
2879}
2880
2881static ssize_t
2882store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2883 const char *buf, size_t count)
2884{
2885 struct nct6775_data *data = dev_get_drvdata(dev);
2886 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2887 int nr = sattr->index;
2888 unsigned long val;
2889 int err;
2890 int low, high;
2891
2892 err = kstrtoul(buf, 10, &val);
2893 if (err < 0)
2894 return err;
2895
2896 high = fan_from_reg16(data->target_speed[nr],
2897 data->fan_div[nr]) + val;
2898 low = fan_from_reg16(data->target_speed[nr],
2899 data->fan_div[nr]) - val;
2900 if (low <= 0)
2901 low = 1;
2902 if (high < low)
2903 high = low;
2904
2905 val = (fan_to_reg(low, data->fan_div[nr]) -
2906 fan_to_reg(high, data->fan_div[nr])) / 2;
2907
2908 /* Limit tolerance as needed */
2909 val = clamp_val(val, 0, data->speed_tolerance_limit);
2910
2911 mutex_lock(&data->update_lock);
2912 data->target_speed_tolerance[nr] = val;
2913 pwm_update_registers(data, nr);
2914 mutex_unlock(&data->update_lock);
2915 return count;
2916}
2917
Guenter Roeckf73cf632013-03-18 09:22:50 -07002918SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2919SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2920 store_pwm_mode, 0);
2921SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2922 store_pwm_enable, 0);
2923SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2924 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2925SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2926 show_target_temp, store_target_temp, 0);
2927SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2928 show_target_speed, store_target_speed, 0);
2929SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2930 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002931
2932/* Smart Fan registers */
2933
2934static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002935show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2936{
2937 struct nct6775_data *data = nct6775_update_device(dev);
2938 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2939 int nr = sattr->nr;
2940 int index = sattr->index;
2941
2942 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2943}
2944
2945static ssize_t
2946store_weight_temp(struct device *dev, struct device_attribute *attr,
2947 const char *buf, size_t count)
2948{
2949 struct nct6775_data *data = dev_get_drvdata(dev);
2950 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2951 int nr = sattr->nr;
2952 int index = sattr->index;
2953 unsigned long val;
2954 int err;
2955
2956 err = kstrtoul(buf, 10, &val);
2957 if (err < 0)
2958 return err;
2959
2960 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2961
2962 mutex_lock(&data->update_lock);
2963 data->weight_temp[index][nr] = val;
2964 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2965 mutex_unlock(&data->update_lock);
2966 return count;
2967}
2968
Guenter Roeckf73cf632013-03-18 09:22:50 -07002969SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2970 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2971SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2972 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2973SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2974 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2975SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2976 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2977SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2978 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2979SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2980 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002981
2982static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002983show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2984{
2985 struct nct6775_data *data = nct6775_update_device(dev);
2986 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2987 int nr = sattr->nr;
2988 int index = sattr->index;
2989
2990 return sprintf(buf, "%d\n",
2991 step_time_from_reg(data->fan_time[index][nr],
2992 data->pwm_mode[nr]));
2993}
2994
2995static ssize_t
2996store_fan_time(struct device *dev, struct device_attribute *attr,
2997 const char *buf, size_t count)
2998{
2999 struct nct6775_data *data = dev_get_drvdata(dev);
3000 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3001 int nr = sattr->nr;
3002 int index = sattr->index;
3003 unsigned long val;
3004 int err;
3005
3006 err = kstrtoul(buf, 10, &val);
3007 if (err < 0)
3008 return err;
3009
3010 val = step_time_to_reg(val, data->pwm_mode[nr]);
3011 mutex_lock(&data->update_lock);
3012 data->fan_time[index][nr] = val;
3013 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
3014 mutex_unlock(&data->update_lock);
3015 return count;
3016}
3017
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003018static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003019show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3020{
3021 struct nct6775_data *data = nct6775_update_device(dev);
3022 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3023
3024 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3025}
3026
3027static ssize_t
3028store_auto_pwm(struct device *dev, struct device_attribute *attr,
3029 const char *buf, size_t count)
3030{
3031 struct nct6775_data *data = dev_get_drvdata(dev);
3032 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3033 int nr = sattr->nr;
3034 int point = sattr->index;
3035 unsigned long val;
3036 int err;
3037 u8 reg;
3038
3039 err = kstrtoul(buf, 10, &val);
3040 if (err < 0)
3041 return err;
3042 if (val > 255)
3043 return -EINVAL;
3044
3045 if (point == data->auto_pwm_num) {
3046 if (data->kind != nct6775 && !val)
3047 return -EINVAL;
3048 if (data->kind != nct6779 && val)
3049 val = 0xff;
3050 }
3051
3052 mutex_lock(&data->update_lock);
3053 data->auto_pwm[nr][point] = val;
3054 if (point < data->auto_pwm_num) {
3055 nct6775_write_value(data,
3056 NCT6775_AUTO_PWM(data, nr, point),
3057 data->auto_pwm[nr][point]);
3058 } else {
3059 switch (data->kind) {
3060 case nct6775:
3061 /* disable if needed (pwm == 0) */
3062 reg = nct6775_read_value(data,
3063 NCT6775_REG_CRITICAL_ENAB[nr]);
3064 if (val)
3065 reg |= 0x02;
3066 else
3067 reg &= ~0x02;
3068 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3069 reg);
3070 break;
3071 case nct6776:
3072 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003073 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003074 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003075 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003076 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003077 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003078 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003079 case nct6796:
Guenter Roeck6c009502012-07-01 08:23:15 -07003080 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003081 val);
3082 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003083 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003084 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003085 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003086 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003087 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003088 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003089 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003090 reg);
3091 break;
3092 }
3093 }
3094 mutex_unlock(&data->update_lock);
3095 return count;
3096}
3097
3098static ssize_t
3099show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3100{
3101 struct nct6775_data *data = nct6775_update_device(dev);
3102 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3103 int nr = sattr->nr;
3104 int point = sattr->index;
3105
3106 /*
3107 * We don't know for sure if the temperature is signed or unsigned.
3108 * Assume it is unsigned.
3109 */
3110 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3111}
3112
3113static ssize_t
3114store_auto_temp(struct device *dev, struct device_attribute *attr,
3115 const char *buf, size_t count)
3116{
3117 struct nct6775_data *data = dev_get_drvdata(dev);
3118 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3119 int nr = sattr->nr;
3120 int point = sattr->index;
3121 unsigned long val;
3122 int err;
3123
3124 err = kstrtoul(buf, 10, &val);
3125 if (err)
3126 return err;
3127 if (val > 255000)
3128 return -EINVAL;
3129
3130 mutex_lock(&data->update_lock);
3131 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3132 if (point < data->auto_pwm_num) {
3133 nct6775_write_value(data,
3134 NCT6775_AUTO_TEMP(data, nr, point),
3135 data->auto_temp[nr][point]);
3136 } else {
3137 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3138 data->auto_temp[nr][point]);
3139 }
3140 mutex_unlock(&data->update_lock);
3141 return count;
3142}
3143
Guenter Roeckf73cf632013-03-18 09:22:50 -07003144static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3145 struct attribute *attr, int index)
3146{
3147 struct device *dev = container_of(kobj, struct device, kobj);
3148 struct nct6775_data *data = dev_get_drvdata(dev);
3149 int pwm = index / 36; /* pwm index */
3150 int nr = index % 36; /* attribute index */
3151
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003152 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003153 return 0;
3154
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003155 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3156 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3157 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003158 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3159 return 0;
3160 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3161 return 0;
3162 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3163 return 0;
3164
3165 if (nr >= 22 && nr <= 35) { /* auto point */
3166 int api = (nr - 22) / 2; /* auto point index */
3167
3168 if (api > data->auto_pwm_num)
3169 return 0;
3170 }
3171 return attr->mode;
3172}
3173
3174SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3175 show_fan_time, store_fan_time, 0, 0);
3176SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3177 show_fan_time, store_fan_time, 0, 1);
3178SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3179 show_fan_time, store_fan_time, 0, 2);
3180SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3181 store_pwm, 0, 1);
3182SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3183 store_pwm, 0, 2);
3184SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3185 show_temp_tolerance, store_temp_tolerance, 0, 0);
3186SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3187 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3188 0, 1);
3189
3190SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3191 0, 3);
3192
3193SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3194 store_pwm, 0, 4);
3195
3196SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3197 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3198SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3199 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3200
3201SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3202 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3203SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3204 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3205
3206SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3207 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3208SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3209 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3210
3211SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3212 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3213SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3214 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3215
3216SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3217 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3218SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3219 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3220
3221SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3222 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3223SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3224 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3225
3226SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3227 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3228SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3229 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3230
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003231/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003232 * nct6775_pwm_is_visible uses the index into the following array
3233 * to determine if attributes should be created or not.
3234 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003235 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003236static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3237 &sensor_dev_template_pwm,
3238 &sensor_dev_template_pwm_mode,
3239 &sensor_dev_template_pwm_enable,
3240 &sensor_dev_template_pwm_temp_sel,
3241 &sensor_dev_template_pwm_temp_tolerance,
3242 &sensor_dev_template_pwm_crit_temp_tolerance,
3243 &sensor_dev_template_pwm_target_temp,
3244 &sensor_dev_template_fan_target,
3245 &sensor_dev_template_fan_tolerance,
3246 &sensor_dev_template_pwm_stop_time,
3247 &sensor_dev_template_pwm_step_up_time,
3248 &sensor_dev_template_pwm_step_down_time,
3249 &sensor_dev_template_pwm_start,
3250 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003251 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003252 &sensor_dev_template_pwm_weight_temp_step,
3253 &sensor_dev_template_pwm_weight_temp_step_tol,
3254 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003255 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003256 &sensor_dev_template_pwm_max, /* 19 */
3257 &sensor_dev_template_pwm_step, /* 20 */
3258 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3259 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3260 &sensor_dev_template_pwm_auto_point1_temp,
3261 &sensor_dev_template_pwm_auto_point2_pwm,
3262 &sensor_dev_template_pwm_auto_point2_temp,
3263 &sensor_dev_template_pwm_auto_point3_pwm,
3264 &sensor_dev_template_pwm_auto_point3_temp,
3265 &sensor_dev_template_pwm_auto_point4_pwm,
3266 &sensor_dev_template_pwm_auto_point4_temp,
3267 &sensor_dev_template_pwm_auto_point5_pwm,
3268 &sensor_dev_template_pwm_auto_point5_temp,
3269 &sensor_dev_template_pwm_auto_point6_pwm,
3270 &sensor_dev_template_pwm_auto_point6_temp,
3271 &sensor_dev_template_pwm_auto_point7_pwm,
3272 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003273
Guenter Roeckf73cf632013-03-18 09:22:50 -07003274 NULL
3275};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003276
Julia Lawallc60fdf82015-12-12 17:36:39 +01003277static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003278 .templates = nct6775_attributes_pwm_template,
3279 .is_visible = nct6775_pwm_is_visible,
3280 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003281};
3282
3283static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003284cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003285{
3286 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003287
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003288 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3289}
3290
Julia Lawall93d72ac2016-12-22 13:05:23 +01003291static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003292
Guenter Roecka6bd5872012-12-04 03:13:34 -08003293/* Case open detection */
3294
3295static ssize_t
3296clear_caseopen(struct device *dev, struct device_attribute *attr,
3297 const char *buf, size_t count)
3298{
3299 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003300 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3301 unsigned long val;
3302 u8 reg;
3303 int ret;
3304
3305 if (kstrtoul(buf, 10, &val) || val != 0)
3306 return -EINVAL;
3307
3308 mutex_lock(&data->update_lock);
3309
3310 /*
3311 * Use CR registers to clear caseopen status.
3312 * The CR registers are the same for all chips, and not all chips
3313 * support clearing the caseopen status through "regular" registers.
3314 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003315 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003316 if (ret) {
3317 count = ret;
3318 goto error;
3319 }
3320
Guenter Roeckdf612d52013-07-08 13:15:04 -07003321 superio_select(data->sioreg, NCT6775_LD_ACPI);
3322 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003323 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003324 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003325 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003326 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3327 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003328
3329 data->valid = false; /* Force cache refresh */
3330error:
3331 mutex_unlock(&data->update_lock);
3332 return count;
3333}
3334
Guenter Roeckf73cf632013-03-18 09:22:50 -07003335static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3336 clear_caseopen, INTRUSION_ALARM_BASE);
3337static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3338 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003339static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3340 store_beep, INTRUSION_ALARM_BASE);
3341static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3342 store_beep, INTRUSION_ALARM_BASE + 1);
3343static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3344 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003345
3346static umode_t nct6775_other_is_visible(struct kobject *kobj,
3347 struct attribute *attr, int index)
3348{
3349 struct device *dev = container_of(kobj, struct device, kobj);
3350 struct nct6775_data *data = dev_get_drvdata(dev);
3351
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003352 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003353 return 0;
3354
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003355 if (index == 1 || index == 2) {
3356 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003357 return 0;
3358 }
3359
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003360 if (index == 3 || index == 4) {
3361 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003362 return 0;
3363 }
3364
Guenter Roeckf73cf632013-03-18 09:22:50 -07003365 return attr->mode;
3366}
3367
3368/*
3369 * nct6775_other_is_visible uses the index into the following array
3370 * to determine if attributes should be created or not.
3371 * Any change in order or content must be matched.
3372 */
3373static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003374 &dev_attr_cpu0_vid.attr, /* 0 */
3375 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3376 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3377 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3378 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3379 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003380
3381 NULL
3382};
3383
3384static const struct attribute_group nct6775_group_other = {
3385 .attrs = nct6775_attributes_other,
3386 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003387};
3388
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003389static inline void nct6775_init_device(struct nct6775_data *data)
3390{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003391 int i;
3392 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003393
3394 /* Start monitoring if needed */
3395 if (data->REG_CONFIG) {
3396 tmp = nct6775_read_value(data, data->REG_CONFIG);
3397 if (!(tmp & 0x01))
3398 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3399 }
3400
Guenter Roeckaa136e52012-12-04 03:26:05 -08003401 /* Enable temperature sensors if needed */
3402 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003403 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003404 continue;
3405 if (!data->reg_temp_config[i])
3406 continue;
3407 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3408 if (tmp & 0x01)
3409 nct6775_write_value(data, data->reg_temp_config[i],
3410 tmp & 0xfe);
3411 }
3412
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003413 /* Enable VBAT monitoring if needed */
3414 tmp = nct6775_read_value(data, data->REG_VBAT);
3415 if (!(tmp & 0x01))
3416 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003417
3418 diode = nct6775_read_value(data, data->REG_DIODE);
3419
3420 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003421 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003422 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003423 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3424 data->temp_type[i]
3425 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003426 else /* thermistor */
3427 data->temp_type[i] = 4;
3428 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003429}
3430
Guenter Roeckf73cf632013-03-18 09:22:50 -07003431static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003432nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003433{
Guenter Roeck1b206242018-02-21 13:09:38 -08003434 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003435 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003436 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003437 bool pwm6pin = false, pwm7pin = false;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003438 int sioreg = data->sioreg;
Guenter Roecka6c54f22018-09-18 09:34:06 -07003439 int cr24;
3440 int cr2c;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003441
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003442 /* Store SIO_REG_ENABLE for use during resume */
3443 superio_select(sioreg, NCT6775_LD_HWM);
3444 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3445
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003446 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3447 if (data->kind == nct6775) {
Guenter Roecka6c54f22018-09-18 09:34:06 -07003448 cr2c = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003449
Guenter Roecka6c54f22018-09-18 09:34:06 -07003450 fan3pin = cr2c & BIT(6);
3451 pwm3pin = cr2c & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003452
3453 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003454 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003455 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003456 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003457 const char *board_vendor, *board_name;
3458
3459 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3460 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3461
3462 if (board_name && board_vendor &&
3463 !strcmp(board_vendor, "ASRock")) {
3464 /*
3465 * Auxiliary fan monitoring is not enabled on ASRock
3466 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3467 * Observed with BIOS version 2.00.
3468 */
3469 if (!strcmp(board_name, "Z77 Pro4-M")) {
3470 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3471 data->sio_reg_enable |= 0xe0;
3472 superio_outb(sioreg, SIO_REG_ENABLE,
3473 data->sio_reg_enable);
3474 }
3475 }
3476 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003477
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003478 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003479 fan3pin = gpok;
3480 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003481 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003482
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003483 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003484 fan4pin = gpok;
3485 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003486 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003487
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003488 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003489 fan5pin = gpok;
3490 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003491 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003492
3493 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003494 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003495 } else if (data->kind == nct6106) {
Guenter Roecka6c54f22018-09-18 09:34:06 -07003496 cr24 = superio_inb(sioreg, 0x24);
3497 fan3pin = !(cr24 & 0x80);
3498 pwm3pin = cr24 & 0x08;
Guenter Roeck81820052018-02-21 13:09:39 -08003499 } else {
3500 /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
Guenter Roeck0085a512018-09-18 09:31:21 -07003501 int cr1b, cr2a, cr2f;
Guenter Roecka6c54f22018-09-18 09:34:06 -07003502 int cr1c;
3503 int cr2d;
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003504 bool dsw_en;
Guenter Roecke5c85222017-05-17 18:09:41 -07003505
Guenter Roecka6c54f22018-09-18 09:34:06 -07003506 cr1c = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003507
Guenter Roecka6c54f22018-09-18 09:34:06 -07003508 fan3pin = !(cr1c & BIT(5));
3509 fan4pin = !(cr1c & BIT(6));
3510 fan5pin = !(cr1c & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003511
Guenter Roecka6c54f22018-09-18 09:34:06 -07003512 pwm3pin = !(cr1c & BIT(0));
3513 pwm4pin = !(cr1c & BIT(1));
3514 pwm5pin = !(cr1c & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003515
Guenter Roecka6c54f22018-09-18 09:34:06 -07003516 cr2d = superio_inb(sioreg, 0x2d);
Guenter Roecke5c85222017-05-17 18:09:41 -07003517 switch (data->kind) {
3518 case nct6791:
3519 case nct6792:
Guenter Roecka6c54f22018-09-18 09:34:06 -07003520 fan6pin = cr2d & BIT(1);
3521 pwm6pin = cr2d & BIT(0);
Guenter Roecke5c85222017-05-17 18:09:41 -07003522 break;
3523 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003524 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003525 case nct6796:
Guenter Roeck0085a512018-09-18 09:31:21 -07003526 cr1b = superio_inb(sioreg, 0x1b);
3527 cr2a = superio_inb(sioreg, 0x2a);
3528 cr2f = superio_inb(sioreg, 0x2f);
3529 dsw_en = cr2f & BIT(3);
David Bartley578ab5f2013-06-24 22:28:28 -07003530
Guenter Roecke5c85222017-05-17 18:09:41 -07003531 if (!pwm5pin)
Guenter Roecka6c54f22018-09-18 09:34:06 -07003532 pwm5pin = cr2d & BIT(7);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003533
Guenter Roecke5c85222017-05-17 18:09:41 -07003534 if (!fan5pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003535 fan5pin = cr1b & BIT(5);
Guenter Roecke5c85222017-05-17 18:09:41 -07003536
Guenter Roeck81820052018-02-21 13:09:39 -08003537 superio_select(sioreg, NCT6775_LD_12);
3538 if (data->kind != nct6796) {
Guenter Roeck0085a512018-09-18 09:31:21 -07003539 int creb = superio_inb(sioreg, 0xeb);
Guenter Roeck81820052018-02-21 13:09:39 -08003540
3541 if (!dsw_en) {
Guenter Roecka6c54f22018-09-18 09:34:06 -07003542 fan6pin = cr2d & BIT(1);
3543 pwm6pin = cr2d & BIT(0);
Guenter Roeck81820052018-02-21 13:09:39 -08003544 }
3545
3546 if (!fan5pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003547 fan5pin = creb & BIT(5);
Guenter Roeck81820052018-02-21 13:09:39 -08003548 if (!pwm5pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003549 pwm5pin = (creb & BIT(4)) &&
3550 !(cr2a & BIT(0));
Guenter Roeck81820052018-02-21 13:09:39 -08003551 if (!fan6pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003552 fan6pin = creb & BIT(3);
Guenter Roeck81820052018-02-21 13:09:39 -08003553 if (!pwm6pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003554 pwm6pin = creb & BIT(2);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003555 }
3556
Guenter Roeck81820052018-02-21 13:09:39 -08003557 if (data->kind == nct6795 || data->kind == nct6796) {
Guenter Roeck0085a512018-09-18 09:31:21 -07003558 int cred = superio_inb(sioreg, 0xed);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003559
3560 if (!fan6pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003561 fan6pin = (cr2a & BIT(4)) &&
3562 (!dsw_en || (cred & BIT(4)));
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003563 if (!pwm6pin)
Guenter Roeck0085a512018-09-18 09:31:21 -07003564 pwm6pin = (cr2a & BIT(3)) &&
3565 (cred & BIT(2));
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003566 }
Guenter Roeck81820052018-02-21 13:09:39 -08003567
3568 if (data->kind == nct6796) {
Guenter Roeck0085a512018-09-18 09:31:21 -07003569 int cr1d = superio_inb(sioreg, 0x1d);
3570 int cr2b = superio_inb(sioreg, 0x2b);
Guenter Roeck81820052018-02-21 13:09:39 -08003571
Guenter Roeck0085a512018-09-18 09:31:21 -07003572 fan7pin = !(cr2b & BIT(2));
3573 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
Guenter Roeck81820052018-02-21 13:09:39 -08003574 }
3575
Guenter Roecke5c85222017-05-17 18:09:41 -07003576 break;
3577 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003578 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003579 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003580
3581 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003582 }
3583
David Bartley578ab5f2013-06-24 22:28:28 -07003584 /* fan 1 and 2 (0x03) are always present */
3585 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003586 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003587 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003588 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003589 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003590 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003591}
3592
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003593static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3594 int *available, int *mask)
3595{
3596 int i;
3597 u8 src;
3598
3599 for (i = 0; i < data->pwm_num && *available; i++) {
3600 int index;
3601
3602 if (!regp[i])
3603 continue;
3604 src = nct6775_read_value(data, regp[i]);
3605 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003606 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003607 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003608 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003609 continue;
3610
3611 index = __ffs(*available);
3612 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003613 *available &= ~BIT(index);
3614 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003615 }
3616}
3617
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003618static int nct6775_probe(struct platform_device *pdev)
3619{
3620 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003621 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003622 struct nct6775_data *data;
3623 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003624 int i, s, err = 0;
3625 int src, mask, available;
3626 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003627 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003628 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003629 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003630 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003631 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003632 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003633 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003634
3635 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3636 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3637 DRVNAME))
3638 return -EBUSY;
3639
3640 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3641 GFP_KERNEL);
3642 if (!data)
3643 return -ENOMEM;
3644
3645 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003646 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003647 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003648 mutex_init(&data->update_lock);
3649 data->name = nct6775_device_names[data->kind];
3650 data->bank = 0xff; /* Force initial bank selection */
3651 platform_set_drvdata(pdev, data);
3652
3653 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003654 case nct6106:
3655 data->in_num = 9;
3656 data->pwm_num = 3;
3657 data->auto_pwm_num = 4;
3658 data->temp_fixed_num = 3;
3659 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003660 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003661
3662 data->fan_from_reg = fan_from_reg13;
3663 data->fan_from_reg_min = fan_from_reg13;
3664
3665 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003666 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003667 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003668
3669 data->REG_VBAT = NCT6106_REG_VBAT;
3670 data->REG_DIODE = NCT6106_REG_DIODE;
3671 data->DIODE_MASK = NCT6106_DIODE_MASK;
3672 data->REG_VIN = NCT6106_REG_IN;
3673 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3674 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3675 data->REG_TARGET = NCT6106_REG_TARGET;
3676 data->REG_FAN = NCT6106_REG_FAN;
3677 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3678 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3679 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3680 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3681 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3682 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3683 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3684 data->REG_PWM[0] = NCT6106_REG_PWM;
3685 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3686 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3687 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3688 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3689 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3690 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3691 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3692 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3693 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3694 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3695 data->REG_CRITICAL_TEMP_TOLERANCE
3696 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3697 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3698 data->CRITICAL_PWM_ENABLE_MASK
3699 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3700 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3701 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3702 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3703 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3704 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3705 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3706 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3707 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3708 data->REG_ALARM = NCT6106_REG_ALARM;
3709 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003710 data->REG_BEEP = NCT6106_REG_BEEP;
3711 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003712
3713 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003714 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003715 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003716 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003717 reg_temp_over = NCT6106_REG_TEMP_OVER;
3718 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3719 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3720 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3721 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003722 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3723 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003724
3725 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003726 case nct6775:
3727 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003728 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003729 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003730 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003731 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003732 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003733 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003734
3735 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003736 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003737
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003738 data->fan_from_reg = fan_from_reg16;
3739 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003740 data->target_temp_mask = 0x7f;
3741 data->tolerance_mask = 0x0f;
3742 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003743
Guenter Roeckaa136e52012-12-04 03:26:05 -08003744 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003745 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003746 data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003747
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003748 data->REG_CONFIG = NCT6775_REG_CONFIG;
3749 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003750 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003751 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003752 data->REG_VIN = NCT6775_REG_IN;
3753 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3754 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003755 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003756 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003757 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003758 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003759 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003760 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003761 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3762 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3763 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003764 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003765 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3766 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3767 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3768 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003769 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003770 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3771 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3772 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003773 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3774 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3775 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3776 data->REG_CRITICAL_TEMP_TOLERANCE
3777 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003778 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3779 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003780 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003781 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3782 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3783 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3784 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003785 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003786 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003787
3788 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003789 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003790 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003791 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003792 reg_temp_over = NCT6775_REG_TEMP_OVER;
3793 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3794 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3795 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3796 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3797
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003798 break;
3799 case nct6776:
3800 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003801 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003802 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003803 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003804 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003805 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003806 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003807
3808 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003809 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003810
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003811 data->fan_from_reg = fan_from_reg13;
3812 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003813 data->target_temp_mask = 0xff;
3814 data->tolerance_mask = 0x07;
3815 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003816
Guenter Roeckaa136e52012-12-04 03:26:05 -08003817 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003818 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003819 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003820
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003821 data->REG_CONFIG = NCT6775_REG_CONFIG;
3822 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003823 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003824 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003825 data->REG_VIN = NCT6775_REG_IN;
3826 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3827 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003828 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003829 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003830 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003831 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003832 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003833 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003834 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003835 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3836 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003837 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003838 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003839 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3840 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003841 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3842 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003843 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3844 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3845 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003846 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3847 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3848 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3849 data->REG_CRITICAL_TEMP_TOLERANCE
3850 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003851 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3852 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003853 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003854 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3855 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3856 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3857 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003858 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003859 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003860
3861 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003862 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003863 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003864 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003865 reg_temp_over = NCT6775_REG_TEMP_OVER;
3866 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3867 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3868 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3869 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3870
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003871 break;
3872 case nct6779:
3873 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003874 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003875 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003876 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003877 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003878 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003879 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003880
3881 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003882 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003883
Guenter Roeckf6de2982018-09-13 20:01:12 -07003884 data->fan_from_reg = fan_from_reg_rpm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003885 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003886 data->target_temp_mask = 0xff;
3887 data->tolerance_mask = 0x07;
3888 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003889
Guenter Roeckaa136e52012-12-04 03:26:05 -08003890 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003891 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003892 data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003893
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003894 data->REG_CONFIG = NCT6775_REG_CONFIG;
3895 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003896 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003897 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003898 data->REG_VIN = NCT6779_REG_IN;
3899 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3900 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003901 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003902 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003903 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003904 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003905 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003906 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003907 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003908 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3909 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003910 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003911 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003912 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3913 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003914 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3915 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003916 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3917 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3918 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003919 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3920 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3921 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3922 data->REG_CRITICAL_TEMP_TOLERANCE
3923 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003924 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3925 data->CRITICAL_PWM_ENABLE_MASK
3926 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3927 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003928 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3929 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003930 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003931 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3932 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3933 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3934 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003935 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003936 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003937
3938 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003939 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003940 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003941 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003942 reg_temp_over = NCT6779_REG_TEMP_OVER;
3943 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3944 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3945 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3946 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3947
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003948 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003949 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003950 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003951 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003952 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003953 case nct6796:
David Bartley578ab5f2013-06-24 22:28:28 -07003954 data->in_num = 15;
Guenter Roeck81820052018-02-21 13:09:39 -08003955 data->pwm_num = (data->kind == nct6796) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07003956 data->auto_pwm_num = 4;
3957 data->has_fan_div = false;
3958 data->temp_fixed_num = 6;
3959 data->num_temp_alarms = 2;
3960 data->num_temp_beeps = 2;
3961
3962 data->ALARM_BITS = NCT6791_ALARM_BITS;
3963 data->BEEP_BITS = NCT6779_BEEP_BITS;
3964
Guenter Roeckf6de2982018-09-13 20:01:12 -07003965 data->fan_from_reg = fan_from_reg_rpm;
David Bartley578ab5f2013-06-24 22:28:28 -07003966 data->fan_from_reg_min = fan_from_reg13;
3967 data->target_temp_mask = 0xff;
3968 data->tolerance_mask = 0x07;
3969 data->speed_tolerance_limit = 63;
3970
Guenter Roeck50224f42015-10-30 07:52:39 -07003971 switch (data->kind) {
3972 default:
3973 case nct6791:
3974 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003975 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003976 data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003977 break;
3978 case nct6792:
3979 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003980 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003981 data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003982 break;
3983 case nct6793:
3984 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003985 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003986 data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003987 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003988 case nct6795:
3989 data->temp_label = nct6795_temp_label;
3990 data->temp_mask = NCT6795_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003991 data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
Guenter Roeck419220d2017-05-17 18:19:18 -07003992 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003993 case nct6796:
3994 data->temp_label = nct6796_temp_label;
3995 data->temp_mask = NCT6796_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003996 data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
Guenter Roeck81820052018-02-21 13:09:39 -08003997 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07003998 }
David Bartley578ab5f2013-06-24 22:28:28 -07003999
4000 data->REG_CONFIG = NCT6775_REG_CONFIG;
4001 data->REG_VBAT = NCT6775_REG_VBAT;
4002 data->REG_DIODE = NCT6775_REG_DIODE;
4003 data->DIODE_MASK = NCT6775_DIODE_MASK;
4004 data->REG_VIN = NCT6779_REG_IN;
4005 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4006 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
4007 data->REG_TARGET = NCT6775_REG_TARGET;
4008 data->REG_FAN = NCT6779_REG_FAN;
4009 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
4010 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
4011 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
4012 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
4013 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004014 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4015 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07004016 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
4017 data->REG_PWM[0] = NCT6775_REG_PWM;
4018 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4019 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004020 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
4021 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004022 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4023 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4024 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
4025 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4026 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4027 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4028 data->REG_CRITICAL_TEMP_TOLERANCE
4029 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
4030 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4031 data->CRITICAL_PWM_ENABLE_MASK
4032 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4033 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
4034 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4035 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4036 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004037 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4038 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4039 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4040 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004041 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004042 if (data->kind == nct6791)
4043 data->REG_BEEP = NCT6776_REG_BEEP;
4044 else
4045 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004046
4047 reg_temp = NCT6779_REG_TEMP;
4048 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004049 if (data->kind == nct6791) {
4050 reg_temp_mon = NCT6779_REG_TEMP_MON;
4051 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4052 } else {
4053 reg_temp_mon = NCT6792_REG_TEMP_MON;
4054 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4055 }
David Bartley578ab5f2013-06-24 22:28:28 -07004056 reg_temp_over = NCT6779_REG_TEMP_OVER;
4057 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4058 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4059 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4060 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4061
4062 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004063 default:
4064 return -ENODEV;
4065 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004066 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004067 data->have_temp = 0;
4068
4069 /*
4070 * On some boards, not all available temperature sources are monitored,
4071 * even though some of the monitoring registers are unused.
4072 * Get list of unused monitoring registers, then detect if any fan
4073 * controls are configured to use unmonitored temperature sources.
4074 * If so, assign the unmonitored temperature sources to available
4075 * monitoring registers.
4076 */
4077 mask = 0;
4078 available = 0;
4079 for (i = 0; i < num_reg_temp; i++) {
4080 if (reg_temp[i] == 0)
4081 continue;
4082
4083 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004084 if (!src || (mask & BIT(src)))
4085 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004086
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004087 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004088 }
4089
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004090 /*
4091 * Now find unmonitored temperature registers and enable monitoring
4092 * if additional monitoring registers are available.
4093 */
4094 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4095 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4096
Guenter Roeckaa136e52012-12-04 03:26:05 -08004097 mask = 0;
4098 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4099 for (i = 0; i < num_reg_temp; i++) {
4100 if (reg_temp[i] == 0)
4101 continue;
4102
4103 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004104 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004105 continue;
4106
Guenter Roeckcc66b302017-05-17 18:05:06 -07004107 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004108 dev_info(dev,
4109 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4110 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4111 continue;
4112 }
4113
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004114 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004115
4116 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4117 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004118 data->have_temp |= BIT(src - 1);
4119 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004120 data->reg_temp[0][src - 1] = reg_temp[i];
4121 data->reg_temp[1][src - 1] = reg_temp_over[i];
4122 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004123 if (reg_temp_crit_h && reg_temp_crit_h[i])
4124 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4125 else if (reg_temp_crit[src - 1])
4126 data->reg_temp[3][src - 1]
4127 = reg_temp_crit[src - 1];
4128 if (reg_temp_crit_l && reg_temp_crit_l[i])
4129 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004130 data->reg_temp_config[src - 1] = reg_temp_config[i];
4131 data->temp_src[src - 1] = src;
4132 continue;
4133 }
4134
4135 if (s >= NUM_TEMP)
4136 continue;
4137
4138 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004139 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004140 data->reg_temp[0][s] = reg_temp[i];
4141 data->reg_temp[1][s] = reg_temp_over[i];
4142 data->reg_temp[2][s] = reg_temp_hyst[i];
4143 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004144 if (reg_temp_crit_h && reg_temp_crit_h[i])
4145 data->reg_temp[3][s] = reg_temp_crit_h[i];
4146 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004147 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004148 if (reg_temp_crit_l && reg_temp_crit_l[i])
4149 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004150
4151 data->temp_src[s] = src;
4152 s++;
4153 }
4154
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004155 /*
4156 * Repeat with temperatures used for fan control.
4157 * This set of registers does not support limits.
4158 */
4159 for (i = 0; i < num_reg_temp_mon; i++) {
4160 if (reg_temp_mon[i] == 0)
4161 continue;
4162
4163 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004164 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004165 continue;
4166
Guenter Roeckcc66b302017-05-17 18:05:06 -07004167 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004168 dev_info(dev,
4169 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4170 src, i, data->REG_TEMP_SEL[i],
4171 reg_temp_mon[i]);
4172 continue;
4173 }
4174
Guenter Roeck7ce41902016-09-11 12:42:52 -07004175 /*
4176 * For virtual temperature sources, the 'virtual' temperature
4177 * for each fan reflects a different temperature, and there
4178 * are no duplicates.
4179 */
Guenter Roeck37196ba2018-09-13 19:43:58 -07004180 if (!(data->virt_temp_mask & BIT(src))) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004181 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004182 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004183 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004184 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004185
4186 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4187 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004188 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004189 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004190 data->have_temp |= BIT(src - 1);
4191 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004192 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4193 data->temp_src[src - 1] = src;
4194 continue;
4195 }
4196
4197 if (s >= NUM_TEMP)
4198 continue;
4199
4200 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004201 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004202 data->reg_temp[0][s] = reg_temp_mon[i];
4203 data->temp_src[s] = src;
4204 s++;
4205 }
4206
Guenter Roeckaa136e52012-12-04 03:26:05 -08004207#ifdef USE_ALTERNATE
4208 /*
4209 * Go through the list of alternate temp registers and enable
4210 * if possible.
4211 * The temperature is already monitored if the respective bit in <mask>
4212 * is set.
4213 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004214 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004215 if (!(data->temp_mask & BIT(i + 1)))
4216 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004217 if (!reg_temp_alternate[i])
4218 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004219 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004220 continue;
4221 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004222 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004223 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004224 data->have_temp |= BIT(i);
4225 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004226 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004227 if (i < num_reg_temp) {
4228 data->reg_temp[1][i] = reg_temp_over[i];
4229 data->reg_temp[2][i] = reg_temp_hyst[i];
4230 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004231 data->temp_src[i] = i + 1;
4232 continue;
4233 }
4234
4235 if (s >= NUM_TEMP) /* Abort if no more space */
4236 break;
4237
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004238 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004239 data->reg_temp[0][s] = reg_temp_alternate[i];
4240 data->temp_src[s] = i + 1;
4241 s++;
4242 }
4243#endif /* USE_ALTERNATE */
4244
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004245 /* Initialize the chip */
4246 nct6775_init_device(data);
4247
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004248 err = superio_enter(sio_data->sioreg);
4249 if (err)
4250 return err;
4251
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004252 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4253 switch (data->kind) {
4254 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004255 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004256 break;
4257 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004258 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004259 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004260 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004261 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004262 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004263 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004264 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004265 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004266 case nct6796:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004267 break;
4268 }
4269
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004270 /*
4271 * Read VID value
4272 * We can get the VID input values directly at logical device D 0xe3.
4273 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004274 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004275 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4276 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4277 data->vrm = vid_which_vrm();
4278 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004279
4280 if (fan_debounce) {
4281 u8 tmp;
4282
4283 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4284 tmp = superio_inb(sio_data->sioreg,
4285 NCT6775_REG_CR_FAN_DEBOUNCE);
4286 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004287 case nct6106:
4288 tmp |= 0xe0;
4289 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004290 case nct6775:
4291 tmp |= 0x1e;
4292 break;
4293 case nct6776:
4294 case nct6779:
4295 tmp |= 0x3e;
4296 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004297 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004298 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004299 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004300 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004301 case nct6796:
David Bartley578ab5f2013-06-24 22:28:28 -07004302 tmp |= 0x7e;
4303 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004304 }
4305 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4306 tmp);
4307 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4308 data->name);
4309 }
4310
Guenter Roeckdf612d52013-07-08 13:15:04 -07004311 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004312
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004313 superio_exit(sio_data->sioreg);
4314
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004315 /* Read fan clock dividers immediately */
4316 nct6775_init_fan_common(dev, data);
4317
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004318 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004319 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4320 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004321 if (IS_ERR(group))
4322 return PTR_ERR(group);
4323
Axel Lin55bdee62014-07-24 08:59:34 +08004324 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004325
Guenter Roeckf73cf632013-03-18 09:22:50 -07004326 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4327 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004328 if (IS_ERR(group))
4329 return PTR_ERR(group);
4330
Axel Lin55bdee62014-07-24 08:59:34 +08004331 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004332
Guenter Roeckf73cf632013-03-18 09:22:50 -07004333 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4334 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004335 if (IS_ERR(group))
4336 return PTR_ERR(group);
4337
Axel Lin55bdee62014-07-24 08:59:34 +08004338 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004339
Guenter Roeckf73cf632013-03-18 09:22:50 -07004340 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4341 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004342 if (IS_ERR(group))
4343 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004344
Axel Lin55bdee62014-07-24 08:59:34 +08004345 data->groups[num_attr_groups++] = group;
4346 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004347
Guenter Roecka150d952013-07-11 22:55:22 -07004348 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4349 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004350 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004351}
4352
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004353static void nct6791_enable_io_mapping(int sioaddr)
4354{
4355 int val;
4356
4357 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4358 if (val & 0x10) {
4359 pr_info("Enabling hardware monitor logical device mappings.\n");
4360 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4361 val & ~0x10);
4362 }
4363}
4364
Guenter Roeck48e93182015-02-07 08:48:49 -08004365static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004366{
4367 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004368
4369 mutex_lock(&data->update_lock);
4370 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004371 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004372 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4373 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4374 }
4375 mutex_unlock(&data->update_lock);
4376
4377 return 0;
4378}
4379
Guenter Roeck48e93182015-02-07 08:48:49 -08004380static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004381{
4382 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004383 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004384 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004385 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004386
4387 mutex_lock(&data->update_lock);
4388 data->bank = 0xff; /* Force initial bank selection */
4389
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004390 err = superio_enter(sioreg);
4391 if (err)
4392 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004393
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004394 superio_select(sioreg, NCT6775_LD_HWM);
4395 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4396 if (reg != data->sio_reg_enable)
4397 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4398
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004399 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004400 data->kind == nct6793 || data->kind == nct6795 ||
4401 data->kind == nct6796)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004402 nct6791_enable_io_mapping(sioreg);
4403
4404 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004405
Guenter Roeck84d19d92012-12-04 08:01:39 -08004406 /* Restore limits */
4407 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004408 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004409 continue;
4410
4411 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4412 data->in[i][1]);
4413 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4414 data->in[i][2]);
4415 }
4416
Guenter Roeckc409fd42013-04-09 05:04:00 -07004417 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004418 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004419 continue;
4420
4421 nct6775_write_value(data, data->REG_FAN_MIN[i],
4422 data->fan_min[i]);
4423 }
4424
4425 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004426 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004427 continue;
4428
Guenter Roeckc409fd42013-04-09 05:04:00 -07004429 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004430 if (data->reg_temp[j][i])
4431 nct6775_write_temp(data, data->reg_temp[j][i],
4432 data->temp[j][i]);
4433 }
4434
4435 /* Restore other settings */
4436 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004437 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004438 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4439 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4440 }
4441
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004442abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004443 /* Force re-reading all values */
4444 data->valid = false;
4445 mutex_unlock(&data->update_lock);
4446
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004447 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004448}
4449
Guenter Roeck48e93182015-02-07 08:48:49 -08004450static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004451
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004452static struct platform_driver nct6775_driver = {
4453 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004454 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004455 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004456 },
4457 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004458};
4459
4460/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004461static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004462{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004463 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004464 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004465 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004466
4467 err = superio_enter(sioaddr);
4468 if (err)
4469 return err;
4470
Guenter Roeckfc72af32016-08-03 22:07:18 -07004471 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4472 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4473 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004474 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004475
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004476 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004477 case SIO_NCT6106_ID:
4478 sio_data->kind = nct6106;
4479 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004480 case SIO_NCT6775_ID:
4481 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004482 break;
4483 case SIO_NCT6776_ID:
4484 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004485 break;
4486 case SIO_NCT6779_ID:
4487 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004488 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004489 case SIO_NCT6791_ID:
4490 sio_data->kind = nct6791;
4491 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004492 case SIO_NCT6792_ID:
4493 sio_data->kind = nct6792;
4494 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004495 case SIO_NCT6793_ID:
4496 sio_data->kind = nct6793;
4497 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004498 case SIO_NCT6795_ID:
4499 sio_data->kind = nct6795;
4500 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004501 case SIO_NCT6796_ID:
4502 sio_data->kind = nct6796;
4503 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004504 default:
4505 if (val != 0xffff)
4506 pr_debug("unsupported chip ID: 0x%04x\n", val);
4507 superio_exit(sioaddr);
4508 return -ENODEV;
4509 }
4510
4511 /* We have a known chip, find the HWM I/O address */
4512 superio_select(sioaddr, NCT6775_LD_HWM);
4513 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4514 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004515 addr = val & IOREGION_ALIGNMENT;
4516 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004517 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4518 superio_exit(sioaddr);
4519 return -ENODEV;
4520 }
4521
4522 /* Activate logical device if needed */
4523 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4524 if (!(val & 0x01)) {
4525 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4526 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4527 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004528
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004529 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004530 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
4531 sio_data->kind == nct6796)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004532 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004533
4534 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004535 pr_info("Found %s or compatible chip at %#x:%#x\n",
4536 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004537 sio_data->sioreg = sioaddr;
4538
Guenter Roeck698a7c22013-04-05 07:35:25 -07004539 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004540}
4541
4542/*
4543 * when Super-I/O functions move to a separate file, the Super-I/O
4544 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004545 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004546 * must keep track of the device
4547 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004548static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004549
4550static int __init sensors_nct6775_init(void)
4551{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004552 int i, err;
4553 bool found = false;
4554 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004555 struct resource res;
4556 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004557 int sioaddr[2] = { 0x2e, 0x4e };
4558
4559 err = platform_driver_register(&nct6775_driver);
4560 if (err)
4561 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004562
4563 /*
4564 * initialize sio_data->kind and sio_data->sioreg.
4565 *
4566 * when Super-I/O functions move to a separate file, the Super-I/O
4567 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4568 * nct6775 hardware monitor, and call probe()
4569 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004570 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4571 address = nct6775_find(sioaddr[i], &sio_data);
4572 if (address <= 0)
4573 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004574
Guenter Roeck698a7c22013-04-05 07:35:25 -07004575 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004576
Guenter Roeck698a7c22013-04-05 07:35:25 -07004577 pdev[i] = platform_device_alloc(DRVNAME, address);
4578 if (!pdev[i]) {
4579 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004580 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004581 }
4582
4583 err = platform_device_add_data(pdev[i], &sio_data,
4584 sizeof(struct nct6775_sio_data));
4585 if (err)
4586 goto exit_device_put;
4587
4588 memset(&res, 0, sizeof(res));
4589 res.name = DRVNAME;
4590 res.start = address + IOREGION_OFFSET;
4591 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4592 res.flags = IORESOURCE_IO;
4593
4594 err = acpi_check_resource_conflict(&res);
4595 if (err) {
4596 platform_device_put(pdev[i]);
4597 pdev[i] = NULL;
4598 continue;
4599 }
4600
4601 err = platform_device_add_resources(pdev[i], &res, 1);
4602 if (err)
4603 goto exit_device_put;
4604
4605 /* platform_device_add calls probe() */
4606 err = platform_device_add(pdev[i]);
4607 if (err)
4608 goto exit_device_put;
4609 }
4610 if (!found) {
4611 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004612 goto exit_unregister;
4613 }
4614
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004615 return 0;
4616
4617exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004618 platform_device_put(pdev[i]);
4619exit_device_unregister:
4620 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004621 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004622 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004623 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004624exit_unregister:
4625 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004626 return err;
4627}
4628
4629static void __exit sensors_nct6775_exit(void)
4630{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004631 int i;
4632
4633 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4634 if (pdev[i])
4635 platform_device_unregister(pdev[i]);
4636 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004637 platform_driver_unregister(&nct6775_driver);
4638}
4639
4640MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004641MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004642MODULE_LICENSE("GPL");
4643
4644module_init(sensors_nct6775_init);
4645module_exit(sensors_nct6775_exit);