blob: 202a2b422461618b2bef4c216f02c74754e6d5c4 [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 Roeck81820052018-02-21 13:09:39 -0800505 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x660 };
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 Roeckcdcaece2012-12-04 09:04:52 -0800927static u16 fan_to_reg(u32 fan, unsigned int divreg)
928{
929 if (!fan)
930 return 0;
931
932 return (1350000U / fan) >> divreg;
933}
934
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800935static inline unsigned int
936div_from_reg(u8 reg)
937{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700938 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800939}
940
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700941/*
942 * Some of the voltage inputs have internal scaling, the tables below
943 * contain 8 (the ADC LSB in mV) * scaling factor * 100
944 */
945static const u16 scale_in[15] = {
946 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
947 800, 800
948};
949
950static inline long in_from_reg(u8 reg, u8 nr)
951{
952 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
953}
954
955static inline u8 in_to_reg(u32 val, u8 nr)
956{
957 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
958}
959
960/*
961 * Data structures and manipulation thereof
962 */
963
964struct nct6775_data {
965 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700966 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700967 enum kinds kind;
968 const char *name;
969
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700970 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700971
Guenter Roeckb7a61352013-04-02 22:14:06 -0700972 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
973 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800974 */
975 u8 temp_src[NUM_TEMP];
976 u16 reg_temp_config[NUM_TEMP];
977 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700978 u32 temp_mask;
Guenter Roeck37196ba2018-09-13 19:43:58 -0700979 u32 virt_temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800980
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700981 u16 REG_CONFIG;
982 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800983 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700984 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700985
986 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700987 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700988
989 const u16 *REG_VIN;
990 const u16 *REG_IN_MINMAX[2];
991
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800992 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800993 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800994 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800995 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800996 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700997 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800998 const u16 *REG_FAN_TIME[3];
999
1000 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001001
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001002 const u8 *REG_PWM_MODE;
1003 const u8 *PWM_MODE_MASK;
1004
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001005 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1006 * [3]=pwm_max, [4]=pwm_step,
1007 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001008 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001009 const u16 *REG_PWM_READ;
1010
Guenter Roeck6c009502012-07-01 08:23:15 -07001011 const u16 *REG_CRITICAL_PWM_ENABLE;
1012 u8 CRITICAL_PWM_ENABLE_MASK;
1013 const u16 *REG_CRITICAL_PWM;
1014
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001015 const u16 *REG_AUTO_TEMP;
1016 const u16 *REG_AUTO_PWM;
1017
1018 const u16 *REG_CRITICAL_TEMP;
1019 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
1020
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001021 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001022 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001023 const u16 *REG_WEIGHT_TEMP_SEL;
1024 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
1025
Guenter Roeckaa136e52012-12-04 03:26:05 -08001026 const u16 *REG_TEMP_OFFSET;
1027
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001028 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07001029 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001030
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001031 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
1032 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
1033
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001034 struct mutex update_lock;
1035 bool valid; /* true if following fields are valid */
1036 unsigned long last_updated; /* In jiffies */
1037
1038 /* Register values */
1039 u8 bank; /* current register bank */
1040 u8 in_num; /* number of in inputs we have */
1041 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -07001042 unsigned int rpm[NUM_FAN];
1043 u16 fan_min[NUM_FAN];
1044 u8 fan_pulses[NUM_FAN];
1045 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001046 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001047 u8 has_fan; /* some fan inputs can be disabled */
1048 u8 has_fan_min; /* some fans don't have min register */
1049 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001050
Guenter Roeck6c009502012-07-01 08:23:15 -07001051 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001052 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001053 u8 temp_fixed_num; /* 3 or 6 */
1054 u8 temp_type[NUM_TEMP_FIXED];
1055 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001056 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1057 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001058 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001059 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001060
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001061 u8 pwm_num; /* number of pwm */
Guenter Roeck57fec3a2018-06-18 09:21:46 -07001062 u8 pwm_mode[NUM_FAN]; /* 0->DC variable voltage,
1063 * 1->PWM variable duty cycle
David Bartley578ab5f2013-06-24 22:28:28 -07001064 */
1065 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001066 /* 0->off
1067 * 1->manual
1068 * 2->thermal cruise mode (also called SmartFan I)
1069 * 3->fan speed cruise mode
1070 * 4->SmartFan III
1071 * 5->enhanced variable thermal cruise (SmartFan IV)
1072 */
David Bartley578ab5f2013-06-24 22:28:28 -07001073 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1074 * [3]=pwm_max, [4]=pwm_step,
1075 * [5]=weight_duty_step, [6]=weight_duty_base
1076 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001077
David Bartley578ab5f2013-06-24 22:28:28 -07001078 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001079 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001080 u32 target_speed[NUM_FAN];
1081 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001082 u8 speed_tolerance_limit;
1083
David Bartley578ab5f2013-06-24 22:28:28 -07001084 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001085 u8 tolerance_mask;
1086
David Bartley578ab5f2013-06-24 22:28:28 -07001087 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001088
1089 /* Automatic fan speed control registers */
1090 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001091 u8 auto_pwm[NUM_FAN][7];
1092 u8 auto_temp[NUM_FAN][7];
1093 u8 pwm_temp_sel[NUM_FAN];
1094 u8 pwm_weight_temp_sel[NUM_FAN];
1095 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1096 * 2->temp_base
1097 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001098
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001099 u8 vid;
1100 u8 vrm;
1101
Guenter Roeckf73cf632013-03-18 09:22:50 -07001102 bool have_vid;
1103
Guenter Roeckaa136e52012-12-04 03:26:05 -08001104 u16 have_temp;
1105 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001106 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001107
Guenter Roeck84d19d92012-12-04 08:01:39 -08001108 /* Remember extra register values over suspend/resume */
1109 u8 vbat;
1110 u8 fandiv1;
1111 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001112 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001113};
1114
1115struct nct6775_sio_data {
1116 int sioreg;
1117 enum kinds kind;
1118};
1119
Guenter Roeckf73cf632013-03-18 09:22:50 -07001120struct sensor_device_template {
1121 struct device_attribute dev_attr;
1122 union {
1123 struct {
1124 u8 nr;
1125 u8 index;
1126 } s;
1127 int index;
1128 } u;
1129 bool s2; /* true if both index and nr are used */
1130};
1131
1132struct sensor_device_attr_u {
1133 union {
1134 struct sensor_device_attribute a1;
1135 struct sensor_device_attribute_2 a2;
1136 } u;
1137 char name[32];
1138};
1139
1140#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1141 .attr = {.name = _template, .mode = _mode }, \
1142 .show = _show, \
1143 .store = _store, \
1144}
1145
1146#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1147 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1148 .u.index = _index, \
1149 .s2 = false }
1150
1151#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1152 _nr, _index) \
1153 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1154 .u.s.index = _index, \
1155 .u.s.nr = _nr, \
1156 .s2 = true }
1157
1158#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1159static struct sensor_device_template sensor_dev_template_##_name \
1160 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1161 _index)
1162
1163#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1164 _nr, _index) \
1165static struct sensor_device_template sensor_dev_template_##_name \
1166 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1167 _nr, _index)
1168
1169struct sensor_template_group {
1170 struct sensor_device_template **templates;
1171 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1172 int base;
1173};
1174
1175static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001176nct6775_create_attr_group(struct device *dev,
1177 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001178 int repeat)
1179{
1180 struct attribute_group *group;
1181 struct sensor_device_attr_u *su;
1182 struct sensor_device_attribute *a;
1183 struct sensor_device_attribute_2 *a2;
1184 struct attribute **attrs;
1185 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001186 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001187
1188 if (repeat <= 0)
1189 return ERR_PTR(-EINVAL);
1190
1191 t = tg->templates;
1192 for (count = 0; *t; t++, count++)
1193 ;
1194
1195 if (count == 0)
1196 return ERR_PTR(-EINVAL);
1197
1198 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1199 if (group == NULL)
1200 return ERR_PTR(-ENOMEM);
1201
Kees Cooka86854d2018-06-12 14:07:58 -07001202 attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001203 GFP_KERNEL);
1204 if (attrs == NULL)
1205 return ERR_PTR(-ENOMEM);
1206
Kees Cooka86854d2018-06-12 14:07:58 -07001207 su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001208 GFP_KERNEL);
1209 if (su == NULL)
1210 return ERR_PTR(-ENOMEM);
1211
1212 group->attrs = attrs;
1213 group->is_visible = tg->is_visible;
1214
1215 for (i = 0; i < repeat; i++) {
1216 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001217 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001218 snprintf(su->name, sizeof(su->name),
1219 (*t)->dev_attr.attr.name, tg->base + i);
1220 if ((*t)->s2) {
1221 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001222 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001223 a2->dev_attr.attr.name = su->name;
1224 a2->nr = (*t)->u.s.nr + i;
1225 a2->index = (*t)->u.s.index;
1226 a2->dev_attr.attr.mode =
1227 (*t)->dev_attr.attr.mode;
1228 a2->dev_attr.show = (*t)->dev_attr.show;
1229 a2->dev_attr.store = (*t)->dev_attr.store;
1230 *attrs = &a2->dev_attr.attr;
1231 } else {
1232 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001233 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001234 a->dev_attr.attr.name = su->name;
1235 a->index = (*t)->u.index + i;
1236 a->dev_attr.attr.mode =
1237 (*t)->dev_attr.attr.mode;
1238 a->dev_attr.show = (*t)->dev_attr.show;
1239 a->dev_attr.store = (*t)->dev_attr.store;
1240 *attrs = &a->dev_attr.attr;
1241 }
1242 attrs++;
1243 su++;
1244 t++;
1245 }
1246 }
1247
Guenter Roeckf73cf632013-03-18 09:22:50 -07001248 return group;
1249}
1250
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001251static bool is_word_sized(struct nct6775_data *data, u16 reg)
1252{
1253 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001254 case nct6106:
1255 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1256 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1257 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001258 case nct6775:
1259 return (((reg & 0xff00) == 0x100 ||
1260 (reg & 0xff00) == 0x200) &&
1261 ((reg & 0x00ff) == 0x50 ||
1262 (reg & 0x00ff) == 0x53 ||
1263 (reg & 0x00ff) == 0x55)) ||
1264 (reg & 0xfff0) == 0x630 ||
1265 reg == 0x640 || reg == 0x642 ||
1266 reg == 0x662 ||
1267 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1268 reg == 0x73 || reg == 0x75 || reg == 0x77;
1269 case nct6776:
1270 return (((reg & 0xff00) == 0x100 ||
1271 (reg & 0xff00) == 0x200) &&
1272 ((reg & 0x00ff) == 0x50 ||
1273 (reg & 0x00ff) == 0x53 ||
1274 (reg & 0x00ff) == 0x55)) ||
1275 (reg & 0xfff0) == 0x630 ||
1276 reg == 0x402 ||
1277 reg == 0x640 || reg == 0x642 ||
1278 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1279 reg == 0x73 || reg == 0x75 || reg == 0x77;
1280 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001281 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001282 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001283 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001284 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001285 case nct6796:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001286 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001287 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001288 reg == 0x402 ||
1289 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001290 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck81820052018-02-21 13:09:39 -08001291 reg == 0x64c || reg == 0x660 ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001292 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001293 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001294 }
1295 return false;
1296}
1297
1298/*
1299 * On older chips, only registers 0x50-0x5f are banked.
1300 * On more recent chips, all registers are banked.
1301 * Assume that is the case and set the bank number for each access.
1302 * Cache the bank number so it only needs to be set if it changes.
1303 */
1304static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1305{
1306 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001307
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001308 if (data->bank != bank) {
1309 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1310 outb_p(bank, data->addr + DATA_REG_OFFSET);
1311 data->bank = bank;
1312 }
1313}
1314
1315static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1316{
1317 int res, word_sized = is_word_sized(data, reg);
1318
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001319 nct6775_set_bank(data, reg);
1320 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1321 res = inb_p(data->addr + DATA_REG_OFFSET);
1322 if (word_sized) {
1323 outb_p((reg & 0xff) + 1,
1324 data->addr + ADDR_REG_OFFSET);
1325 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1326 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001327 return res;
1328}
1329
1330static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1331{
1332 int word_sized = is_word_sized(data, reg);
1333
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001334 nct6775_set_bank(data, reg);
1335 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1336 if (word_sized) {
1337 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1338 outb_p((reg & 0xff) + 1,
1339 data->addr + ADDR_REG_OFFSET);
1340 }
1341 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001342 return 0;
1343}
1344
Guenter Roeckaa136e52012-12-04 03:26:05 -08001345/* We left-align 8-bit temperature values to make the code simpler */
1346static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1347{
1348 u16 res;
1349
1350 res = nct6775_read_value(data, reg);
1351 if (!is_word_sized(data, reg))
1352 res <<= 8;
1353
1354 return res;
1355}
1356
1357static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1358{
1359 if (!is_word_sized(data, reg))
1360 value >>= 8;
1361 return nct6775_write_value(data, reg, value);
1362}
1363
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001364/* This function assumes that the caller holds data->update_lock */
1365static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1366{
1367 u8 reg;
1368
1369 switch (nr) {
1370 case 0:
1371 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1372 | (data->fan_div[0] & 0x7);
1373 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1374 break;
1375 case 1:
1376 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1377 | ((data->fan_div[1] << 4) & 0x70);
1378 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1379 break;
1380 case 2:
1381 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1382 | (data->fan_div[2] & 0x7);
1383 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1384 break;
1385 case 3:
1386 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1387 | ((data->fan_div[3] << 4) & 0x70);
1388 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1389 break;
1390 }
1391}
1392
1393static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1394{
1395 if (data->kind == nct6775)
1396 nct6775_write_fan_div(data, nr);
1397}
1398
1399static void nct6775_update_fan_div(struct nct6775_data *data)
1400{
1401 u8 i;
1402
1403 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1404 data->fan_div[0] = i & 0x7;
1405 data->fan_div[1] = (i & 0x70) >> 4;
1406 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1407 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001408 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001409 data->fan_div[3] = (i & 0x70) >> 4;
1410}
1411
1412static void nct6775_update_fan_div_common(struct nct6775_data *data)
1413{
1414 if (data->kind == nct6775)
1415 nct6775_update_fan_div(data);
1416}
1417
1418static void nct6775_init_fan_div(struct nct6775_data *data)
1419{
1420 int i;
1421
1422 nct6775_update_fan_div_common(data);
1423 /*
1424 * For all fans, start with highest divider value if the divider
1425 * register is not initialized. This ensures that we get a
1426 * reading from the fan count register, even if it is not optimal.
1427 * We'll compute a better divider later on.
1428 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001429 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001430 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001431 continue;
1432 if (data->fan_div[i] == 0) {
1433 data->fan_div[i] = 7;
1434 nct6775_write_fan_div_common(data, i);
1435 }
1436 }
1437}
1438
1439static void nct6775_init_fan_common(struct device *dev,
1440 struct nct6775_data *data)
1441{
1442 int i;
1443 u8 reg;
1444
1445 if (data->has_fan_div)
1446 nct6775_init_fan_div(data);
1447
1448 /*
1449 * If fan_min is not set (0), set it to 0xff to disable it. This
1450 * prevents the unnecessary warning when fanX_min is reported as 0.
1451 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001452 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001453 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001454 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1455 if (!reg)
1456 nct6775_write_value(data, data->REG_FAN_MIN[i],
1457 data->has_fan_div ? 0xff
1458 : 0xff1f);
1459 }
1460 }
1461}
1462
1463static void nct6775_select_fan_div(struct device *dev,
1464 struct nct6775_data *data, int nr, u16 reg)
1465{
1466 u8 fan_div = data->fan_div[nr];
1467 u16 fan_min;
1468
1469 if (!data->has_fan_div)
1470 return;
1471
1472 /*
1473 * If we failed to measure the fan speed, or the reported value is not
1474 * in the optimal range, and the clock divider can be modified,
1475 * let's try that for next time.
1476 */
1477 if (reg == 0x00 && fan_div < 0x07)
1478 fan_div++;
1479 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1480 fan_div--;
1481
1482 if (fan_div != data->fan_div[nr]) {
1483 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1484 nr + 1, div_from_reg(data->fan_div[nr]),
1485 div_from_reg(fan_div));
1486
1487 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001488 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001489 fan_min = data->fan_min[nr];
1490 if (fan_div > data->fan_div[nr]) {
1491 if (fan_min != 255 && fan_min > 1)
1492 fan_min >>= 1;
1493 } else {
1494 if (fan_min != 255) {
1495 fan_min <<= 1;
1496 if (fan_min > 254)
1497 fan_min = 254;
1498 }
1499 }
1500 if (fan_min != data->fan_min[nr]) {
1501 data->fan_min[nr] = fan_min;
1502 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1503 fan_min);
1504 }
1505 }
1506 data->fan_div[nr] = fan_div;
1507 nct6775_write_fan_div_common(data, nr);
1508 }
1509}
1510
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001511static void nct6775_update_pwm(struct device *dev)
1512{
1513 struct nct6775_data *data = dev_get_drvdata(dev);
1514 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001515 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001516 bool duty_is_dc;
1517
1518 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001519 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001520 continue;
1521
1522 duty_is_dc = data->REG_PWM_MODE[i] &&
1523 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1524 & data->PWM_MODE_MASK[i]);
Guenter Roeck415eb2a2018-03-26 19:50:31 -07001525 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001526
1527 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1528 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1529 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1530 data->pwm[j][i]
1531 = nct6775_read_value(data,
1532 data->REG_PWM[j][i]);
1533 }
1534 }
1535
1536 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1537 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001538
1539 if (!data->temp_tolerance[0][i] ||
1540 data->pwm_enable[i] != speed_cruise)
1541 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1542 if (!data->target_speed_tolerance[i] ||
1543 data->pwm_enable[i] == speed_cruise) {
1544 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001545
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001546 if (data->REG_TOLERANCE_H) {
1547 t |= (nct6775_read_value(data,
1548 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1549 }
1550 data->target_speed_tolerance[i] = t;
1551 }
1552
1553 data->temp_tolerance[1][i] =
1554 nct6775_read_value(data,
1555 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1556
1557 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1558 data->pwm_temp_sel[i] = reg & 0x1f;
1559 /* If fan can stop, report floor as 0 */
1560 if (reg & 0x80)
1561 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001562
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001563 if (!data->REG_WEIGHT_TEMP_SEL[i])
1564 continue;
1565
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001566 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1567 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1568 /* If weight is disabled, report weight source as 0 */
Dan Carpentere3f3d7a2018-09-05 10:46:27 +03001569 if (!(reg & 0x80))
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001570 data->pwm_weight_temp_sel[i] = 0;
1571
1572 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001573 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001574 data->weight_temp[j][i]
1575 = nct6775_read_value(data,
1576 data->REG_WEIGHT_TEMP[j][i]);
1577 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001578 }
1579}
1580
1581static void nct6775_update_pwm_limits(struct device *dev)
1582{
1583 struct nct6775_data *data = dev_get_drvdata(dev);
1584 int i, j;
1585 u8 reg;
1586 u16 reg_t;
1587
1588 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001589 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001590 continue;
1591
Guenter Roeckc409fd42013-04-09 05:04:00 -07001592 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001593 data->fan_time[j][i] =
1594 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1595 }
1596
1597 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1598 /* Update only in matching mode or if never updated */
1599 if (!data->target_temp[i] ||
1600 data->pwm_enable[i] == thermal_cruise)
1601 data->target_temp[i] = reg_t & data->target_temp_mask;
1602 if (!data->target_speed[i] ||
1603 data->pwm_enable[i] == speed_cruise) {
1604 if (data->REG_TOLERANCE_H) {
1605 reg_t |= (nct6775_read_value(data,
1606 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1607 }
1608 data->target_speed[i] = reg_t;
1609 }
1610
1611 for (j = 0; j < data->auto_pwm_num; j++) {
1612 data->auto_pwm[i][j] =
1613 nct6775_read_value(data,
1614 NCT6775_AUTO_PWM(data, i, j));
1615 data->auto_temp[i][j] =
1616 nct6775_read_value(data,
1617 NCT6775_AUTO_TEMP(data, i, j));
1618 }
1619
1620 /* critical auto_pwm temperature data */
1621 data->auto_temp[i][data->auto_pwm_num] =
1622 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1623
1624 switch (data->kind) {
1625 case nct6775:
1626 reg = nct6775_read_value(data,
1627 NCT6775_REG_CRITICAL_ENAB[i]);
1628 data->auto_pwm[i][data->auto_pwm_num] =
1629 (reg & 0x02) ? 0xff : 0x00;
1630 break;
1631 case nct6776:
1632 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1633 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001634 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001635 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001636 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001637 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001638 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001639 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001640 case nct6796:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001641 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001642 data->REG_CRITICAL_PWM_ENABLE[i]);
1643 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1644 reg = nct6775_read_value(data,
1645 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001646 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001647 reg = 0xff;
1648 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001649 break;
1650 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001651 }
1652}
1653
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001654static struct nct6775_data *nct6775_update_device(struct device *dev)
1655{
1656 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001657 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001658
1659 mutex_lock(&data->update_lock);
1660
Guenter Roeck6445e662013-04-21 09:13:28 -07001661 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001662 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001663 /* Fan clock dividers */
1664 nct6775_update_fan_div_common(data);
1665
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001666 /* Measured voltages and limits */
1667 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001668 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001669 continue;
1670
1671 data->in[i][0] = nct6775_read_value(data,
1672 data->REG_VIN[i]);
1673 data->in[i][1] = nct6775_read_value(data,
1674 data->REG_IN_MINMAX[0][i]);
1675 data->in[i][2] = nct6775_read_value(data,
1676 data->REG_IN_MINMAX[1][i]);
1677 }
1678
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001679 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001680 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001681 u16 reg;
1682
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001683 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001684 continue;
1685
1686 reg = nct6775_read_value(data, data->REG_FAN[i]);
1687 data->rpm[i] = data->fan_from_reg(reg,
1688 data->fan_div[i]);
1689
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001690 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001691 data->fan_min[i] = nct6775_read_value(data,
1692 data->REG_FAN_MIN[i]);
Guenter Roeckc7932792018-09-06 09:47:51 -07001693
1694 if (data->REG_FAN_PULSES[i]) {
1695 data->fan_pulses[i] =
1696 (nct6775_read_value(data,
1697 data->REG_FAN_PULSES[i])
1698 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
1699 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001700
1701 nct6775_select_fan_div(dev, data, i, reg);
1702 }
1703
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001704 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001705 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001706
Guenter Roeckaa136e52012-12-04 03:26:05 -08001707 /* Measured temperatures and limits */
1708 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001709 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001710 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001711 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001712 if (data->reg_temp[j][i])
1713 data->temp[j][i]
1714 = nct6775_read_temp(data,
1715 data->reg_temp[j][i]);
1716 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001717 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001718 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001719 continue;
1720 data->temp_offset[i]
1721 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1722 }
1723
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001724 data->alarms = 0;
1725 for (i = 0; i < NUM_REG_ALARM; i++) {
1726 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001727
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001728 if (!data->REG_ALARM[i])
1729 continue;
1730 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1731 data->alarms |= ((u64)alarm) << (i << 3);
1732 }
1733
Guenter Roeck30846992013-06-24 22:21:59 -07001734 data->beeps = 0;
1735 for (i = 0; i < NUM_REG_BEEP; i++) {
1736 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001737
Guenter Roeck30846992013-06-24 22:21:59 -07001738 if (!data->REG_BEEP[i])
1739 continue;
1740 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1741 data->beeps |= ((u64)beep) << (i << 3);
1742 }
1743
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001744 data->last_updated = jiffies;
1745 data->valid = true;
1746 }
1747
1748 mutex_unlock(&data->update_lock);
1749 return data;
1750}
1751
1752/*
1753 * Sysfs callback functions
1754 */
1755static ssize_t
1756show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1757{
1758 struct nct6775_data *data = nct6775_update_device(dev);
1759 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001760 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001761 int nr = sattr->nr;
1762
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001763 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1764}
1765
1766static ssize_t
1767store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1768 size_t count)
1769{
1770 struct nct6775_data *data = dev_get_drvdata(dev);
1771 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001772 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001773 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001774 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001775 int err;
1776
1777 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001778 if (err < 0)
1779 return err;
1780 mutex_lock(&data->update_lock);
1781 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001782 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001783 data->in[nr][index]);
1784 mutex_unlock(&data->update_lock);
1785 return count;
1786}
1787
1788static ssize_t
1789show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1790{
1791 struct nct6775_data *data = nct6775_update_device(dev);
1792 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1793 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001794
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001795 return sprintf(buf, "%u\n",
1796 (unsigned int)((data->alarms >> nr) & 0x01));
1797}
1798
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001799static int find_temp_source(struct nct6775_data *data, int index, int count)
1800{
1801 int source = data->temp_src[index];
1802 int nr;
1803
1804 for (nr = 0; nr < count; nr++) {
1805 int src;
1806
1807 src = nct6775_read_value(data,
1808 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1809 if (src == source)
1810 return nr;
1811 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001812 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001813}
1814
1815static ssize_t
1816show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1817{
1818 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1819 struct nct6775_data *data = nct6775_update_device(dev);
1820 unsigned int alarm = 0;
1821 int nr;
1822
1823 /*
1824 * For temperatures, there is no fixed mapping from registers to alarm
1825 * bits. Alarm bits are determined by the temperature source mapping.
1826 */
1827 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1828 if (nr >= 0) {
1829 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001830
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001831 alarm = (data->alarms >> bit) & 0x01;
1832 }
1833 return sprintf(buf, "%u\n", alarm);
1834}
1835
Guenter Roeck30846992013-06-24 22:21:59 -07001836static ssize_t
1837show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1838{
1839 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1840 struct nct6775_data *data = nct6775_update_device(dev);
1841 int nr = data->BEEP_BITS[sattr->index];
1842
1843 return sprintf(buf, "%u\n",
1844 (unsigned int)((data->beeps >> nr) & 0x01));
1845}
1846
1847static ssize_t
1848store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1849 size_t count)
1850{
1851 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1852 struct nct6775_data *data = dev_get_drvdata(dev);
1853 int nr = data->BEEP_BITS[sattr->index];
1854 int regindex = nr >> 3;
1855 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001856 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001857
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001858 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001859 if (err < 0)
1860 return err;
1861 if (val > 1)
1862 return -EINVAL;
1863
1864 mutex_lock(&data->update_lock);
1865 if (val)
1866 data->beeps |= (1ULL << nr);
1867 else
1868 data->beeps &= ~(1ULL << nr);
1869 nct6775_write_value(data, data->REG_BEEP[regindex],
1870 (data->beeps >> (regindex << 3)) & 0xff);
1871 mutex_unlock(&data->update_lock);
1872 return count;
1873}
1874
1875static ssize_t
1876show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1877{
1878 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1879 struct nct6775_data *data = nct6775_update_device(dev);
1880 unsigned int beep = 0;
1881 int nr;
1882
1883 /*
1884 * For temperatures, there is no fixed mapping from registers to beep
1885 * enable bits. Beep enable bits are determined by the temperature
1886 * source mapping.
1887 */
1888 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1889 if (nr >= 0) {
1890 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001891
Guenter Roeck30846992013-06-24 22:21:59 -07001892 beep = (data->beeps >> bit) & 0x01;
1893 }
1894 return sprintf(buf, "%u\n", beep);
1895}
1896
1897static ssize_t
1898store_temp_beep(struct device *dev, struct device_attribute *attr,
1899 const char *buf, size_t count)
1900{
1901 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1902 struct nct6775_data *data = dev_get_drvdata(dev);
1903 int nr, bit, regindex;
1904 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001905 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001906
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001907 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001908 if (err < 0)
1909 return err;
1910 if (val > 1)
1911 return -EINVAL;
1912
1913 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1914 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001915 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001916
1917 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1918 regindex = bit >> 3;
1919
1920 mutex_lock(&data->update_lock);
1921 if (val)
1922 data->beeps |= (1ULL << bit);
1923 else
1924 data->beeps &= ~(1ULL << bit);
1925 nct6775_write_value(data, data->REG_BEEP[regindex],
1926 (data->beeps >> (regindex << 3)) & 0xff);
1927 mutex_unlock(&data->update_lock);
1928
1929 return count;
1930}
1931
Guenter Roeckf73cf632013-03-18 09:22:50 -07001932static umode_t nct6775_in_is_visible(struct kobject *kobj,
1933 struct attribute *attr, int index)
1934{
1935 struct device *dev = container_of(kobj, struct device, kobj);
1936 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001937 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001938
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001939 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001940 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001941
Guenter Roeckf73cf632013-03-18 09:22:50 -07001942 return attr->mode;
1943}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001944
Guenter Roeckf73cf632013-03-18 09:22:50 -07001945SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1946SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001947SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1948 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001949SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1950 store_in_reg, 0, 1);
1951SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1952 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001953
Guenter Roeckf73cf632013-03-18 09:22:50 -07001954/*
1955 * nct6775_in_is_visible uses the index into the following array
1956 * to determine if attributes should be created or not.
1957 * Any change in order or content must be matched.
1958 */
1959static struct sensor_device_template *nct6775_attributes_in_template[] = {
1960 &sensor_dev_template_in_input,
1961 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001962 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001963 &sensor_dev_template_in_min,
1964 &sensor_dev_template_in_max,
1965 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001966};
1967
Julia Lawallc60fdf82015-12-12 17:36:39 +01001968static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001969 .templates = nct6775_attributes_in_template,
1970 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001971};
1972
1973static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001974show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1975{
1976 struct nct6775_data *data = nct6775_update_device(dev);
1977 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1978 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001979
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001980 return sprintf(buf, "%d\n", data->rpm[nr]);
1981}
1982
1983static ssize_t
1984show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1985{
1986 struct nct6775_data *data = nct6775_update_device(dev);
1987 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1988 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001989
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001990 return sprintf(buf, "%d\n",
1991 data->fan_from_reg_min(data->fan_min[nr],
1992 data->fan_div[nr]));
1993}
1994
1995static ssize_t
1996show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1997{
1998 struct nct6775_data *data = nct6775_update_device(dev);
1999 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2000 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002001
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002002 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
2003}
2004
2005static ssize_t
2006store_fan_min(struct device *dev, struct device_attribute *attr,
2007 const char *buf, size_t count)
2008{
2009 struct nct6775_data *data = dev_get_drvdata(dev);
2010 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2011 int nr = sattr->index;
2012 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002013 unsigned int reg;
2014 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002015 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002016
2017 err = kstrtoul(buf, 10, &val);
2018 if (err < 0)
2019 return err;
2020
2021 mutex_lock(&data->update_lock);
2022 if (!data->has_fan_div) {
2023 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
2024 if (!val) {
2025 val = 0xff1f;
2026 } else {
2027 if (val > 1350000U)
2028 val = 135000U;
2029 val = 1350000U / val;
2030 val = (val & 0x1f) | ((val << 3) & 0xff00);
2031 }
2032 data->fan_min[nr] = val;
2033 goto write_min; /* Leave fan divider alone */
2034 }
2035 if (!val) {
2036 /* No min limit, alarm disabled */
2037 data->fan_min[nr] = 255;
2038 new_div = data->fan_div[nr]; /* No change */
2039 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
2040 goto write_div;
2041 }
2042 reg = 1350000U / val;
2043 if (reg >= 128 * 255) {
2044 /*
2045 * Speed below this value cannot possibly be represented,
2046 * even with the highest divider (128)
2047 */
2048 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002049 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002050 dev_warn(dev,
2051 "fan%u low limit %lu below minimum %u, set to minimum\n",
2052 nr + 1, val, data->fan_from_reg_min(254, 7));
2053 } else if (!reg) {
2054 /*
2055 * Speed above this value cannot possibly be represented,
2056 * even with the lowest divider (1)
2057 */
2058 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002059 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002060 dev_warn(dev,
2061 "fan%u low limit %lu above maximum %u, set to maximum\n",
2062 nr + 1, val, data->fan_from_reg_min(1, 0));
2063 } else {
2064 /*
2065 * Automatically pick the best divider, i.e. the one such
2066 * that the min limit will correspond to a register value
2067 * in the 96..192 range
2068 */
2069 new_div = 0;
2070 while (reg > 192 && new_div < 7) {
2071 reg >>= 1;
2072 new_div++;
2073 }
2074 data->fan_min[nr] = reg;
2075 }
2076
2077write_div:
2078 /*
2079 * Write both the fan clock divider (if it changed) and the new
2080 * fan min (unconditionally)
2081 */
2082 if (new_div != data->fan_div[nr]) {
2083 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2084 nr + 1, div_from_reg(data->fan_div[nr]),
2085 div_from_reg(new_div));
2086 data->fan_div[nr] = new_div;
2087 nct6775_write_fan_div_common(data, nr);
2088 /* Give the chip time to sample a new speed value */
2089 data->last_updated = jiffies;
2090 }
2091
2092write_min:
2093 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2094 mutex_unlock(&data->update_lock);
2095
2096 return count;
2097}
2098
Guenter Roeck5c25d952012-12-11 07:29:06 -08002099static ssize_t
2100show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2101{
2102 struct nct6775_data *data = nct6775_update_device(dev);
2103 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2104 int p = data->fan_pulses[sattr->index];
2105
2106 return sprintf(buf, "%d\n", p ? : 4);
2107}
2108
2109static ssize_t
2110store_fan_pulses(struct device *dev, struct device_attribute *attr,
2111 const char *buf, size_t count)
2112{
2113 struct nct6775_data *data = dev_get_drvdata(dev);
2114 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2115 int nr = sattr->index;
2116 unsigned long val;
2117 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002118 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002119
2120 err = kstrtoul(buf, 10, &val);
2121 if (err < 0)
2122 return err;
2123
2124 if (val > 4)
2125 return -EINVAL;
2126
2127 mutex_lock(&data->update_lock);
2128 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002129 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2130 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2131 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2132 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002133 mutex_unlock(&data->update_lock);
2134
2135 return count;
2136}
2137
Guenter Roeckf73cf632013-03-18 09:22:50 -07002138static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2139 struct attribute *attr, int index)
2140{
2141 struct device *dev = container_of(kobj, struct device, kobj);
2142 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002143 int fan = index / 6; /* fan index */
2144 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002145
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002146 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002147 return 0;
2148
2149 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2150 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002151 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002152 return 0;
Guenter Roeck81820052018-02-21 13:09:39 -08002153 if (nr == 3 && !data->REG_FAN_PULSES[fan])
2154 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002155 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002156 return 0;
2157 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002158 return 0;
2159
2160 return attr->mode;
2161}
2162
2163SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2164SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2165 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002166SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2167 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002168SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2169 store_fan_pulses, 0);
2170SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2171 store_fan_min, 0);
2172SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2173
2174/*
2175 * nct6775_fan_is_visible uses the index into the following array
2176 * to determine if attributes should be created or not.
2177 * Any change in order or content must be matched.
2178 */
2179static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2180 &sensor_dev_template_fan_input,
2181 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002182 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002183 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002184 &sensor_dev_template_fan_min, /* 4 */
2185 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002186 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002187};
2188
Julia Lawallc60fdf82015-12-12 17:36:39 +01002189static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002190 .templates = nct6775_attributes_fan_template,
2191 .is_visible = nct6775_fan_is_visible,
2192 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002193};
2194
2195static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002196show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2197{
2198 struct nct6775_data *data = nct6775_update_device(dev);
2199 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2200 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002201
Guenter Roeckaa136e52012-12-04 03:26:05 -08002202 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2203}
2204
2205static ssize_t
2206show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2207{
2208 struct nct6775_data *data = nct6775_update_device(dev);
2209 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2210 int nr = sattr->nr;
2211 int index = sattr->index;
2212
2213 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2214}
2215
2216static ssize_t
2217store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2218 size_t count)
2219{
2220 struct nct6775_data *data = dev_get_drvdata(dev);
2221 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2222 int nr = sattr->nr;
2223 int index = sattr->index;
2224 int err;
2225 long val;
2226
2227 err = kstrtol(buf, 10, &val);
2228 if (err < 0)
2229 return err;
2230
2231 mutex_lock(&data->update_lock);
2232 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2233 nct6775_write_temp(data, data->reg_temp[index][nr],
2234 data->temp[index][nr]);
2235 mutex_unlock(&data->update_lock);
2236 return count;
2237}
2238
2239static ssize_t
2240show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2241{
2242 struct nct6775_data *data = nct6775_update_device(dev);
2243 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2244
2245 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2246}
2247
2248static ssize_t
2249store_temp_offset(struct device *dev, struct device_attribute *attr,
2250 const char *buf, size_t count)
2251{
2252 struct nct6775_data *data = dev_get_drvdata(dev);
2253 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2254 int nr = sattr->index;
2255 long val;
2256 int err;
2257
2258 err = kstrtol(buf, 10, &val);
2259 if (err < 0)
2260 return err;
2261
2262 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2263
2264 mutex_lock(&data->update_lock);
2265 data->temp_offset[nr] = val;
2266 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2267 mutex_unlock(&data->update_lock);
2268
2269 return count;
2270}
2271
2272static ssize_t
2273show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2274{
2275 struct nct6775_data *data = nct6775_update_device(dev);
2276 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2277 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002278
Guenter Roeckaa136e52012-12-04 03:26:05 -08002279 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2280}
2281
2282static ssize_t
2283store_temp_type(struct device *dev, struct device_attribute *attr,
2284 const char *buf, size_t count)
2285{
2286 struct nct6775_data *data = nct6775_update_device(dev);
2287 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2288 int nr = sattr->index;
2289 unsigned long val;
2290 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002291 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002292
2293 err = kstrtoul(buf, 10, &val);
2294 if (err < 0)
2295 return err;
2296
2297 if (val != 1 && val != 3 && val != 4)
2298 return -EINVAL;
2299
2300 mutex_lock(&data->update_lock);
2301
2302 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002303 vbit = 0x02 << nr;
2304 dbit = data->DIODE_MASK << nr;
2305 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2306 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002307 switch (val) {
2308 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002309 vbat |= vbit;
2310 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002311 break;
2312 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002313 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002314 break;
2315 case 4: /* thermistor */
2316 break;
2317 }
2318 nct6775_write_value(data, data->REG_VBAT, vbat);
2319 nct6775_write_value(data, data->REG_DIODE, diode);
2320
2321 mutex_unlock(&data->update_lock);
2322 return count;
2323}
2324
Guenter Roeckf73cf632013-03-18 09:22:50 -07002325static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2326 struct attribute *attr, int index)
2327{
2328 struct device *dev = container_of(kobj, struct device, kobj);
2329 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002330 int temp = index / 10; /* temp index */
2331 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002332
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002333 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002334 return 0;
2335
Guenter Roeckcc66b302017-05-17 18:05:06 -07002336 if (nr == 1 && !data->temp_label)
2337 return 0;
2338
Guenter Roeckf73cf632013-03-18 09:22:50 -07002339 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2340 return 0; /* alarm */
2341
Guenter Roeck30846992013-06-24 22:21:59 -07002342 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2343 return 0; /* beep */
2344
2345 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002346 return 0;
2347
Guenter Roeck30846992013-06-24 22:21:59 -07002348 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002349 return 0;
2350
Guenter Roeck30846992013-06-24 22:21:59 -07002351 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002352 return 0;
2353
Guenter Roeck30846992013-06-24 22:21:59 -07002354 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002355 return 0;
2356
2357 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002358 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002359 return 0;
2360
2361 return attr->mode;
2362}
2363
2364SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2365SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2366SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2367 store_temp, 0, 1);
2368SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2369 show_temp, store_temp, 0, 2);
2370SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2371 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002372SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2373 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002374SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2375 show_temp_offset, store_temp_offset, 0);
2376SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2377 store_temp_type, 0);
2378SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002379SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2380 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002381
2382/*
2383 * nct6775_temp_is_visible uses the index into the following array
2384 * to determine if attributes should be created or not.
2385 * Any change in order or content must be matched.
2386 */
2387static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2388 &sensor_dev_template_temp_input,
2389 &sensor_dev_template_temp_label,
2390 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002391 &sensor_dev_template_temp_beep, /* 3 */
2392 &sensor_dev_template_temp_max, /* 4 */
2393 &sensor_dev_template_temp_max_hyst, /* 5 */
2394 &sensor_dev_template_temp_crit, /* 6 */
2395 &sensor_dev_template_temp_lcrit, /* 7 */
2396 &sensor_dev_template_temp_offset, /* 8 */
2397 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002398 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002399};
2400
Julia Lawallc60fdf82015-12-12 17:36:39 +01002401static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002402 .templates = nct6775_attributes_temp_template,
2403 .is_visible = nct6775_temp_is_visible,
2404 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002405};
2406
Guenter Roeckaa136e52012-12-04 03:26:05 -08002407static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002408show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2409{
2410 struct nct6775_data *data = nct6775_update_device(dev);
2411 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2412
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002413 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002414}
2415
2416static ssize_t
2417store_pwm_mode(struct device *dev, struct device_attribute *attr,
2418 const char *buf, size_t count)
2419{
2420 struct nct6775_data *data = dev_get_drvdata(dev);
2421 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2422 int nr = sattr->index;
2423 unsigned long val;
2424 int err;
2425 u8 reg;
2426
2427 err = kstrtoul(buf, 10, &val);
2428 if (err < 0)
2429 return err;
2430
2431 if (val > 1)
2432 return -EINVAL;
2433
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002434 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002435 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002436 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002437 return -EINVAL;
2438 return count;
2439 }
2440
2441 mutex_lock(&data->update_lock);
2442 data->pwm_mode[nr] = val;
2443 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2444 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002445 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002446 reg |= data->PWM_MODE_MASK[nr];
2447 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2448 mutex_unlock(&data->update_lock);
2449 return count;
2450}
2451
2452static ssize_t
2453show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2454{
2455 struct nct6775_data *data = nct6775_update_device(dev);
2456 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2457 int nr = sattr->nr;
2458 int index = sattr->index;
2459 int pwm;
2460
2461 /*
2462 * For automatic fan control modes, show current pwm readings.
2463 * Otherwise, show the configured value.
2464 */
2465 if (index == 0 && data->pwm_enable[nr] > manual)
2466 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2467 else
2468 pwm = data->pwm[index][nr];
2469
2470 return sprintf(buf, "%d\n", pwm);
2471}
2472
2473static ssize_t
2474store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2475 size_t count)
2476{
2477 struct nct6775_data *data = dev_get_drvdata(dev);
2478 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2479 int nr = sattr->nr;
2480 int index = sattr->index;
2481 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002482 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2483 int maxval[7]
2484 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002485 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002486 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002487
2488 err = kstrtoul(buf, 10, &val);
2489 if (err < 0)
2490 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002491 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002492
2493 mutex_lock(&data->update_lock);
2494 data->pwm[index][nr] = val;
2495 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002496 if (index == 2) { /* floor: disable if val == 0 */
2497 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2498 reg &= 0x7f;
2499 if (val)
2500 reg |= 0x80;
2501 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2502 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002503 mutex_unlock(&data->update_lock);
2504 return count;
2505}
2506
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002507/* Returns 0 if OK, -EINVAL otherwise */
2508static int check_trip_points(struct nct6775_data *data, int nr)
2509{
2510 int i;
2511
2512 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2513 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2514 return -EINVAL;
2515 }
2516 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2517 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2518 return -EINVAL;
2519 }
2520 /* validate critical temperature and pwm if enabled (pwm > 0) */
2521 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2522 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2523 data->auto_temp[nr][data->auto_pwm_num] ||
2524 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2525 data->auto_pwm[nr][data->auto_pwm_num])
2526 return -EINVAL;
2527 }
2528 return 0;
2529}
2530
2531static void pwm_update_registers(struct nct6775_data *data, int nr)
2532{
2533 u8 reg;
2534
2535 switch (data->pwm_enable[nr]) {
2536 case off:
2537 case manual:
2538 break;
2539 case speed_cruise:
2540 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2541 reg = (reg & ~data->tolerance_mask) |
2542 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2543 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2544 nct6775_write_value(data, data->REG_TARGET[nr],
2545 data->target_speed[nr] & 0xff);
2546 if (data->REG_TOLERANCE_H) {
2547 reg = (data->target_speed[nr] >> 8) & 0x0f;
2548 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2549 nct6775_write_value(data,
2550 data->REG_TOLERANCE_H[nr],
2551 reg);
2552 }
2553 break;
2554 case thermal_cruise:
2555 nct6775_write_value(data, data->REG_TARGET[nr],
2556 data->target_temp[nr]);
Gustavo A. R. Silvaffb32432018-07-02 16:30:17 -05002557 /* fall through */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002558 default:
2559 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2560 reg = (reg & ~data->tolerance_mask) |
2561 data->temp_tolerance[0][nr];
2562 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2563 break;
2564 }
2565}
2566
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002567static ssize_t
2568show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2569{
2570 struct nct6775_data *data = nct6775_update_device(dev);
2571 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2572
2573 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2574}
2575
2576static ssize_t
2577store_pwm_enable(struct device *dev, struct device_attribute *attr,
2578 const char *buf, size_t count)
2579{
2580 struct nct6775_data *data = dev_get_drvdata(dev);
2581 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2582 int nr = sattr->index;
2583 unsigned long val;
2584 int err;
2585 u16 reg;
2586
2587 err = kstrtoul(buf, 10, &val);
2588 if (err < 0)
2589 return err;
2590
2591 if (val > sf4)
2592 return -EINVAL;
2593
2594 if (val == sf3 && data->kind != nct6775)
2595 return -EINVAL;
2596
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002597 if (val == sf4 && check_trip_points(data, nr)) {
2598 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2599 dev_err(dev, "Adjust trip points and try again\n");
2600 return -EINVAL;
2601 }
2602
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002603 mutex_lock(&data->update_lock);
2604 data->pwm_enable[nr] = val;
2605 if (val == off) {
2606 /*
2607 * turn off pwm control: select manual mode, set pwm to maximum
2608 */
2609 data->pwm[0][nr] = 255;
2610 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2611 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002612 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002613 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2614 reg &= 0x0f;
2615 reg |= pwm_enable_to_reg(val) << 4;
2616 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2617 mutex_unlock(&data->update_lock);
2618 return count;
2619}
2620
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002621static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002622show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002623{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002624 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002625
2626 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002627 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002628 continue;
2629 if (src == data->temp_src[i]) {
2630 sel = i + 1;
2631 break;
2632 }
2633 }
2634
2635 return sprintf(buf, "%d\n", sel);
2636}
2637
2638static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002639show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2640{
2641 struct nct6775_data *data = nct6775_update_device(dev);
2642 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2643 int index = sattr->index;
2644
2645 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2646}
2647
2648static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002649store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2650 const char *buf, size_t count)
2651{
2652 struct nct6775_data *data = nct6775_update_device(dev);
2653 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2654 int nr = sattr->index;
2655 unsigned long val;
2656 int err, reg, src;
2657
2658 err = kstrtoul(buf, 10, &val);
2659 if (err < 0)
2660 return err;
2661 if (val == 0 || val > NUM_TEMP)
2662 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002663 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002664 return -EINVAL;
2665
2666 mutex_lock(&data->update_lock);
2667 src = data->temp_src[val - 1];
2668 data->pwm_temp_sel[nr] = src;
2669 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2670 reg &= 0xe0;
2671 reg |= src;
2672 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2673 mutex_unlock(&data->update_lock);
2674
2675 return count;
2676}
2677
2678static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002679show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2680 char *buf)
2681{
2682 struct nct6775_data *data = nct6775_update_device(dev);
2683 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2684 int index = sattr->index;
2685
2686 return show_pwm_temp_sel_common(data, buf,
2687 data->pwm_weight_temp_sel[index]);
2688}
2689
2690static ssize_t
2691store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2692 const char *buf, size_t count)
2693{
2694 struct nct6775_data *data = nct6775_update_device(dev);
2695 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2696 int nr = sattr->index;
2697 unsigned long val;
2698 int err, reg, src;
2699
2700 err = kstrtoul(buf, 10, &val);
2701 if (err < 0)
2702 return err;
2703 if (val > NUM_TEMP)
2704 return -EINVAL;
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -05002705 val = array_index_nospec(val, NUM_TEMP + 1);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002706 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002707 !data->temp_src[val - 1]))
2708 return -EINVAL;
2709
2710 mutex_lock(&data->update_lock);
2711 if (val) {
2712 src = data->temp_src[val - 1];
2713 data->pwm_weight_temp_sel[nr] = src;
2714 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2715 reg &= 0xe0;
2716 reg |= (src | 0x80);
2717 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2718 } else {
2719 data->pwm_weight_temp_sel[nr] = 0;
2720 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2721 reg &= 0x7f;
2722 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2723 }
2724 mutex_unlock(&data->update_lock);
2725
2726 return count;
2727}
2728
2729static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002730show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2731{
2732 struct nct6775_data *data = nct6775_update_device(dev);
2733 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2734
2735 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2736}
2737
2738static ssize_t
2739store_target_temp(struct device *dev, struct device_attribute *attr,
2740 const char *buf, size_t count)
2741{
2742 struct nct6775_data *data = dev_get_drvdata(dev);
2743 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2744 int nr = sattr->index;
2745 unsigned long val;
2746 int err;
2747
2748 err = kstrtoul(buf, 10, &val);
2749 if (err < 0)
2750 return err;
2751
2752 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2753 data->target_temp_mask);
2754
2755 mutex_lock(&data->update_lock);
2756 data->target_temp[nr] = val;
2757 pwm_update_registers(data, nr);
2758 mutex_unlock(&data->update_lock);
2759 return count;
2760}
2761
2762static ssize_t
2763show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2764{
2765 struct nct6775_data *data = nct6775_update_device(dev);
2766 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2767 int nr = sattr->index;
2768
2769 return sprintf(buf, "%d\n",
2770 fan_from_reg16(data->target_speed[nr],
2771 data->fan_div[nr]));
2772}
2773
2774static ssize_t
2775store_target_speed(struct device *dev, struct device_attribute *attr,
2776 const char *buf, size_t count)
2777{
2778 struct nct6775_data *data = dev_get_drvdata(dev);
2779 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2780 int nr = sattr->index;
2781 unsigned long val;
2782 int err;
2783 u16 speed;
2784
2785 err = kstrtoul(buf, 10, &val);
2786 if (err < 0)
2787 return err;
2788
2789 val = clamp_val(val, 0, 1350000U);
2790 speed = fan_to_reg(val, data->fan_div[nr]);
2791
2792 mutex_lock(&data->update_lock);
2793 data->target_speed[nr] = speed;
2794 pwm_update_registers(data, nr);
2795 mutex_unlock(&data->update_lock);
2796 return count;
2797}
2798
2799static ssize_t
2800show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2801 char *buf)
2802{
2803 struct nct6775_data *data = nct6775_update_device(dev);
2804 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2805 int nr = sattr->nr;
2806 int index = sattr->index;
2807
2808 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2809}
2810
2811static ssize_t
2812store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2813 const char *buf, size_t count)
2814{
2815 struct nct6775_data *data = dev_get_drvdata(dev);
2816 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2817 int nr = sattr->nr;
2818 int index = sattr->index;
2819 unsigned long val;
2820 int err;
2821
2822 err = kstrtoul(buf, 10, &val);
2823 if (err < 0)
2824 return err;
2825
2826 /* Limit tolerance as needed */
2827 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2828
2829 mutex_lock(&data->update_lock);
2830 data->temp_tolerance[index][nr] = val;
2831 if (index)
2832 pwm_update_registers(data, nr);
2833 else
2834 nct6775_write_value(data,
2835 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2836 val);
2837 mutex_unlock(&data->update_lock);
2838 return count;
2839}
2840
2841/*
2842 * Fan speed tolerance is a tricky beast, since the associated register is
2843 * a tick counter, but the value is reported and configured as rpm.
2844 * Compute resulting low and high rpm values and report the difference.
2845 */
2846static ssize_t
2847show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2848 char *buf)
2849{
2850 struct nct6775_data *data = nct6775_update_device(dev);
2851 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2852 int nr = sattr->index;
2853 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2854 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2855 int tolerance;
2856
2857 if (low <= 0)
2858 low = 1;
2859 if (high > 0xffff)
2860 high = 0xffff;
2861 if (high < low)
2862 high = low;
2863
2864 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2865 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2866
2867 return sprintf(buf, "%d\n", tolerance);
2868}
2869
2870static ssize_t
2871store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2872 const char *buf, size_t count)
2873{
2874 struct nct6775_data *data = dev_get_drvdata(dev);
2875 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2876 int nr = sattr->index;
2877 unsigned long val;
2878 int err;
2879 int low, high;
2880
2881 err = kstrtoul(buf, 10, &val);
2882 if (err < 0)
2883 return err;
2884
2885 high = fan_from_reg16(data->target_speed[nr],
2886 data->fan_div[nr]) + val;
2887 low = fan_from_reg16(data->target_speed[nr],
2888 data->fan_div[nr]) - val;
2889 if (low <= 0)
2890 low = 1;
2891 if (high < low)
2892 high = low;
2893
2894 val = (fan_to_reg(low, data->fan_div[nr]) -
2895 fan_to_reg(high, data->fan_div[nr])) / 2;
2896
2897 /* Limit tolerance as needed */
2898 val = clamp_val(val, 0, data->speed_tolerance_limit);
2899
2900 mutex_lock(&data->update_lock);
2901 data->target_speed_tolerance[nr] = val;
2902 pwm_update_registers(data, nr);
2903 mutex_unlock(&data->update_lock);
2904 return count;
2905}
2906
Guenter Roeckf73cf632013-03-18 09:22:50 -07002907SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2908SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2909 store_pwm_mode, 0);
2910SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2911 store_pwm_enable, 0);
2912SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2913 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2914SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2915 show_target_temp, store_target_temp, 0);
2916SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2917 show_target_speed, store_target_speed, 0);
2918SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2919 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002920
2921/* Smart Fan registers */
2922
2923static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002924show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2925{
2926 struct nct6775_data *data = nct6775_update_device(dev);
2927 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2928 int nr = sattr->nr;
2929 int index = sattr->index;
2930
2931 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2932}
2933
2934static ssize_t
2935store_weight_temp(struct device *dev, struct device_attribute *attr,
2936 const char *buf, size_t count)
2937{
2938 struct nct6775_data *data = dev_get_drvdata(dev);
2939 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2940 int nr = sattr->nr;
2941 int index = sattr->index;
2942 unsigned long val;
2943 int err;
2944
2945 err = kstrtoul(buf, 10, &val);
2946 if (err < 0)
2947 return err;
2948
2949 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2950
2951 mutex_lock(&data->update_lock);
2952 data->weight_temp[index][nr] = val;
2953 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2954 mutex_unlock(&data->update_lock);
2955 return count;
2956}
2957
Guenter Roeckf73cf632013-03-18 09:22:50 -07002958SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2959 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2960SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2961 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2962SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2963 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2964SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2965 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2966SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2967 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2968SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2969 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002970
2971static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002972show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2973{
2974 struct nct6775_data *data = nct6775_update_device(dev);
2975 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2976 int nr = sattr->nr;
2977 int index = sattr->index;
2978
2979 return sprintf(buf, "%d\n",
2980 step_time_from_reg(data->fan_time[index][nr],
2981 data->pwm_mode[nr]));
2982}
2983
2984static ssize_t
2985store_fan_time(struct device *dev, struct device_attribute *attr,
2986 const char *buf, size_t count)
2987{
2988 struct nct6775_data *data = dev_get_drvdata(dev);
2989 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2990 int nr = sattr->nr;
2991 int index = sattr->index;
2992 unsigned long val;
2993 int err;
2994
2995 err = kstrtoul(buf, 10, &val);
2996 if (err < 0)
2997 return err;
2998
2999 val = step_time_to_reg(val, data->pwm_mode[nr]);
3000 mutex_lock(&data->update_lock);
3001 data->fan_time[index][nr] = val;
3002 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
3003 mutex_unlock(&data->update_lock);
3004 return count;
3005}
3006
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003007static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003008show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3009{
3010 struct nct6775_data *data = nct6775_update_device(dev);
3011 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3012
3013 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3014}
3015
3016static ssize_t
3017store_auto_pwm(struct device *dev, struct device_attribute *attr,
3018 const char *buf, size_t count)
3019{
3020 struct nct6775_data *data = dev_get_drvdata(dev);
3021 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3022 int nr = sattr->nr;
3023 int point = sattr->index;
3024 unsigned long val;
3025 int err;
3026 u8 reg;
3027
3028 err = kstrtoul(buf, 10, &val);
3029 if (err < 0)
3030 return err;
3031 if (val > 255)
3032 return -EINVAL;
3033
3034 if (point == data->auto_pwm_num) {
3035 if (data->kind != nct6775 && !val)
3036 return -EINVAL;
3037 if (data->kind != nct6779 && val)
3038 val = 0xff;
3039 }
3040
3041 mutex_lock(&data->update_lock);
3042 data->auto_pwm[nr][point] = val;
3043 if (point < data->auto_pwm_num) {
3044 nct6775_write_value(data,
3045 NCT6775_AUTO_PWM(data, nr, point),
3046 data->auto_pwm[nr][point]);
3047 } else {
3048 switch (data->kind) {
3049 case nct6775:
3050 /* disable if needed (pwm == 0) */
3051 reg = nct6775_read_value(data,
3052 NCT6775_REG_CRITICAL_ENAB[nr]);
3053 if (val)
3054 reg |= 0x02;
3055 else
3056 reg &= ~0x02;
3057 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3058 reg);
3059 break;
3060 case nct6776:
3061 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003062 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003063 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003064 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003065 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003066 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003067 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003068 case nct6796:
Guenter Roeck6c009502012-07-01 08:23:15 -07003069 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003070 val);
3071 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003072 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003073 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003074 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003075 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003076 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003077 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003078 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003079 reg);
3080 break;
3081 }
3082 }
3083 mutex_unlock(&data->update_lock);
3084 return count;
3085}
3086
3087static ssize_t
3088show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3089{
3090 struct nct6775_data *data = nct6775_update_device(dev);
3091 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3092 int nr = sattr->nr;
3093 int point = sattr->index;
3094
3095 /*
3096 * We don't know for sure if the temperature is signed or unsigned.
3097 * Assume it is unsigned.
3098 */
3099 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3100}
3101
3102static ssize_t
3103store_auto_temp(struct device *dev, struct device_attribute *attr,
3104 const char *buf, size_t count)
3105{
3106 struct nct6775_data *data = dev_get_drvdata(dev);
3107 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3108 int nr = sattr->nr;
3109 int point = sattr->index;
3110 unsigned long val;
3111 int err;
3112
3113 err = kstrtoul(buf, 10, &val);
3114 if (err)
3115 return err;
3116 if (val > 255000)
3117 return -EINVAL;
3118
3119 mutex_lock(&data->update_lock);
3120 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3121 if (point < data->auto_pwm_num) {
3122 nct6775_write_value(data,
3123 NCT6775_AUTO_TEMP(data, nr, point),
3124 data->auto_temp[nr][point]);
3125 } else {
3126 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3127 data->auto_temp[nr][point]);
3128 }
3129 mutex_unlock(&data->update_lock);
3130 return count;
3131}
3132
Guenter Roeckf73cf632013-03-18 09:22:50 -07003133static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3134 struct attribute *attr, int index)
3135{
3136 struct device *dev = container_of(kobj, struct device, kobj);
3137 struct nct6775_data *data = dev_get_drvdata(dev);
3138 int pwm = index / 36; /* pwm index */
3139 int nr = index % 36; /* attribute index */
3140
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003141 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003142 return 0;
3143
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003144 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3145 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3146 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003147 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3148 return 0;
3149 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3150 return 0;
3151 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3152 return 0;
3153
3154 if (nr >= 22 && nr <= 35) { /* auto point */
3155 int api = (nr - 22) / 2; /* auto point index */
3156
3157 if (api > data->auto_pwm_num)
3158 return 0;
3159 }
3160 return attr->mode;
3161}
3162
3163SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3164 show_fan_time, store_fan_time, 0, 0);
3165SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3166 show_fan_time, store_fan_time, 0, 1);
3167SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3168 show_fan_time, store_fan_time, 0, 2);
3169SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3170 store_pwm, 0, 1);
3171SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3172 store_pwm, 0, 2);
3173SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3174 show_temp_tolerance, store_temp_tolerance, 0, 0);
3175SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3176 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3177 0, 1);
3178
3179SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3180 0, 3);
3181
3182SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3183 store_pwm, 0, 4);
3184
3185SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3186 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3187SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3188 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3189
3190SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3191 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3192SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3193 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3194
3195SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3196 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3197SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3198 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3199
3200SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3201 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3202SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3203 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3204
3205SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3206 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3207SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3208 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3209
3210SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3211 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3212SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3213 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3214
3215SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3216 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3217SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3218 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3219
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003220/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003221 * nct6775_pwm_is_visible uses the index into the following array
3222 * to determine if attributes should be created or not.
3223 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003224 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003225static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3226 &sensor_dev_template_pwm,
3227 &sensor_dev_template_pwm_mode,
3228 &sensor_dev_template_pwm_enable,
3229 &sensor_dev_template_pwm_temp_sel,
3230 &sensor_dev_template_pwm_temp_tolerance,
3231 &sensor_dev_template_pwm_crit_temp_tolerance,
3232 &sensor_dev_template_pwm_target_temp,
3233 &sensor_dev_template_fan_target,
3234 &sensor_dev_template_fan_tolerance,
3235 &sensor_dev_template_pwm_stop_time,
3236 &sensor_dev_template_pwm_step_up_time,
3237 &sensor_dev_template_pwm_step_down_time,
3238 &sensor_dev_template_pwm_start,
3239 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003240 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003241 &sensor_dev_template_pwm_weight_temp_step,
3242 &sensor_dev_template_pwm_weight_temp_step_tol,
3243 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003244 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003245 &sensor_dev_template_pwm_max, /* 19 */
3246 &sensor_dev_template_pwm_step, /* 20 */
3247 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3248 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3249 &sensor_dev_template_pwm_auto_point1_temp,
3250 &sensor_dev_template_pwm_auto_point2_pwm,
3251 &sensor_dev_template_pwm_auto_point2_temp,
3252 &sensor_dev_template_pwm_auto_point3_pwm,
3253 &sensor_dev_template_pwm_auto_point3_temp,
3254 &sensor_dev_template_pwm_auto_point4_pwm,
3255 &sensor_dev_template_pwm_auto_point4_temp,
3256 &sensor_dev_template_pwm_auto_point5_pwm,
3257 &sensor_dev_template_pwm_auto_point5_temp,
3258 &sensor_dev_template_pwm_auto_point6_pwm,
3259 &sensor_dev_template_pwm_auto_point6_temp,
3260 &sensor_dev_template_pwm_auto_point7_pwm,
3261 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003262
Guenter Roeckf73cf632013-03-18 09:22:50 -07003263 NULL
3264};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003265
Julia Lawallc60fdf82015-12-12 17:36:39 +01003266static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003267 .templates = nct6775_attributes_pwm_template,
3268 .is_visible = nct6775_pwm_is_visible,
3269 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003270};
3271
3272static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003273cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003274{
3275 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003276
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003277 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3278}
3279
Julia Lawall93d72ac2016-12-22 13:05:23 +01003280static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003281
Guenter Roecka6bd5872012-12-04 03:13:34 -08003282/* Case open detection */
3283
3284static ssize_t
3285clear_caseopen(struct device *dev, struct device_attribute *attr,
3286 const char *buf, size_t count)
3287{
3288 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003289 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3290 unsigned long val;
3291 u8 reg;
3292 int ret;
3293
3294 if (kstrtoul(buf, 10, &val) || val != 0)
3295 return -EINVAL;
3296
3297 mutex_lock(&data->update_lock);
3298
3299 /*
3300 * Use CR registers to clear caseopen status.
3301 * The CR registers are the same for all chips, and not all chips
3302 * support clearing the caseopen status through "regular" registers.
3303 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003304 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003305 if (ret) {
3306 count = ret;
3307 goto error;
3308 }
3309
Guenter Roeckdf612d52013-07-08 13:15:04 -07003310 superio_select(data->sioreg, NCT6775_LD_ACPI);
3311 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003312 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003313 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003314 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003315 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3316 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003317
3318 data->valid = false; /* Force cache refresh */
3319error:
3320 mutex_unlock(&data->update_lock);
3321 return count;
3322}
3323
Guenter Roeckf73cf632013-03-18 09:22:50 -07003324static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3325 clear_caseopen, INTRUSION_ALARM_BASE);
3326static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3327 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003328static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3329 store_beep, INTRUSION_ALARM_BASE);
3330static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3331 store_beep, INTRUSION_ALARM_BASE + 1);
3332static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3333 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003334
3335static umode_t nct6775_other_is_visible(struct kobject *kobj,
3336 struct attribute *attr, int index)
3337{
3338 struct device *dev = container_of(kobj, struct device, kobj);
3339 struct nct6775_data *data = dev_get_drvdata(dev);
3340
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003341 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003342 return 0;
3343
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003344 if (index == 1 || index == 2) {
3345 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003346 return 0;
3347 }
3348
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003349 if (index == 3 || index == 4) {
3350 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003351 return 0;
3352 }
3353
Guenter Roeckf73cf632013-03-18 09:22:50 -07003354 return attr->mode;
3355}
3356
3357/*
3358 * nct6775_other_is_visible uses the index into the following array
3359 * to determine if attributes should be created or not.
3360 * Any change in order or content must be matched.
3361 */
3362static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003363 &dev_attr_cpu0_vid.attr, /* 0 */
3364 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3365 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3366 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3367 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3368 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003369
3370 NULL
3371};
3372
3373static const struct attribute_group nct6775_group_other = {
3374 .attrs = nct6775_attributes_other,
3375 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003376};
3377
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003378static inline void nct6775_init_device(struct nct6775_data *data)
3379{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003380 int i;
3381 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003382
3383 /* Start monitoring if needed */
3384 if (data->REG_CONFIG) {
3385 tmp = nct6775_read_value(data, data->REG_CONFIG);
3386 if (!(tmp & 0x01))
3387 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3388 }
3389
Guenter Roeckaa136e52012-12-04 03:26:05 -08003390 /* Enable temperature sensors if needed */
3391 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003392 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003393 continue;
3394 if (!data->reg_temp_config[i])
3395 continue;
3396 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3397 if (tmp & 0x01)
3398 nct6775_write_value(data, data->reg_temp_config[i],
3399 tmp & 0xfe);
3400 }
3401
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003402 /* Enable VBAT monitoring if needed */
3403 tmp = nct6775_read_value(data, data->REG_VBAT);
3404 if (!(tmp & 0x01))
3405 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003406
3407 diode = nct6775_read_value(data, data->REG_DIODE);
3408
3409 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003410 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003411 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003412 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3413 data->temp_type[i]
3414 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003415 else /* thermistor */
3416 data->temp_type[i] = 4;
3417 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003418}
3419
Guenter Roeckf73cf632013-03-18 09:22:50 -07003420static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003421nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003422{
Guenter Roeck1b206242018-02-21 13:09:38 -08003423 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003424 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003425 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003426 bool pwm6pin = false, pwm7pin = false;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003427 int sioreg = data->sioreg;
3428 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003429
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003430 /* Store SIO_REG_ENABLE for use during resume */
3431 superio_select(sioreg, NCT6775_LD_HWM);
3432 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3433
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003434 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3435 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003436 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003437
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003438 fan3pin = regval & BIT(6);
3439 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003440
3441 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003442 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003443 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003444 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003445 const char *board_vendor, *board_name;
3446
3447 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3448 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3449
3450 if (board_name && board_vendor &&
3451 !strcmp(board_vendor, "ASRock")) {
3452 /*
3453 * Auxiliary fan monitoring is not enabled on ASRock
3454 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3455 * Observed with BIOS version 2.00.
3456 */
3457 if (!strcmp(board_name, "Z77 Pro4-M")) {
3458 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3459 data->sio_reg_enable |= 0xe0;
3460 superio_outb(sioreg, SIO_REG_ENABLE,
3461 data->sio_reg_enable);
3462 }
3463 }
3464 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003465
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003466 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003467 fan3pin = gpok;
3468 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003469 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003470
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003471 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003472 fan4pin = gpok;
3473 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003474 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003475
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003476 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003477 fan5pin = gpok;
3478 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003479 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003480
3481 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003482 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003483 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003484 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003485 fan3pin = !(regval & 0x80);
3486 pwm3pin = regval & 0x08;
Guenter Roeck81820052018-02-21 13:09:39 -08003487 } else {
3488 /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
3489 int regval_1b, regval_2a, regval_2f;
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003490 bool dsw_en;
Guenter Roecke5c85222017-05-17 18:09:41 -07003491
Guenter Roeckdf612d52013-07-08 13:15:04 -07003492 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003493
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003494 fan3pin = !(regval & BIT(5));
3495 fan4pin = !(regval & BIT(6));
3496 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003497
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003498 pwm3pin = !(regval & BIT(0));
3499 pwm4pin = !(regval & BIT(1));
3500 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003501
Guenter Roecke5c85222017-05-17 18:09:41 -07003502 regval = superio_inb(sioreg, 0x2d);
3503 switch (data->kind) {
3504 case nct6791:
3505 case nct6792:
3506 fan6pin = regval & BIT(1);
3507 pwm6pin = regval & BIT(0);
3508 break;
3509 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003510 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003511 case nct6796:
Guenter Roecke5c85222017-05-17 18:09:41 -07003512 regval_1b = superio_inb(sioreg, 0x1b);
3513 regval_2a = superio_inb(sioreg, 0x2a);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003514 regval_2f = superio_inb(sioreg, 0x2f);
3515 dsw_en = regval_2f & BIT(3);
David Bartley578ab5f2013-06-24 22:28:28 -07003516
Guenter Roecke5c85222017-05-17 18:09:41 -07003517 if (!pwm5pin)
3518 pwm5pin = regval & BIT(7);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003519
Guenter Roecke5c85222017-05-17 18:09:41 -07003520 if (!fan5pin)
3521 fan5pin = regval_1b & BIT(5);
3522
Guenter Roeck81820052018-02-21 13:09:39 -08003523 superio_select(sioreg, NCT6775_LD_12);
3524 if (data->kind != nct6796) {
3525 int regval_eb = superio_inb(sioreg, 0xeb);
3526
3527 if (!dsw_en) {
3528 fan6pin = regval & BIT(1);
3529 pwm6pin = regval & BIT(0);
3530 }
3531
3532 if (!fan5pin)
3533 fan5pin = regval_eb & BIT(5);
3534 if (!pwm5pin)
3535 pwm5pin = (regval_eb & BIT(4)) &&
3536 !(regval_2a & BIT(0));
3537 if (!fan6pin)
3538 fan6pin = regval_eb & BIT(3);
3539 if (!pwm6pin)
3540 pwm6pin = regval_eb & BIT(2);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003541 }
3542
Guenter Roeck81820052018-02-21 13:09:39 -08003543 if (data->kind == nct6795 || data->kind == nct6796) {
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003544 int regval_ed = superio_inb(sioreg, 0xed);
3545
3546 if (!fan6pin)
3547 fan6pin = (regval_2a & BIT(4)) &&
3548 (!dsw_en ||
3549 (dsw_en && (regval_ed & BIT(4))));
3550 if (!pwm6pin)
3551 pwm6pin = (regval_2a & BIT(3)) &&
3552 (regval_ed & BIT(2));
3553 }
Guenter Roeck81820052018-02-21 13:09:39 -08003554
3555 if (data->kind == nct6796) {
3556 int regval_1d = superio_inb(sioreg, 0x1d);
3557 int regval_2b = superio_inb(sioreg, 0x2b);
3558
3559 fan7pin = !(regval_2b & BIT(2));
3560 pwm7pin = !(regval_1d & (BIT(2) | BIT(3)));
3561 }
3562
Guenter Roecke5c85222017-05-17 18:09:41 -07003563 break;
3564 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003565 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003566 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003567
3568 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003569 }
3570
David Bartley578ab5f2013-06-24 22:28:28 -07003571 /* fan 1 and 2 (0x03) are always present */
3572 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003573 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003574 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003575 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003576 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003577 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003578}
3579
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003580static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3581 int *available, int *mask)
3582{
3583 int i;
3584 u8 src;
3585
3586 for (i = 0; i < data->pwm_num && *available; i++) {
3587 int index;
3588
3589 if (!regp[i])
3590 continue;
3591 src = nct6775_read_value(data, regp[i]);
3592 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003593 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003594 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003595 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003596 continue;
3597
3598 index = __ffs(*available);
3599 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003600 *available &= ~BIT(index);
3601 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003602 }
3603}
3604
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003605static int nct6775_probe(struct platform_device *pdev)
3606{
3607 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003608 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003609 struct nct6775_data *data;
3610 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003611 int i, s, err = 0;
3612 int src, mask, available;
3613 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003614 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003615 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003616 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003617 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003618 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003619 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003620 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003621
3622 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3623 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3624 DRVNAME))
3625 return -EBUSY;
3626
3627 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3628 GFP_KERNEL);
3629 if (!data)
3630 return -ENOMEM;
3631
3632 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003633 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003634 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003635 mutex_init(&data->update_lock);
3636 data->name = nct6775_device_names[data->kind];
3637 data->bank = 0xff; /* Force initial bank selection */
3638 platform_set_drvdata(pdev, data);
3639
3640 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003641 case nct6106:
3642 data->in_num = 9;
3643 data->pwm_num = 3;
3644 data->auto_pwm_num = 4;
3645 data->temp_fixed_num = 3;
3646 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003647 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003648
3649 data->fan_from_reg = fan_from_reg13;
3650 data->fan_from_reg_min = fan_from_reg13;
3651
3652 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003653 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003654 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003655
3656 data->REG_VBAT = NCT6106_REG_VBAT;
3657 data->REG_DIODE = NCT6106_REG_DIODE;
3658 data->DIODE_MASK = NCT6106_DIODE_MASK;
3659 data->REG_VIN = NCT6106_REG_IN;
3660 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3661 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3662 data->REG_TARGET = NCT6106_REG_TARGET;
3663 data->REG_FAN = NCT6106_REG_FAN;
3664 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3665 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3666 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3667 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3668 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3669 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3670 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3671 data->REG_PWM[0] = NCT6106_REG_PWM;
3672 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3673 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3674 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3675 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3676 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3677 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3678 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3679 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3680 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3681 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3682 data->REG_CRITICAL_TEMP_TOLERANCE
3683 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3684 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3685 data->CRITICAL_PWM_ENABLE_MASK
3686 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3687 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3688 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3689 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3690 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3691 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3692 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3693 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3694 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3695 data->REG_ALARM = NCT6106_REG_ALARM;
3696 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003697 data->REG_BEEP = NCT6106_REG_BEEP;
3698 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003699
3700 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003701 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003702 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003703 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003704 reg_temp_over = NCT6106_REG_TEMP_OVER;
3705 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3706 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3707 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3708 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003709 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3710 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003711
3712 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003713 case nct6775:
3714 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003715 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003716 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003717 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003718 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003719 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003720 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003721
3722 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003723 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003724
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003725 data->fan_from_reg = fan_from_reg16;
3726 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003727 data->target_temp_mask = 0x7f;
3728 data->tolerance_mask = 0x0f;
3729 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003730
Guenter Roeckaa136e52012-12-04 03:26:05 -08003731 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003732 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003733 data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003734
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003735 data->REG_CONFIG = NCT6775_REG_CONFIG;
3736 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003737 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003738 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003739 data->REG_VIN = NCT6775_REG_IN;
3740 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3741 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003742 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003743 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003744 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003745 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003746 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003747 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003748 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3749 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3750 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003751 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003752 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3753 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3754 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3755 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003756 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003757 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3758 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3759 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003760 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3761 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3762 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3763 data->REG_CRITICAL_TEMP_TOLERANCE
3764 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003765 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3766 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003767 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003768 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3769 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3770 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3771 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003772 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003773 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003774
3775 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003776 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003777 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003778 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003779 reg_temp_over = NCT6775_REG_TEMP_OVER;
3780 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3781 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3782 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3783 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3784
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003785 break;
3786 case nct6776:
3787 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003788 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003789 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003790 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003791 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003792 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003793 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003794
3795 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003796 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003797
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003798 data->fan_from_reg = fan_from_reg13;
3799 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003800 data->target_temp_mask = 0xff;
3801 data->tolerance_mask = 0x07;
3802 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003803
Guenter Roeckaa136e52012-12-04 03:26:05 -08003804 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003805 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003806 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003807
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003808 data->REG_CONFIG = NCT6775_REG_CONFIG;
3809 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003810 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003811 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003812 data->REG_VIN = NCT6775_REG_IN;
3813 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3814 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003815 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003816 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003817 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003818 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003819 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003820 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003821 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003822 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3823 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003824 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003825 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003826 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3827 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003828 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3829 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003830 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3831 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3832 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003833 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3834 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3835 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3836 data->REG_CRITICAL_TEMP_TOLERANCE
3837 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003838 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3839 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003840 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003841 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3842 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3843 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3844 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003845 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003846 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003847
3848 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003849 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003850 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003851 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003852 reg_temp_over = NCT6775_REG_TEMP_OVER;
3853 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3854 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3855 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3856 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3857
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003858 break;
3859 case nct6779:
3860 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003861 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003862 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003863 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003864 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003865 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003866 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003867
3868 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003869 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003870
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003871 data->fan_from_reg = fan_from_reg13;
3872 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003873 data->target_temp_mask = 0xff;
3874 data->tolerance_mask = 0x07;
3875 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003876
Guenter Roeckaa136e52012-12-04 03:26:05 -08003877 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003878 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003879 data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003880
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003881 data->REG_CONFIG = NCT6775_REG_CONFIG;
3882 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003883 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003884 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003885 data->REG_VIN = NCT6779_REG_IN;
3886 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3887 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003888 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003889 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003890 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003891 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003892 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003893 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003894 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003895 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3896 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003897 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003898 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003899 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3900 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003901 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3902 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003903 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3904 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3905 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003906 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3907 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3908 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3909 data->REG_CRITICAL_TEMP_TOLERANCE
3910 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003911 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3912 data->CRITICAL_PWM_ENABLE_MASK
3913 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3914 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003915 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3916 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003917 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003918 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3919 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3920 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3921 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003922 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003923 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003924
3925 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003926 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003927 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003928 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003929 reg_temp_over = NCT6779_REG_TEMP_OVER;
3930 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3931 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3932 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3933 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3934
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003935 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003936 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003937 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003938 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003939 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003940 case nct6796:
David Bartley578ab5f2013-06-24 22:28:28 -07003941 data->in_num = 15;
Guenter Roeck81820052018-02-21 13:09:39 -08003942 data->pwm_num = (data->kind == nct6796) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07003943 data->auto_pwm_num = 4;
3944 data->has_fan_div = false;
3945 data->temp_fixed_num = 6;
3946 data->num_temp_alarms = 2;
3947 data->num_temp_beeps = 2;
3948
3949 data->ALARM_BITS = NCT6791_ALARM_BITS;
3950 data->BEEP_BITS = NCT6779_BEEP_BITS;
3951
3952 data->fan_from_reg = fan_from_reg13;
3953 data->fan_from_reg_min = fan_from_reg13;
3954 data->target_temp_mask = 0xff;
3955 data->tolerance_mask = 0x07;
3956 data->speed_tolerance_limit = 63;
3957
Guenter Roeck50224f42015-10-30 07:52:39 -07003958 switch (data->kind) {
3959 default:
3960 case nct6791:
3961 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003962 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003963 data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003964 break;
3965 case nct6792:
3966 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003967 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003968 data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003969 break;
3970 case nct6793:
3971 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003972 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003973 data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003974 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003975 case nct6795:
3976 data->temp_label = nct6795_temp_label;
3977 data->temp_mask = NCT6795_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003978 data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
Guenter Roeck419220d2017-05-17 18:19:18 -07003979 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003980 case nct6796:
3981 data->temp_label = nct6796_temp_label;
3982 data->temp_mask = NCT6796_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003983 data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
Guenter Roeck81820052018-02-21 13:09:39 -08003984 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07003985 }
David Bartley578ab5f2013-06-24 22:28:28 -07003986
3987 data->REG_CONFIG = NCT6775_REG_CONFIG;
3988 data->REG_VBAT = NCT6775_REG_VBAT;
3989 data->REG_DIODE = NCT6775_REG_DIODE;
3990 data->DIODE_MASK = NCT6775_DIODE_MASK;
3991 data->REG_VIN = NCT6779_REG_IN;
3992 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3993 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3994 data->REG_TARGET = NCT6775_REG_TARGET;
3995 data->REG_FAN = NCT6779_REG_FAN;
3996 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3997 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3998 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3999 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
4000 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004001 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4002 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07004003 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
4004 data->REG_PWM[0] = NCT6775_REG_PWM;
4005 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4006 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004007 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
4008 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004009 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4010 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4011 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
4012 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4013 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4014 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4015 data->REG_CRITICAL_TEMP_TOLERANCE
4016 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
4017 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4018 data->CRITICAL_PWM_ENABLE_MASK
4019 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4020 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
4021 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4022 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4023 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004024 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4025 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4026 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4027 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004028 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004029 if (data->kind == nct6791)
4030 data->REG_BEEP = NCT6776_REG_BEEP;
4031 else
4032 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004033
4034 reg_temp = NCT6779_REG_TEMP;
4035 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004036 if (data->kind == nct6791) {
4037 reg_temp_mon = NCT6779_REG_TEMP_MON;
4038 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4039 } else {
4040 reg_temp_mon = NCT6792_REG_TEMP_MON;
4041 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4042 }
David Bartley578ab5f2013-06-24 22:28:28 -07004043 reg_temp_over = NCT6779_REG_TEMP_OVER;
4044 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4045 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4046 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4047 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4048
4049 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004050 default:
4051 return -ENODEV;
4052 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004053 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004054 data->have_temp = 0;
4055
4056 /*
4057 * On some boards, not all available temperature sources are monitored,
4058 * even though some of the monitoring registers are unused.
4059 * Get list of unused monitoring registers, then detect if any fan
4060 * controls are configured to use unmonitored temperature sources.
4061 * If so, assign the unmonitored temperature sources to available
4062 * monitoring registers.
4063 */
4064 mask = 0;
4065 available = 0;
4066 for (i = 0; i < num_reg_temp; i++) {
4067 if (reg_temp[i] == 0)
4068 continue;
4069
4070 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004071 if (!src || (mask & BIT(src)))
4072 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004073
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004074 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004075 }
4076
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004077 /*
4078 * Now find unmonitored temperature registers and enable monitoring
4079 * if additional monitoring registers are available.
4080 */
4081 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4082 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4083
Guenter Roeckaa136e52012-12-04 03:26:05 -08004084 mask = 0;
4085 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4086 for (i = 0; i < num_reg_temp; i++) {
4087 if (reg_temp[i] == 0)
4088 continue;
4089
4090 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004091 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004092 continue;
4093
Guenter Roeckcc66b302017-05-17 18:05:06 -07004094 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004095 dev_info(dev,
4096 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4097 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4098 continue;
4099 }
4100
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004101 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004102
4103 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4104 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004105 data->have_temp |= BIT(src - 1);
4106 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004107 data->reg_temp[0][src - 1] = reg_temp[i];
4108 data->reg_temp[1][src - 1] = reg_temp_over[i];
4109 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004110 if (reg_temp_crit_h && reg_temp_crit_h[i])
4111 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4112 else if (reg_temp_crit[src - 1])
4113 data->reg_temp[3][src - 1]
4114 = reg_temp_crit[src - 1];
4115 if (reg_temp_crit_l && reg_temp_crit_l[i])
4116 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004117 data->reg_temp_config[src - 1] = reg_temp_config[i];
4118 data->temp_src[src - 1] = src;
4119 continue;
4120 }
4121
4122 if (s >= NUM_TEMP)
4123 continue;
4124
4125 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004126 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004127 data->reg_temp[0][s] = reg_temp[i];
4128 data->reg_temp[1][s] = reg_temp_over[i];
4129 data->reg_temp[2][s] = reg_temp_hyst[i];
4130 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004131 if (reg_temp_crit_h && reg_temp_crit_h[i])
4132 data->reg_temp[3][s] = reg_temp_crit_h[i];
4133 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004134 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004135 if (reg_temp_crit_l && reg_temp_crit_l[i])
4136 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004137
4138 data->temp_src[s] = src;
4139 s++;
4140 }
4141
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004142 /*
4143 * Repeat with temperatures used for fan control.
4144 * This set of registers does not support limits.
4145 */
4146 for (i = 0; i < num_reg_temp_mon; i++) {
4147 if (reg_temp_mon[i] == 0)
4148 continue;
4149
4150 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004151 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004152 continue;
4153
Guenter Roeckcc66b302017-05-17 18:05:06 -07004154 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004155 dev_info(dev,
4156 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4157 src, i, data->REG_TEMP_SEL[i],
4158 reg_temp_mon[i]);
4159 continue;
4160 }
4161
Guenter Roeck7ce41902016-09-11 12:42:52 -07004162 /*
4163 * For virtual temperature sources, the 'virtual' temperature
4164 * for each fan reflects a different temperature, and there
4165 * are no duplicates.
4166 */
Guenter Roeck37196ba2018-09-13 19:43:58 -07004167 if (!(data->virt_temp_mask & BIT(src))) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004168 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004169 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004170 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004171 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004172
4173 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4174 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004175 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004176 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004177 data->have_temp |= BIT(src - 1);
4178 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004179 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4180 data->temp_src[src - 1] = src;
4181 continue;
4182 }
4183
4184 if (s >= NUM_TEMP)
4185 continue;
4186
4187 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004188 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004189 data->reg_temp[0][s] = reg_temp_mon[i];
4190 data->temp_src[s] = src;
4191 s++;
4192 }
4193
Guenter Roeckaa136e52012-12-04 03:26:05 -08004194#ifdef USE_ALTERNATE
4195 /*
4196 * Go through the list of alternate temp registers and enable
4197 * if possible.
4198 * The temperature is already monitored if the respective bit in <mask>
4199 * is set.
4200 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004201 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004202 if (!(data->temp_mask & BIT(i + 1)))
4203 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004204 if (!reg_temp_alternate[i])
4205 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004206 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004207 continue;
4208 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004209 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004210 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004211 data->have_temp |= BIT(i);
4212 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004213 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004214 if (i < num_reg_temp) {
4215 data->reg_temp[1][i] = reg_temp_over[i];
4216 data->reg_temp[2][i] = reg_temp_hyst[i];
4217 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004218 data->temp_src[i] = i + 1;
4219 continue;
4220 }
4221
4222 if (s >= NUM_TEMP) /* Abort if no more space */
4223 break;
4224
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004225 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004226 data->reg_temp[0][s] = reg_temp_alternate[i];
4227 data->temp_src[s] = i + 1;
4228 s++;
4229 }
4230#endif /* USE_ALTERNATE */
4231
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004232 /* Initialize the chip */
4233 nct6775_init_device(data);
4234
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004235 err = superio_enter(sio_data->sioreg);
4236 if (err)
4237 return err;
4238
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004239 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4240 switch (data->kind) {
4241 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004242 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004243 break;
4244 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004245 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004246 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004247 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004248 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004249 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004250 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004251 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004252 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004253 case nct6796:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004254 break;
4255 }
4256
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004257 /*
4258 * Read VID value
4259 * We can get the VID input values directly at logical device D 0xe3.
4260 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004261 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004262 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4263 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4264 data->vrm = vid_which_vrm();
4265 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004266
4267 if (fan_debounce) {
4268 u8 tmp;
4269
4270 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4271 tmp = superio_inb(sio_data->sioreg,
4272 NCT6775_REG_CR_FAN_DEBOUNCE);
4273 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004274 case nct6106:
4275 tmp |= 0xe0;
4276 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004277 case nct6775:
4278 tmp |= 0x1e;
4279 break;
4280 case nct6776:
4281 case nct6779:
4282 tmp |= 0x3e;
4283 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004284 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004285 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004286 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004287 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004288 case nct6796:
David Bartley578ab5f2013-06-24 22:28:28 -07004289 tmp |= 0x7e;
4290 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004291 }
4292 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4293 tmp);
4294 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4295 data->name);
4296 }
4297
Guenter Roeckdf612d52013-07-08 13:15:04 -07004298 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004299
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004300 superio_exit(sio_data->sioreg);
4301
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004302 /* Read fan clock dividers immediately */
4303 nct6775_init_fan_common(dev, data);
4304
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004305 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004306 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4307 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004308 if (IS_ERR(group))
4309 return PTR_ERR(group);
4310
Axel Lin55bdee62014-07-24 08:59:34 +08004311 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004312
Guenter Roeckf73cf632013-03-18 09:22:50 -07004313 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4314 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004315 if (IS_ERR(group))
4316 return PTR_ERR(group);
4317
Axel Lin55bdee62014-07-24 08:59:34 +08004318 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004319
Guenter Roeckf73cf632013-03-18 09:22:50 -07004320 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4321 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004322 if (IS_ERR(group))
4323 return PTR_ERR(group);
4324
Axel Lin55bdee62014-07-24 08:59:34 +08004325 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004326
Guenter Roeckf73cf632013-03-18 09:22:50 -07004327 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4328 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004329 if (IS_ERR(group))
4330 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004331
Axel Lin55bdee62014-07-24 08:59:34 +08004332 data->groups[num_attr_groups++] = group;
4333 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004334
Guenter Roecka150d952013-07-11 22:55:22 -07004335 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4336 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004337 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004338}
4339
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004340static void nct6791_enable_io_mapping(int sioaddr)
4341{
4342 int val;
4343
4344 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4345 if (val & 0x10) {
4346 pr_info("Enabling hardware monitor logical device mappings.\n");
4347 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4348 val & ~0x10);
4349 }
4350}
4351
Guenter Roeck48e93182015-02-07 08:48:49 -08004352static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004353{
4354 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004355
4356 mutex_lock(&data->update_lock);
4357 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004358 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004359 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4360 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4361 }
4362 mutex_unlock(&data->update_lock);
4363
4364 return 0;
4365}
4366
Guenter Roeck48e93182015-02-07 08:48:49 -08004367static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004368{
4369 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004370 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004371 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004372 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004373
4374 mutex_lock(&data->update_lock);
4375 data->bank = 0xff; /* Force initial bank selection */
4376
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004377 err = superio_enter(sioreg);
4378 if (err)
4379 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004380
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004381 superio_select(sioreg, NCT6775_LD_HWM);
4382 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4383 if (reg != data->sio_reg_enable)
4384 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4385
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004386 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004387 data->kind == nct6793 || data->kind == nct6795 ||
4388 data->kind == nct6796)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004389 nct6791_enable_io_mapping(sioreg);
4390
4391 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004392
Guenter Roeck84d19d92012-12-04 08:01:39 -08004393 /* Restore limits */
4394 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004395 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004396 continue;
4397
4398 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4399 data->in[i][1]);
4400 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4401 data->in[i][2]);
4402 }
4403
Guenter Roeckc409fd42013-04-09 05:04:00 -07004404 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004405 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004406 continue;
4407
4408 nct6775_write_value(data, data->REG_FAN_MIN[i],
4409 data->fan_min[i]);
4410 }
4411
4412 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004413 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004414 continue;
4415
Guenter Roeckc409fd42013-04-09 05:04:00 -07004416 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004417 if (data->reg_temp[j][i])
4418 nct6775_write_temp(data, data->reg_temp[j][i],
4419 data->temp[j][i]);
4420 }
4421
4422 /* Restore other settings */
4423 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004424 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004425 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4426 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4427 }
4428
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004429abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004430 /* Force re-reading all values */
4431 data->valid = false;
4432 mutex_unlock(&data->update_lock);
4433
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004434 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004435}
4436
Guenter Roeck48e93182015-02-07 08:48:49 -08004437static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004438
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004439static struct platform_driver nct6775_driver = {
4440 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004441 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004442 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004443 },
4444 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004445};
4446
4447/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004448static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004449{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004450 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004451 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004452 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004453
4454 err = superio_enter(sioaddr);
4455 if (err)
4456 return err;
4457
Guenter Roeckfc72af32016-08-03 22:07:18 -07004458 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4459 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4460 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004461 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004462
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004463 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004464 case SIO_NCT6106_ID:
4465 sio_data->kind = nct6106;
4466 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004467 case SIO_NCT6775_ID:
4468 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004469 break;
4470 case SIO_NCT6776_ID:
4471 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004472 break;
4473 case SIO_NCT6779_ID:
4474 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004475 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004476 case SIO_NCT6791_ID:
4477 sio_data->kind = nct6791;
4478 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004479 case SIO_NCT6792_ID:
4480 sio_data->kind = nct6792;
4481 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004482 case SIO_NCT6793_ID:
4483 sio_data->kind = nct6793;
4484 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004485 case SIO_NCT6795_ID:
4486 sio_data->kind = nct6795;
4487 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004488 case SIO_NCT6796_ID:
4489 sio_data->kind = nct6796;
4490 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004491 default:
4492 if (val != 0xffff)
4493 pr_debug("unsupported chip ID: 0x%04x\n", val);
4494 superio_exit(sioaddr);
4495 return -ENODEV;
4496 }
4497
4498 /* We have a known chip, find the HWM I/O address */
4499 superio_select(sioaddr, NCT6775_LD_HWM);
4500 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4501 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004502 addr = val & IOREGION_ALIGNMENT;
4503 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004504 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4505 superio_exit(sioaddr);
4506 return -ENODEV;
4507 }
4508
4509 /* Activate logical device if needed */
4510 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4511 if (!(val & 0x01)) {
4512 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4513 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4514 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004515
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004516 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004517 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
4518 sio_data->kind == nct6796)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004519 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004520
4521 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004522 pr_info("Found %s or compatible chip at %#x:%#x\n",
4523 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004524 sio_data->sioreg = sioaddr;
4525
Guenter Roeck698a7c22013-04-05 07:35:25 -07004526 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004527}
4528
4529/*
4530 * when Super-I/O functions move to a separate file, the Super-I/O
4531 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004532 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004533 * must keep track of the device
4534 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004535static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004536
4537static int __init sensors_nct6775_init(void)
4538{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004539 int i, err;
4540 bool found = false;
4541 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004542 struct resource res;
4543 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004544 int sioaddr[2] = { 0x2e, 0x4e };
4545
4546 err = platform_driver_register(&nct6775_driver);
4547 if (err)
4548 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004549
4550 /*
4551 * initialize sio_data->kind and sio_data->sioreg.
4552 *
4553 * when Super-I/O functions move to a separate file, the Super-I/O
4554 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4555 * nct6775 hardware monitor, and call probe()
4556 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004557 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4558 address = nct6775_find(sioaddr[i], &sio_data);
4559 if (address <= 0)
4560 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004561
Guenter Roeck698a7c22013-04-05 07:35:25 -07004562 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004563
Guenter Roeck698a7c22013-04-05 07:35:25 -07004564 pdev[i] = platform_device_alloc(DRVNAME, address);
4565 if (!pdev[i]) {
4566 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004567 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004568 }
4569
4570 err = platform_device_add_data(pdev[i], &sio_data,
4571 sizeof(struct nct6775_sio_data));
4572 if (err)
4573 goto exit_device_put;
4574
4575 memset(&res, 0, sizeof(res));
4576 res.name = DRVNAME;
4577 res.start = address + IOREGION_OFFSET;
4578 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4579 res.flags = IORESOURCE_IO;
4580
4581 err = acpi_check_resource_conflict(&res);
4582 if (err) {
4583 platform_device_put(pdev[i]);
4584 pdev[i] = NULL;
4585 continue;
4586 }
4587
4588 err = platform_device_add_resources(pdev[i], &res, 1);
4589 if (err)
4590 goto exit_device_put;
4591
4592 /* platform_device_add calls probe() */
4593 err = platform_device_add(pdev[i]);
4594 if (err)
4595 goto exit_device_put;
4596 }
4597 if (!found) {
4598 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004599 goto exit_unregister;
4600 }
4601
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004602 return 0;
4603
4604exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004605 platform_device_put(pdev[i]);
4606exit_device_unregister:
4607 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004608 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004609 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004610 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004611exit_unregister:
4612 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004613 return err;
4614}
4615
4616static void __exit sensors_nct6775_exit(void)
4617{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004618 int i;
4619
4620 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4621 if (pdev[i])
4622 platform_device_unregister(pdev[i]);
4623 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004624 platform_driver_unregister(&nct6775_driver);
4625}
4626
4627MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004628MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004629MODULE_LICENSE("GPL");
4630
4631module_init(sensors_nct6775_init);
4632module_exit(sensors_nct6775_exit);