blob: 5bd15622a85f942ea7eefbf1b80124640bb368c7 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002/*
3 * nct6775 - Driver for the hardware monitoring functionality of
4 * Nuvoton NCT677x Super-I/O chips
5 *
6 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
7 *
8 * Derived from w83627ehf driver
Jean Delvare7c81c60f2014-01-29 20:40:08 +01009 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070010 * Copyright (C) 2006 Yuan Mu (Winbond),
11 * Rudolf Marek <r.marek@assembler.cz>
12 * David Hubbard <david.c.hubbard@gmail.com>
13 * Daniel J Blueman <daniel.blueman@gmail.com>
14 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
15 *
16 * Shamelessly ripped from the w83627hf driver
17 * Copyright (C) 2003 Mark Studebaker
18 *
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070019 * Supports the following chips:
20 *
21 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070022 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Björn Gerhart29c7cb42019-07-23 18:06:46 +020023 * nct6116d 9 5 5 3+3 0xd280 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070024 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
25 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
26 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070027 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080028 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070029 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck419220d2017-05-17 18:19:18 -070030 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
Guenter Roeck81820052018-02-21 13:09:39 -080031 * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
Guenter Roecke41da282018-09-18 20:48:29 -070032 * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3
Guenter Roeck05996822018-09-19 20:26:16 -070033 * (0xd451)
Guenter Roeck264142b2018-12-26 07:34:31 -080034 * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3
35 * (0xd429)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070036 *
37 * #temp lists the number of monitored temperature sources (first value) plus
38 * the number of directly connectable temperature sensors (second value).
39 */
40
41#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
42
43#include <linux/module.h>
44#include <linux/init.h>
45#include <linux/slab.h>
46#include <linux/jiffies.h>
47#include <linux/platform_device.h>
48#include <linux/hwmon.h>
49#include <linux/hwmon-sysfs.h>
50#include <linux/hwmon-vid.h>
51#include <linux/err.h>
52#include <linux/mutex.h>
53#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070054#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080055#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070056#include <linux/io.h>
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -050057#include <linux/nospec.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070058#include "lm75.h"
59
Guenter Roeckaa136e52012-12-04 03:26:05 -080060#define USE_ALTERNATE
61
Björn Gerhart29c7cb42019-07-23 18:06:46 +020062enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
63 nct6793, nct6795, nct6796, nct6797, nct6798 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070064
65/* used to set data->name = nct6775_device_names[data->sio_kind] */
66static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070067 "nct6106",
Björn Gerhart29c7cb42019-07-23 18:06:46 +020068 "nct6116",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070069 "nct6775",
70 "nct6776",
71 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070072 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080073 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070074 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070075 "nct6795",
Guenter Roeck81820052018-02-21 13:09:39 -080076 "nct6796",
Guenter Roecke41da282018-09-18 20:48:29 -070077 "nct6797",
Guenter Roeck05996822018-09-19 20:26:16 -070078 "nct6798",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070079};
80
81static const char * const nct6775_sio_names[] __initconst = {
82 "NCT6106D",
Björn Gerhart29c7cb42019-07-23 18:06:46 +020083 "NCT6116D",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070084 "NCT6775F",
85 "NCT6776D/F",
86 "NCT6779D",
87 "NCT6791D",
88 "NCT6792D",
89 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -070090 "NCT6795D",
Guenter Roeck81820052018-02-21 13:09:39 -080091 "NCT6796D",
Guenter Roecke41da282018-09-18 20:48:29 -070092 "NCT6797D",
Guenter Roeck05996822018-09-19 20:26:16 -070093 "NCT6798D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070094};
95
96static unsigned short force_id;
97module_param(force_id, ushort, 0);
98MODULE_PARM_DESC(force_id, "Override the detected device ID");
99
Guenter Roeck47ece962012-12-04 07:59:32 -0800100static unsigned short fan_debounce;
101module_param(fan_debounce, ushort, 0);
102MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
103
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700104#define DRVNAME "nct6775"
105
106/*
107 * Super-I/O constants and functions
108 */
109
Guenter Roecka6bd5872012-12-04 03:13:34 -0800110#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700111#define NCT6775_LD_HWM 0x0b
112#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700113#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114
115#define SIO_REG_LDSEL 0x07 /* Logical device select */
116#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
117#define SIO_REG_ENABLE 0x30 /* Logical device enable */
118#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
119
Guenter Roeck6c009502012-07-01 08:23:15 -0700120#define SIO_NCT6106_ID 0xc450
Björn Gerhart29c7cb42019-07-23 18:06:46 +0200121#define SIO_NCT6116_ID 0xd280
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700122#define SIO_NCT6775_ID 0xb470
123#define SIO_NCT6776_ID 0xc330
124#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700125#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800126#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700127#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700128#define SIO_NCT6795_ID 0xd350
Guenter Roeck81820052018-02-21 13:09:39 -0800129#define SIO_NCT6796_ID 0xd420
Guenter Roecke41da282018-09-18 20:48:29 -0700130#define SIO_NCT6797_ID 0xd450
Guenter Roeck264142b2018-12-26 07:34:31 -0800131#define SIO_NCT6798_ID 0xd428
Guenter Roeck05996822018-09-19 20:26:16 -0700132#define SIO_ID_MASK 0xFFF8
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700133
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800134enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
135
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700136static inline void
137superio_outb(int ioreg, int reg, int val)
138{
139 outb(reg, ioreg);
140 outb(val, ioreg + 1);
141}
142
143static inline int
144superio_inb(int ioreg, int reg)
145{
146 outb(reg, ioreg);
147 return inb(ioreg + 1);
148}
149
150static inline void
151superio_select(int ioreg, int ld)
152{
153 outb(SIO_REG_LDSEL, ioreg);
154 outb(ld, ioreg + 1);
155}
156
157static inline int
158superio_enter(int ioreg)
159{
160 /*
161 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
162 */
163 if (!request_muxed_region(ioreg, 2, DRVNAME))
164 return -EBUSY;
165
166 outb(0x87, ioreg);
167 outb(0x87, ioreg);
168
169 return 0;
170}
171
172static inline void
173superio_exit(int ioreg)
174{
175 outb(0xaa, ioreg);
176 outb(0x02, ioreg);
177 outb(0x02, ioreg + 1);
178 release_region(ioreg, 2);
179}
180
181/*
182 * ISA constants
183 */
184
185#define IOREGION_ALIGNMENT (~7)
186#define IOREGION_OFFSET 5
187#define IOREGION_LENGTH 2
188#define ADDR_REG_OFFSET 0
189#define DATA_REG_OFFSET 1
190
191#define NCT6775_REG_BANK 0x4E
192#define NCT6775_REG_CONFIG 0x40
193
194/*
195 * Not currently used:
196 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
197 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
198 * REG_MAN_ID is at port 0x4f
199 * REG_CHIP_ID is at port 0x58
200 */
201
Guenter Roeckaa136e52012-12-04 03:26:05 -0800202#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
203#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
204
Guenter Roeck6c009502012-07-01 08:23:15 -0700205#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700206#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700207
Guenter Roeck81820052018-02-21 13:09:39 -0800208#define NUM_FAN 7
David Bartley578ab5f2013-06-24 22:28:28 -0700209
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700210/* Common and NCT6775 specific data */
211
212/* Voltage min/max registers for nr=7..14 are in bank 5 */
213
214static const u16 NCT6775_REG_IN_MAX[] = {
215 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
216 0x55c, 0x55e, 0x560, 0x562 };
217static const u16 NCT6775_REG_IN_MIN[] = {
218 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
219 0x55d, 0x55f, 0x561, 0x563 };
220static const u16 NCT6775_REG_IN[] = {
221 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
222};
223
224#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800225#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700226#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700227
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800228#define NCT6775_REG_FANDIV1 0x506
229#define NCT6775_REG_FANDIV2 0x507
230
Guenter Roeck47ece962012-12-04 07:59:32 -0800231#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
232
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700233static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
234
Guenter Roeck30846992013-06-24 22:21:59 -0700235/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700236
237static const s8 NCT6775_ALARM_BITS[] = {
238 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
239 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
240 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700241 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700242 -1, -1, -1, /* unused */
243 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
244 12, -1 }; /* intrusion0, intrusion1 */
245
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800246#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800247#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800248#define INTRUSION_ALARM_BASE 30
249
Guenter Roeck30846992013-06-24 22:21:59 -0700250static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
251
252/*
253 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
254 * 30..31 intrusion
255 */
256static const s8 NCT6775_BEEP_BITS[] = {
257 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
258 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
259 21, /* global beep enable */
260 6, 7, 11, 28, -1, /* fan1..fan5 */
261 -1, -1, -1, /* unused */
262 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
263 12, -1 }; /* intrusion0, intrusion1 */
264
265#define BEEP_ENABLE_BASE 15
266
Guenter Roecka6bd5872012-12-04 03:13:34 -0800267static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
268static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
269
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800270/* DC or PWM output fan configuration */
271static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
272static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
273
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800274/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800275
David Bartley578ab5f2013-06-24 22:28:28 -0700276static const u16 NCT6775_REG_TARGET[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800277 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
David Bartley578ab5f2013-06-24 22:28:28 -0700278static const u16 NCT6775_REG_FAN_MODE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800279 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800280static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800281 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800282static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800283 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800284static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800285 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
David Bartley578ab5f2013-06-24 22:28:28 -0700286static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800287 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800288static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
289static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
290
291static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800292 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
David Bartley578ab5f2013-06-24 22:28:28 -0700293static const u16 NCT6775_REG_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800294 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
David Bartley578ab5f2013-06-24 22:28:28 -0700295static const u16 NCT6775_REG_PWM_READ[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800296 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800297
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800298static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
299static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeckc7932792018-09-06 09:47:51 -0700300static const u16 NCT6775_REG_FAN_PULSES[NUM_FAN] = {
301 0x641, 0x642, 0x643, 0x644 };
302static const u16 NCT6775_FAN_PULSE_SHIFT[NUM_FAN] = { };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800303
Guenter Roeckaa136e52012-12-04 03:26:05 -0800304static const u16 NCT6775_REG_TEMP[] = {
305 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
306
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800307static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
308
Guenter Roeckaa136e52012-12-04 03:26:05 -0800309static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
310 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
311static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
312 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
313static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
314 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
315
316static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
317 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
318
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800319static const u16 NCT6775_REG_TEMP_SEL[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800320 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800321
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800322static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700323 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800324static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700325 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800326static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700327 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800328static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700329 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800330static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700331 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800332
Guenter Roeckaa136e52012-12-04 03:26:05 -0800333static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
334
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800335static const u16 NCT6775_REG_AUTO_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800336 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800337static const u16 NCT6775_REG_AUTO_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800338 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800339
340#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
341#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
342
343static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
344
345static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800346 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800347static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800348 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800349
Guenter Roeckaa136e52012-12-04 03:26:05 -0800350static const char *const nct6775_temp_label[] = {
351 "",
352 "SYSTIN",
353 "CPUTIN",
354 "AUXTIN",
355 "AMD SB-TSI",
356 "PECI Agent 0",
357 "PECI Agent 1",
358 "PECI Agent 2",
359 "PECI Agent 3",
360 "PECI Agent 4",
361 "PECI Agent 5",
362 "PECI Agent 6",
363 "PECI Agent 7",
364 "PCH_CHIP_CPU_MAX_TEMP",
365 "PCH_CHIP_TEMP",
366 "PCH_CPU_TEMP",
367 "PCH_MCH_TEMP",
368 "PCH_DIM0_TEMP",
369 "PCH_DIM1_TEMP",
370 "PCH_DIM2_TEMP",
371 "PCH_DIM3_TEMP"
372};
373
Guenter Roeckcc66b302017-05-17 18:05:06 -0700374#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700375#define NCT6775_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800376
Guenter Roeckcc66b302017-05-17 18:05:06 -0700377static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
378 [13] = 0x661,
379 [14] = 0x662,
380 [15] = 0x664,
381};
382
383static const u16 NCT6775_REG_TEMP_CRIT[32] = {
384 [4] = 0xa00,
385 [5] = 0xa01,
386 [6] = 0xa02,
387 [7] = 0xa03,
388 [8] = 0xa04,
389 [9] = 0xa05,
390 [10] = 0xa06,
391 [11] = 0xa07
392};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800393
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700394/* NCT6776 specific data */
395
Guenter Roeck728d2942015-08-31 16:13:47 -0700396/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
397#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
398#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
399
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700400static const s8 NCT6776_ALARM_BITS[] = {
401 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
402 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
403 -1, /* unused */
404 6, 7, 11, 10, 23, /* fan1..fan5 */
405 -1, -1, -1, /* unused */
406 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
407 12, 9 }; /* intrusion0, intrusion1 */
408
Guenter Roeck30846992013-06-24 22:21:59 -0700409static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
410
411static const s8 NCT6776_BEEP_BITS[] = {
412 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
413 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
414 24, /* global beep enable */
415 25, 26, 27, 28, 29, /* fan1..fan5 */
416 -1, -1, -1, /* unused */
417 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
418 30, 31 }; /* intrusion0, intrusion1 */
419
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800420static const u16 NCT6776_REG_TOLERANCE_H[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800421 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800422
David Bartley578ab5f2013-06-24 22:28:28 -0700423static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
424static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800425
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800426static const u16 NCT6776_REG_FAN_MIN[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800427 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
Guenter Roeckc7932792018-09-06 09:47:51 -0700428static const u16 NCT6776_REG_FAN_PULSES[NUM_FAN] = {
429 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800430
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800431static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700432 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800433
Guenter Roeckaa136e52012-12-04 03:26:05 -0800434static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
435 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
436
437static const char *const nct6776_temp_label[] = {
438 "",
439 "SYSTIN",
440 "CPUTIN",
441 "AUXTIN",
442 "SMBUSMASTER 0",
443 "SMBUSMASTER 1",
444 "SMBUSMASTER 2",
445 "SMBUSMASTER 3",
446 "SMBUSMASTER 4",
447 "SMBUSMASTER 5",
448 "SMBUSMASTER 6",
449 "SMBUSMASTER 7",
450 "PECI Agent 0",
451 "PECI Agent 1",
452 "PCH_CHIP_CPU_MAX_TEMP",
453 "PCH_CHIP_TEMP",
454 "PCH_CPU_TEMP",
455 "PCH_MCH_TEMP",
456 "PCH_DIM0_TEMP",
457 "PCH_DIM1_TEMP",
458 "PCH_DIM2_TEMP",
459 "PCH_DIM3_TEMP",
460 "BYTE_TEMP"
461};
462
Guenter Roeckcc66b302017-05-17 18:05:06 -0700463#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700464#define NCT6776_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800465
Guenter Roeckcc66b302017-05-17 18:05:06 -0700466static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
467 [14] = 0x401,
468 [15] = 0x402,
469 [16] = 0x404,
470};
471
472static const u16 NCT6776_REG_TEMP_CRIT[32] = {
473 [11] = 0x709,
474 [12] = 0x70a,
475};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800476
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700477/* NCT6779 specific data */
478
479static const u16 NCT6779_REG_IN[] = {
480 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
481 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
482
483static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
484 0x459, 0x45A, 0x45B, 0x568 };
485
486static const s8 NCT6779_ALARM_BITS[] = {
487 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
488 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
489 -1, /* unused */
490 6, 7, 11, 10, 23, /* fan1..fan5 */
491 -1, -1, -1, /* unused */
492 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
493 12, 9 }; /* intrusion0, intrusion1 */
494
Guenter Roeck30846992013-06-24 22:21:59 -0700495static const s8 NCT6779_BEEP_BITS[] = {
496 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
497 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
498 24, /* global beep enable */
499 25, 26, 27, 28, 29, /* fan1..fan5 */
500 -1, -1, -1, /* unused */
501 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
502 30, 31 }; /* intrusion0, intrusion1 */
503
David Bartley578ab5f2013-06-24 22:28:28 -0700504static const u16 NCT6779_REG_FAN[] = {
Guenter Roeck55066352018-09-17 05:23:58 -0700505 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
Guenter Roeckc7932792018-09-06 09:47:51 -0700506static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
Guenter Roecke41da282018-09-18 20:48:29 -0700507 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f };
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",
Guenter Roeck3be8c9d2018-09-19 21:52:49 -0700707 "Agent0 Dimm0",
708 "Agent0 Dimm1",
709 "Agent1 Dimm0",
710 "Agent1 Dimm1",
Guenter Roeck419220d2017-05-17 18:19:18 -0700711 "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",
Guenter Roeck3be8c9d2018-09-19 21:52:49 -0700745 "Agent0 Dimm0",
746 "Agent0 Dimm1",
747 "Agent1 Dimm0",
748 "Agent1 Dimm1",
Guenter Roeck81820052018-02-21 13:09:39 -0800749 "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 Roeck05996822018-09-19 20:26:16 -0700760static const char *const nct6798_temp_label[] = {
761 "",
762 "SYSTIN",
763 "CPUTIN",
764 "AUXTIN0",
765 "AUXTIN1",
766 "AUXTIN2",
767 "AUXTIN3",
768 "AUXTIN4",
769 "SMBUSMASTER 0",
770 "SMBUSMASTER 1",
771 "Virtual_TEMP",
772 "Virtual_TEMP",
773 "",
774 "",
775 "",
776 "",
777 "PECI Agent 0",
778 "PECI Agent 1",
779 "PCH_CHIP_CPU_MAX_TEMP",
780 "PCH_CHIP_TEMP",
781 "PCH_CPU_TEMP",
782 "PCH_MCH_TEMP",
783 "Agent0 Dimm0",
784 "Agent0 Dimm1",
785 "Agent1 Dimm0",
786 "Agent1 Dimm1",
787 "BYTE_TEMP0",
788 "BYTE_TEMP1",
Guenter Roeck8a037462020-07-14 14:31:11 -0700789 "PECI Agent 0 Calibration", /* undocumented */
790 "PECI Agent 1 Calibration", /* undocumented */
Guenter Roeck05996822018-09-19 20:26:16 -0700791 "",
792 "Virtual_TEMP"
793};
794
Guenter Roeck8a037462020-07-14 14:31:11 -0700795#define NCT6798_TEMP_MASK 0xbfff0ffe
Guenter Roeck05996822018-09-19 20:26:16 -0700796#define NCT6798_VIRT_TEMP_MASK 0x80000c00
797
Guenter Roeck6c009502012-07-01 08:23:15 -0700798/* NCT6102D/NCT6106D specific data */
799
800#define NCT6106_REG_VBAT 0x318
801#define NCT6106_REG_DIODE 0x319
802#define NCT6106_DIODE_MASK 0x01
803
804static const u16 NCT6106_REG_IN_MAX[] = {
805 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
806static const u16 NCT6106_REG_IN_MIN[] = {
807 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
808static const u16 NCT6106_REG_IN[] = {
809 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
810
811static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800812static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700813static const u16 NCT6106_REG_TEMP_HYST[] = {
814 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
815static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700816 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
817static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
818 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
819static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
820 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700821static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
822static const u16 NCT6106_REG_TEMP_CONFIG[] = {
823 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
824
825static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
826static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
Guenter Roeckc7932792018-09-06 09:47:51 -0700827static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6 };
828static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700829
830static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
831static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700832static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
833static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700834static const u16 NCT6106_REG_TEMP_SOURCE[] = {
835 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
836
837static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
838static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
839 0x11b, 0x12b, 0x13b };
840
841static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
842#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
843static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
844
845static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
846static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
847static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
848static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
849static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
850static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
851
852static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
853
854static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
855static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
856static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
Björn Gerhartf3d43e22019-07-15 18:33:55 +0200857static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
Guenter Roeck6c009502012-07-01 08:23:15 -0700858static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
859static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
860
861static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
862static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
863
864static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
865 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
866
867static const s8 NCT6106_ALARM_BITS[] = {
868 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
869 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
870 -1, /* unused */
871 32, 33, 34, -1, -1, /* fan1..fan5 */
872 -1, -1, -1, /* unused */
873 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
874 48, -1 /* intrusion0, intrusion1 */
875};
876
Guenter Roeck30846992013-06-24 22:21:59 -0700877static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
878 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
879
880static const s8 NCT6106_BEEP_BITS[] = {
881 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
882 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
883 32, /* global beep enable */
884 24, 25, 26, 27, 28, /* fan1..fan5 */
885 -1, -1, -1, /* unused */
886 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
887 34, -1 /* intrusion0, intrusion1 */
888};
889
Guenter Roeckcc66b302017-05-17 18:05:06 -0700890static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
891 [14] = 0x51,
892 [15] = 0x52,
893 [16] = 0x54,
894};
Guenter Roeck6c009502012-07-01 08:23:15 -0700895
Guenter Roeckcc66b302017-05-17 18:05:06 -0700896static const u16 NCT6106_REG_TEMP_CRIT[32] = {
897 [11] = 0x204,
898 [12] = 0x205,
899};
Guenter Roeck6c009502012-07-01 08:23:15 -0700900
Björn Gerhart29c7cb42019-07-23 18:06:46 +0200901/* NCT6112D/NCT6114D/NCT6116D specific data */
902
903static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
904static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 };
905static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 };
906static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
907
908static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
909static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
910static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
911static const u16 NCT6116_REG_TEMP_SOURCE[] = {
912 0xb0, 0xb1, 0xb2 };
913
914static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
915 0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
916static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = {
917 0x11b, 0x12b, 0x13b, 0x19b, 0x1ab };
918
919static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = {
920 0x11c, 0x12c, 0x13c, 0x19c, 0x1ac };
921static const u16 NCT6116_REG_CRITICAL_PWM[] = {
922 0x11d, 0x12d, 0x13d, 0x19d, 0x1ad };
923
924static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = {
925 0x114, 0x124, 0x134, 0x194, 0x1a4 };
926static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = {
927 0x115, 0x125, 0x135, 0x195, 0x1a5 };
928static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = {
929 0x116, 0x126, 0x136, 0x196, 0x1a6 };
930static const u16 NCT6116_REG_FAN_START_OUTPUT[] = {
931 0x117, 0x127, 0x137, 0x197, 0x1a7 };
932static const u16 NCT6116_REG_FAN_STOP_TIME[] = {
933 0x118, 0x128, 0x138, 0x198, 0x1a8 };
934static const u16 NCT6116_REG_TOLERANCE_H[] = {
935 0x112, 0x122, 0x132, 0x192, 0x1a2 };
936
937static const u16 NCT6116_REG_TARGET[] = {
938 0x111, 0x121, 0x131, 0x191, 0x1a1 };
939
940static const u16 NCT6116_REG_AUTO_TEMP[] = {
941 0x160, 0x170, 0x180, 0x1d0, 0x1e0 };
942static const u16 NCT6116_REG_AUTO_PWM[] = {
943 0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
944
945static const s8 NCT6116_ALARM_BITS[] = {
946 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
947 9, -1, -1, -1, -1, -1, -1, /* in8..in9 */
948 -1, /* unused */
949 32, 33, 34, 35, 36, /* fan1..fan5 */
950 -1, -1, -1, /* unused */
951 16, 17, 18, -1, -1, -1, /* temp1..temp6 */
952 48, -1 /* intrusion0, intrusion1 */
953};
954
955static const s8 NCT6116_BEEP_BITS[] = {
956 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
957 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
958 32, /* global beep enable */
959 24, 25, 26, 27, 28, /* fan1..fan5 */
960 -1, -1, -1, /* unused */
961 16, 17, 18, -1, -1, -1, /* temp1..temp6 */
962 34, -1 /* intrusion0, intrusion1 */
963};
964
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800965static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
966{
967 if (mode == 0 && pwm == 255)
968 return off;
969 return mode + 1;
970}
971
972static int pwm_enable_to_reg(enum pwm_enable mode)
973{
974 if (mode == off)
975 return 0;
976 return mode - 1;
977}
978
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700979/*
980 * Conversions
981 */
982
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800983/* 1 is DC mode, output in ms */
984static unsigned int step_time_from_reg(u8 reg, u8 mode)
985{
986 return mode ? 400 * reg : 100 * reg;
987}
988
989static u8 step_time_to_reg(unsigned int msec, u8 mode)
990{
991 return clamp_val((mode ? (msec + 200) / 400 :
992 (msec + 50) / 100), 1, 255);
993}
994
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800995static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
996{
997 if (reg == 0 || reg == 255)
998 return 0;
999 return 1350000U / (reg << divreg);
1000}
1001
1002static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
1003{
1004 if ((reg & 0xff1f) == 0xff1f)
1005 return 0;
1006
1007 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
1008
1009 if (reg == 0)
1010 return 0;
1011
1012 return 1350000U / reg;
1013}
1014
1015static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
1016{
1017 if (reg == 0 || reg == 0xffff)
1018 return 0;
1019
1020 /*
1021 * Even though the registers are 16 bit wide, the fan divisor
1022 * still applies.
1023 */
1024 return 1350000U / (reg << divreg);
1025}
1026
Guenter Roeckf6de2982018-09-13 20:01:12 -07001027static unsigned int fan_from_reg_rpm(u16 reg, unsigned int divreg)
1028{
1029 return reg;
1030}
1031
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001032static u16 fan_to_reg(u32 fan, unsigned int divreg)
1033{
1034 if (!fan)
1035 return 0;
1036
1037 return (1350000U / fan) >> divreg;
1038}
1039
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001040static inline unsigned int
1041div_from_reg(u8 reg)
1042{
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001043 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001044}
1045
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001046/*
1047 * Some of the voltage inputs have internal scaling, the tables below
1048 * contain 8 (the ADC LSB in mV) * scaling factor * 100
1049 */
1050static const u16 scale_in[15] = {
1051 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
1052 800, 800
1053};
1054
1055static inline long in_from_reg(u8 reg, u8 nr)
1056{
1057 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
1058}
1059
1060static inline u8 in_to_reg(u32 val, u8 nr)
1061{
1062 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
1063}
1064
1065/*
1066 * Data structures and manipulation thereof
1067 */
1068
1069struct nct6775_data {
1070 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -07001071 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001072 enum kinds kind;
1073 const char *name;
1074
Guenter Roeck615fc8c2013-07-06 09:43:30 -07001075 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001076
Guenter Roeckb7a61352013-04-02 22:14:06 -07001077 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1078 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -08001079 */
1080 u8 temp_src[NUM_TEMP];
1081 u16 reg_temp_config[NUM_TEMP];
1082 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07001083 u32 temp_mask;
Guenter Roeck37196ba2018-09-13 19:43:58 -07001084 u32 virt_temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001085
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001086 u16 REG_CONFIG;
1087 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001088 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07001089 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001090
1091 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07001092 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001093
1094 const u16 *REG_VIN;
1095 const u16 *REG_IN_MINMAX[2];
1096
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001097 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001098 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001099 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001100 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001101 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07001102 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001103 const u16 *REG_FAN_TIME[3];
1104
1105 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001106
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001107 const u8 *REG_PWM_MODE;
1108 const u8 *PWM_MODE_MASK;
1109
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001110 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1111 * [3]=pwm_max, [4]=pwm_step,
1112 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001113 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001114 const u16 *REG_PWM_READ;
1115
Guenter Roeck6c009502012-07-01 08:23:15 -07001116 const u16 *REG_CRITICAL_PWM_ENABLE;
1117 u8 CRITICAL_PWM_ENABLE_MASK;
1118 const u16 *REG_CRITICAL_PWM;
1119
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001120 const u16 *REG_AUTO_TEMP;
1121 const u16 *REG_AUTO_PWM;
1122
1123 const u16 *REG_CRITICAL_TEMP;
1124 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
1125
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001126 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001127 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001128 const u16 *REG_WEIGHT_TEMP_SEL;
1129 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
1130
Guenter Roeckaa136e52012-12-04 03:26:05 -08001131 const u16 *REG_TEMP_OFFSET;
1132
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001133 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07001134 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001135
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001136 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
1137 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
1138
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001139 struct mutex update_lock;
1140 bool valid; /* true if following fields are valid */
1141 unsigned long last_updated; /* In jiffies */
1142
1143 /* Register values */
1144 u8 bank; /* current register bank */
1145 u8 in_num; /* number of in inputs we have */
1146 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -07001147 unsigned int rpm[NUM_FAN];
1148 u16 fan_min[NUM_FAN];
1149 u8 fan_pulses[NUM_FAN];
1150 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001151 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001152 u8 has_fan; /* some fan inputs can be disabled */
1153 u8 has_fan_min; /* some fans don't have min register */
1154 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001155
Guenter Roeck6c009502012-07-01 08:23:15 -07001156 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001157 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001158 u8 temp_fixed_num; /* 3 or 6 */
1159 u8 temp_type[NUM_TEMP_FIXED];
1160 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001161 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1162 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001163 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001164 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001165
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001166 u8 pwm_num; /* number of pwm */
Guenter Roeck57fec3a2018-06-18 09:21:46 -07001167 u8 pwm_mode[NUM_FAN]; /* 0->DC variable voltage,
1168 * 1->PWM variable duty cycle
David Bartley578ab5f2013-06-24 22:28:28 -07001169 */
1170 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001171 /* 0->off
1172 * 1->manual
1173 * 2->thermal cruise mode (also called SmartFan I)
1174 * 3->fan speed cruise mode
1175 * 4->SmartFan III
1176 * 5->enhanced variable thermal cruise (SmartFan IV)
1177 */
David Bartley578ab5f2013-06-24 22:28:28 -07001178 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1179 * [3]=pwm_max, [4]=pwm_step,
1180 * [5]=weight_duty_step, [6]=weight_duty_base
1181 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001182
David Bartley578ab5f2013-06-24 22:28:28 -07001183 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001184 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001185 u32 target_speed[NUM_FAN];
1186 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001187 u8 speed_tolerance_limit;
1188
David Bartley578ab5f2013-06-24 22:28:28 -07001189 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001190 u8 tolerance_mask;
1191
David Bartley578ab5f2013-06-24 22:28:28 -07001192 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001193
1194 /* Automatic fan speed control registers */
1195 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001196 u8 auto_pwm[NUM_FAN][7];
1197 u8 auto_temp[NUM_FAN][7];
1198 u8 pwm_temp_sel[NUM_FAN];
1199 u8 pwm_weight_temp_sel[NUM_FAN];
1200 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1201 * 2->temp_base
1202 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001203
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001204 u8 vid;
1205 u8 vrm;
1206
Guenter Roeckf73cf632013-03-18 09:22:50 -07001207 bool have_vid;
1208
Guenter Roeckaa136e52012-12-04 03:26:05 -08001209 u16 have_temp;
1210 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001211 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001212
Guenter Roeck84d19d92012-12-04 08:01:39 -08001213 /* Remember extra register values over suspend/resume */
1214 u8 vbat;
1215 u8 fandiv1;
1216 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001217 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001218};
1219
1220struct nct6775_sio_data {
1221 int sioreg;
1222 enum kinds kind;
1223};
1224
Guenter Roeckf73cf632013-03-18 09:22:50 -07001225struct sensor_device_template {
1226 struct device_attribute dev_attr;
1227 union {
1228 struct {
1229 u8 nr;
1230 u8 index;
1231 } s;
1232 int index;
1233 } u;
1234 bool s2; /* true if both index and nr are used */
1235};
1236
1237struct sensor_device_attr_u {
1238 union {
1239 struct sensor_device_attribute a1;
1240 struct sensor_device_attribute_2 a2;
1241 } u;
1242 char name[32];
1243};
1244
1245#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1246 .attr = {.name = _template, .mode = _mode }, \
1247 .show = _show, \
1248 .store = _store, \
1249}
1250
1251#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1252 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1253 .u.index = _index, \
1254 .s2 = false }
1255
1256#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1257 _nr, _index) \
1258 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1259 .u.s.index = _index, \
1260 .u.s.nr = _nr, \
1261 .s2 = true }
1262
1263#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1264static struct sensor_device_template sensor_dev_template_##_name \
1265 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1266 _index)
1267
1268#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1269 _nr, _index) \
1270static struct sensor_device_template sensor_dev_template_##_name \
1271 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1272 _nr, _index)
1273
1274struct sensor_template_group {
1275 struct sensor_device_template **templates;
1276 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1277 int base;
1278};
1279
1280static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001281nct6775_create_attr_group(struct device *dev,
1282 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001283 int repeat)
1284{
1285 struct attribute_group *group;
1286 struct sensor_device_attr_u *su;
1287 struct sensor_device_attribute *a;
1288 struct sensor_device_attribute_2 *a2;
1289 struct attribute **attrs;
1290 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001291 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001292
1293 if (repeat <= 0)
1294 return ERR_PTR(-EINVAL);
1295
1296 t = tg->templates;
1297 for (count = 0; *t; t++, count++)
1298 ;
1299
1300 if (count == 0)
1301 return ERR_PTR(-EINVAL);
1302
1303 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1304 if (group == NULL)
1305 return ERR_PTR(-ENOMEM);
1306
Kees Cooka86854d2018-06-12 14:07:58 -07001307 attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001308 GFP_KERNEL);
1309 if (attrs == NULL)
1310 return ERR_PTR(-ENOMEM);
1311
Kees Cooka86854d2018-06-12 14:07:58 -07001312 su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001313 GFP_KERNEL);
1314 if (su == NULL)
1315 return ERR_PTR(-ENOMEM);
1316
1317 group->attrs = attrs;
1318 group->is_visible = tg->is_visible;
1319
1320 for (i = 0; i < repeat; i++) {
1321 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001322 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001323 snprintf(su->name, sizeof(su->name),
1324 (*t)->dev_attr.attr.name, tg->base + i);
1325 if ((*t)->s2) {
1326 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001327 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001328 a2->dev_attr.attr.name = su->name;
1329 a2->nr = (*t)->u.s.nr + i;
1330 a2->index = (*t)->u.s.index;
1331 a2->dev_attr.attr.mode =
1332 (*t)->dev_attr.attr.mode;
1333 a2->dev_attr.show = (*t)->dev_attr.show;
1334 a2->dev_attr.store = (*t)->dev_attr.store;
1335 *attrs = &a2->dev_attr.attr;
1336 } else {
1337 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001338 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001339 a->dev_attr.attr.name = su->name;
1340 a->index = (*t)->u.index + i;
1341 a->dev_attr.attr.mode =
1342 (*t)->dev_attr.attr.mode;
1343 a->dev_attr.show = (*t)->dev_attr.show;
1344 a->dev_attr.store = (*t)->dev_attr.store;
1345 *attrs = &a->dev_attr.attr;
1346 }
1347 attrs++;
1348 su++;
1349 t++;
1350 }
1351 }
1352
Guenter Roeckf73cf632013-03-18 09:22:50 -07001353 return group;
1354}
1355
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001356static bool is_word_sized(struct nct6775_data *data, u16 reg)
1357{
1358 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001359 case nct6106:
1360 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1361 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1362 reg == 0x111 || reg == 0x121 || reg == 0x131;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02001363 case nct6116:
1364 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1365 reg == 0x26 || reg == 0x28 || reg == 0xe0 || reg == 0xe2 ||
1366 reg == 0xe4 || reg == 0xe6 || reg == 0xe8 || reg == 0x111 ||
1367 reg == 0x121 || reg == 0x131 || reg == 0x191 || reg == 0x1a1;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001368 case nct6775:
1369 return (((reg & 0xff00) == 0x100 ||
1370 (reg & 0xff00) == 0x200) &&
1371 ((reg & 0x00ff) == 0x50 ||
1372 (reg & 0x00ff) == 0x53 ||
1373 (reg & 0x00ff) == 0x55)) ||
1374 (reg & 0xfff0) == 0x630 ||
1375 reg == 0x640 || reg == 0x642 ||
1376 reg == 0x662 ||
1377 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1378 reg == 0x73 || reg == 0x75 || reg == 0x77;
1379 case nct6776:
1380 return (((reg & 0xff00) == 0x100 ||
1381 (reg & 0xff00) == 0x200) &&
1382 ((reg & 0x00ff) == 0x50 ||
1383 (reg & 0x00ff) == 0x53 ||
1384 (reg & 0x00ff) == 0x55)) ||
1385 (reg & 0xfff0) == 0x630 ||
1386 reg == 0x402 ||
1387 reg == 0x640 || reg == 0x642 ||
1388 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1389 reg == 0x73 || reg == 0x75 || reg == 0x77;
1390 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001391 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001392 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001393 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001394 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001395 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07001396 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07001397 case nct6798:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001398 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
Guenter Roeckf6de2982018-09-13 20:01:12 -07001399 (reg & 0xfff0) == 0x4c0 ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001400 reg == 0x402 ||
1401 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001402 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck55066352018-09-17 05:23:58 -07001403 reg == 0x64c ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001404 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001405 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001406 }
1407 return false;
1408}
1409
1410/*
1411 * On older chips, only registers 0x50-0x5f are banked.
1412 * On more recent chips, all registers are banked.
1413 * Assume that is the case and set the bank number for each access.
1414 * Cache the bank number so it only needs to be set if it changes.
1415 */
1416static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1417{
1418 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001419
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001420 if (data->bank != bank) {
1421 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1422 outb_p(bank, data->addr + DATA_REG_OFFSET);
1423 data->bank = bank;
1424 }
1425}
1426
1427static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1428{
1429 int res, word_sized = is_word_sized(data, reg);
1430
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001431 nct6775_set_bank(data, reg);
1432 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1433 res = inb_p(data->addr + DATA_REG_OFFSET);
1434 if (word_sized) {
1435 outb_p((reg & 0xff) + 1,
1436 data->addr + ADDR_REG_OFFSET);
1437 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1438 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001439 return res;
1440}
1441
1442static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1443{
1444 int word_sized = is_word_sized(data, reg);
1445
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001446 nct6775_set_bank(data, reg);
1447 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1448 if (word_sized) {
1449 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1450 outb_p((reg & 0xff) + 1,
1451 data->addr + ADDR_REG_OFFSET);
1452 }
1453 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001454 return 0;
1455}
1456
Guenter Roeckaa136e52012-12-04 03:26:05 -08001457/* We left-align 8-bit temperature values to make the code simpler */
1458static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1459{
1460 u16 res;
1461
1462 res = nct6775_read_value(data, reg);
1463 if (!is_word_sized(data, reg))
1464 res <<= 8;
1465
1466 return res;
1467}
1468
1469static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1470{
1471 if (!is_word_sized(data, reg))
1472 value >>= 8;
1473 return nct6775_write_value(data, reg, value);
1474}
1475
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001476/* This function assumes that the caller holds data->update_lock */
1477static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1478{
1479 u8 reg;
1480
1481 switch (nr) {
1482 case 0:
1483 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1484 | (data->fan_div[0] & 0x7);
1485 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1486 break;
1487 case 1:
1488 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1489 | ((data->fan_div[1] << 4) & 0x70);
1490 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1491 break;
1492 case 2:
1493 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1494 | (data->fan_div[2] & 0x7);
1495 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1496 break;
1497 case 3:
1498 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1499 | ((data->fan_div[3] << 4) & 0x70);
1500 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1501 break;
1502 }
1503}
1504
1505static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1506{
1507 if (data->kind == nct6775)
1508 nct6775_write_fan_div(data, nr);
1509}
1510
1511static void nct6775_update_fan_div(struct nct6775_data *data)
1512{
1513 u8 i;
1514
1515 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1516 data->fan_div[0] = i & 0x7;
1517 data->fan_div[1] = (i & 0x70) >> 4;
1518 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1519 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001520 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001521 data->fan_div[3] = (i & 0x70) >> 4;
1522}
1523
1524static void nct6775_update_fan_div_common(struct nct6775_data *data)
1525{
1526 if (data->kind == nct6775)
1527 nct6775_update_fan_div(data);
1528}
1529
1530static void nct6775_init_fan_div(struct nct6775_data *data)
1531{
1532 int i;
1533
1534 nct6775_update_fan_div_common(data);
1535 /*
1536 * For all fans, start with highest divider value if the divider
1537 * register is not initialized. This ensures that we get a
1538 * reading from the fan count register, even if it is not optimal.
1539 * We'll compute a better divider later on.
1540 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001541 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001542 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001543 continue;
1544 if (data->fan_div[i] == 0) {
1545 data->fan_div[i] = 7;
1546 nct6775_write_fan_div_common(data, i);
1547 }
1548 }
1549}
1550
1551static void nct6775_init_fan_common(struct device *dev,
1552 struct nct6775_data *data)
1553{
1554 int i;
1555 u8 reg;
1556
1557 if (data->has_fan_div)
1558 nct6775_init_fan_div(data);
1559
1560 /*
1561 * If fan_min is not set (0), set it to 0xff to disable it. This
1562 * prevents the unnecessary warning when fanX_min is reported as 0.
1563 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001564 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001565 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001566 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1567 if (!reg)
1568 nct6775_write_value(data, data->REG_FAN_MIN[i],
1569 data->has_fan_div ? 0xff
1570 : 0xff1f);
1571 }
1572 }
1573}
1574
1575static void nct6775_select_fan_div(struct device *dev,
1576 struct nct6775_data *data, int nr, u16 reg)
1577{
1578 u8 fan_div = data->fan_div[nr];
1579 u16 fan_min;
1580
1581 if (!data->has_fan_div)
1582 return;
1583
1584 /*
1585 * If we failed to measure the fan speed, or the reported value is not
1586 * in the optimal range, and the clock divider can be modified,
1587 * let's try that for next time.
1588 */
1589 if (reg == 0x00 && fan_div < 0x07)
1590 fan_div++;
1591 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1592 fan_div--;
1593
1594 if (fan_div != data->fan_div[nr]) {
1595 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1596 nr + 1, div_from_reg(data->fan_div[nr]),
1597 div_from_reg(fan_div));
1598
1599 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001600 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001601 fan_min = data->fan_min[nr];
1602 if (fan_div > data->fan_div[nr]) {
1603 if (fan_min != 255 && fan_min > 1)
1604 fan_min >>= 1;
1605 } else {
1606 if (fan_min != 255) {
1607 fan_min <<= 1;
1608 if (fan_min > 254)
1609 fan_min = 254;
1610 }
1611 }
1612 if (fan_min != data->fan_min[nr]) {
1613 data->fan_min[nr] = fan_min;
1614 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1615 fan_min);
1616 }
1617 }
1618 data->fan_div[nr] = fan_div;
1619 nct6775_write_fan_div_common(data, nr);
1620 }
1621}
1622
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001623static void nct6775_update_pwm(struct device *dev)
1624{
1625 struct nct6775_data *data = dev_get_drvdata(dev);
1626 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001627 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001628 bool duty_is_dc;
1629
1630 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001631 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001632 continue;
1633
1634 duty_is_dc = data->REG_PWM_MODE[i] &&
1635 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1636 & data->PWM_MODE_MASK[i]);
Guenter Roeck415eb2a2018-03-26 19:50:31 -07001637 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001638
1639 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1640 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1641 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1642 data->pwm[j][i]
1643 = nct6775_read_value(data,
1644 data->REG_PWM[j][i]);
1645 }
1646 }
1647
1648 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1649 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001650
1651 if (!data->temp_tolerance[0][i] ||
1652 data->pwm_enable[i] != speed_cruise)
1653 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1654 if (!data->target_speed_tolerance[i] ||
1655 data->pwm_enable[i] == speed_cruise) {
1656 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001657
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001658 if (data->REG_TOLERANCE_H) {
1659 t |= (nct6775_read_value(data,
1660 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1661 }
1662 data->target_speed_tolerance[i] = t;
1663 }
1664
1665 data->temp_tolerance[1][i] =
1666 nct6775_read_value(data,
1667 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1668
1669 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1670 data->pwm_temp_sel[i] = reg & 0x1f;
1671 /* If fan can stop, report floor as 0 */
1672 if (reg & 0x80)
1673 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001674
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001675 if (!data->REG_WEIGHT_TEMP_SEL[i])
1676 continue;
1677
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001678 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1679 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1680 /* If weight is disabled, report weight source as 0 */
Dan Carpentere3f3d7a2018-09-05 10:46:27 +03001681 if (!(reg & 0x80))
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001682 data->pwm_weight_temp_sel[i] = 0;
1683
1684 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001685 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001686 data->weight_temp[j][i]
1687 = nct6775_read_value(data,
1688 data->REG_WEIGHT_TEMP[j][i]);
1689 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001690 }
1691}
1692
1693static void nct6775_update_pwm_limits(struct device *dev)
1694{
1695 struct nct6775_data *data = dev_get_drvdata(dev);
1696 int i, j;
1697 u8 reg;
1698 u16 reg_t;
1699
1700 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001701 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001702 continue;
1703
Guenter Roeckc409fd42013-04-09 05:04:00 -07001704 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001705 data->fan_time[j][i] =
1706 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1707 }
1708
1709 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1710 /* Update only in matching mode or if never updated */
1711 if (!data->target_temp[i] ||
1712 data->pwm_enable[i] == thermal_cruise)
1713 data->target_temp[i] = reg_t & data->target_temp_mask;
1714 if (!data->target_speed[i] ||
1715 data->pwm_enable[i] == speed_cruise) {
1716 if (data->REG_TOLERANCE_H) {
1717 reg_t |= (nct6775_read_value(data,
1718 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1719 }
1720 data->target_speed[i] = reg_t;
1721 }
1722
1723 for (j = 0; j < data->auto_pwm_num; j++) {
1724 data->auto_pwm[i][j] =
1725 nct6775_read_value(data,
1726 NCT6775_AUTO_PWM(data, i, j));
1727 data->auto_temp[i][j] =
1728 nct6775_read_value(data,
1729 NCT6775_AUTO_TEMP(data, i, j));
1730 }
1731
1732 /* critical auto_pwm temperature data */
1733 data->auto_temp[i][data->auto_pwm_num] =
1734 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1735
1736 switch (data->kind) {
1737 case nct6775:
1738 reg = nct6775_read_value(data,
1739 NCT6775_REG_CRITICAL_ENAB[i]);
1740 data->auto_pwm[i][data->auto_pwm_num] =
1741 (reg & 0x02) ? 0xff : 0x00;
1742 break;
1743 case nct6776:
1744 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1745 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001746 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02001747 case nct6116:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001748 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001749 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001750 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001751 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001752 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001753 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07001754 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07001755 case nct6798:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001756 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001757 data->REG_CRITICAL_PWM_ENABLE[i]);
1758 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1759 reg = nct6775_read_value(data,
1760 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001761 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001762 reg = 0xff;
1763 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001764 break;
1765 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001766 }
1767}
1768
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001769static struct nct6775_data *nct6775_update_device(struct device *dev)
1770{
1771 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001772 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001773
1774 mutex_lock(&data->update_lock);
1775
Guenter Roeck6445e662013-04-21 09:13:28 -07001776 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001777 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001778 /* Fan clock dividers */
1779 nct6775_update_fan_div_common(data);
1780
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001781 /* Measured voltages and limits */
1782 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001783 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001784 continue;
1785
1786 data->in[i][0] = nct6775_read_value(data,
1787 data->REG_VIN[i]);
1788 data->in[i][1] = nct6775_read_value(data,
1789 data->REG_IN_MINMAX[0][i]);
1790 data->in[i][2] = nct6775_read_value(data,
1791 data->REG_IN_MINMAX[1][i]);
1792 }
1793
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001794 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001795 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001796 u16 reg;
1797
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001798 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001799 continue;
1800
1801 reg = nct6775_read_value(data, data->REG_FAN[i]);
1802 data->rpm[i] = data->fan_from_reg(reg,
1803 data->fan_div[i]);
1804
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001805 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001806 data->fan_min[i] = nct6775_read_value(data,
1807 data->REG_FAN_MIN[i]);
Guenter Roeckc7932792018-09-06 09:47:51 -07001808
1809 if (data->REG_FAN_PULSES[i]) {
1810 data->fan_pulses[i] =
1811 (nct6775_read_value(data,
1812 data->REG_FAN_PULSES[i])
1813 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
1814 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001815
1816 nct6775_select_fan_div(dev, data, i, reg);
1817 }
1818
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001819 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001820 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001821
Guenter Roeckaa136e52012-12-04 03:26:05 -08001822 /* Measured temperatures and limits */
1823 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001824 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001825 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001826 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001827 if (data->reg_temp[j][i])
1828 data->temp[j][i]
1829 = nct6775_read_temp(data,
1830 data->reg_temp[j][i]);
1831 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001832 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001833 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001834 continue;
1835 data->temp_offset[i]
1836 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1837 }
1838
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001839 data->alarms = 0;
1840 for (i = 0; i < NUM_REG_ALARM; i++) {
1841 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001842
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001843 if (!data->REG_ALARM[i])
1844 continue;
1845 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1846 data->alarms |= ((u64)alarm) << (i << 3);
1847 }
1848
Guenter Roeck30846992013-06-24 22:21:59 -07001849 data->beeps = 0;
1850 for (i = 0; i < NUM_REG_BEEP; i++) {
1851 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001852
Guenter Roeck30846992013-06-24 22:21:59 -07001853 if (!data->REG_BEEP[i])
1854 continue;
1855 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1856 data->beeps |= ((u64)beep) << (i << 3);
1857 }
1858
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001859 data->last_updated = jiffies;
1860 data->valid = true;
1861 }
1862
1863 mutex_unlock(&data->update_lock);
1864 return data;
1865}
1866
1867/*
1868 * Sysfs callback functions
1869 */
1870static ssize_t
1871show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1872{
1873 struct nct6775_data *data = nct6775_update_device(dev);
1874 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001875 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001876 int nr = sattr->nr;
1877
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001878 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1879}
1880
1881static ssize_t
1882store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1883 size_t count)
1884{
1885 struct nct6775_data *data = dev_get_drvdata(dev);
1886 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001887 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001888 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001889 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001890 int err;
1891
1892 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001893 if (err < 0)
1894 return err;
1895 mutex_lock(&data->update_lock);
1896 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001897 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001898 data->in[nr][index]);
1899 mutex_unlock(&data->update_lock);
1900 return count;
1901}
1902
1903static ssize_t
1904show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1905{
1906 struct nct6775_data *data = nct6775_update_device(dev);
1907 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1908 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001909
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001910 return sprintf(buf, "%u\n",
1911 (unsigned int)((data->alarms >> nr) & 0x01));
1912}
1913
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001914static int find_temp_source(struct nct6775_data *data, int index, int count)
1915{
1916 int source = data->temp_src[index];
1917 int nr;
1918
1919 for (nr = 0; nr < count; nr++) {
1920 int src;
1921
1922 src = nct6775_read_value(data,
1923 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1924 if (src == source)
1925 return nr;
1926 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001927 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001928}
1929
1930static ssize_t
1931show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1932{
1933 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1934 struct nct6775_data *data = nct6775_update_device(dev);
1935 unsigned int alarm = 0;
1936 int nr;
1937
1938 /*
1939 * For temperatures, there is no fixed mapping from registers to alarm
1940 * bits. Alarm bits are determined by the temperature source mapping.
1941 */
1942 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1943 if (nr >= 0) {
1944 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001945
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001946 alarm = (data->alarms >> bit) & 0x01;
1947 }
1948 return sprintf(buf, "%u\n", alarm);
1949}
1950
Guenter Roeck30846992013-06-24 22:21:59 -07001951static ssize_t
1952show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1953{
1954 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1955 struct nct6775_data *data = nct6775_update_device(dev);
1956 int nr = data->BEEP_BITS[sattr->index];
1957
1958 return sprintf(buf, "%u\n",
1959 (unsigned int)((data->beeps >> nr) & 0x01));
1960}
1961
1962static ssize_t
1963store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1964 size_t count)
1965{
1966 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1967 struct nct6775_data *data = dev_get_drvdata(dev);
1968 int nr = data->BEEP_BITS[sattr->index];
1969 int regindex = nr >> 3;
1970 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001971 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001972
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001973 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001974 if (err < 0)
1975 return err;
1976 if (val > 1)
1977 return -EINVAL;
1978
1979 mutex_lock(&data->update_lock);
1980 if (val)
1981 data->beeps |= (1ULL << nr);
1982 else
1983 data->beeps &= ~(1ULL << nr);
1984 nct6775_write_value(data, data->REG_BEEP[regindex],
1985 (data->beeps >> (regindex << 3)) & 0xff);
1986 mutex_unlock(&data->update_lock);
1987 return count;
1988}
1989
1990static ssize_t
1991show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1992{
1993 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1994 struct nct6775_data *data = nct6775_update_device(dev);
1995 unsigned int beep = 0;
1996 int nr;
1997
1998 /*
1999 * For temperatures, there is no fixed mapping from registers to beep
2000 * enable bits. Beep enable bits are determined by the temperature
2001 * source mapping.
2002 */
2003 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
2004 if (nr >= 0) {
2005 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002006
Guenter Roeck30846992013-06-24 22:21:59 -07002007 beep = (data->beeps >> bit) & 0x01;
2008 }
2009 return sprintf(buf, "%u\n", beep);
2010}
2011
2012static ssize_t
2013store_temp_beep(struct device *dev, struct device_attribute *attr,
2014 const char *buf, size_t count)
2015{
2016 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2017 struct nct6775_data *data = dev_get_drvdata(dev);
2018 int nr, bit, regindex;
2019 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002020 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07002021
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002022 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07002023 if (err < 0)
2024 return err;
2025 if (val > 1)
2026 return -EINVAL;
2027
2028 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
2029 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07002030 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07002031
2032 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
2033 regindex = bit >> 3;
2034
2035 mutex_lock(&data->update_lock);
2036 if (val)
2037 data->beeps |= (1ULL << bit);
2038 else
2039 data->beeps &= ~(1ULL << bit);
2040 nct6775_write_value(data, data->REG_BEEP[regindex],
2041 (data->beeps >> (regindex << 3)) & 0xff);
2042 mutex_unlock(&data->update_lock);
2043
2044 return count;
2045}
2046
Guenter Roeckf73cf632013-03-18 09:22:50 -07002047static umode_t nct6775_in_is_visible(struct kobject *kobj,
2048 struct attribute *attr, int index)
2049{
zhouchuangao036855a2020-05-11 11:43:06 +08002050 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002051 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002052 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002053
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002054 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002055 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002056
Guenter Roeckf73cf632013-03-18 09:22:50 -07002057 return attr->mode;
2058}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002059
Guenter Roeckf73cf632013-03-18 09:22:50 -07002060SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
2061SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002062SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
2063 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002064SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
2065 store_in_reg, 0, 1);
2066SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
2067 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002068
Guenter Roeckf73cf632013-03-18 09:22:50 -07002069/*
2070 * nct6775_in_is_visible uses the index into the following array
2071 * to determine if attributes should be created or not.
2072 * Any change in order or content must be matched.
2073 */
2074static struct sensor_device_template *nct6775_attributes_in_template[] = {
2075 &sensor_dev_template_in_input,
2076 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07002077 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07002078 &sensor_dev_template_in_min,
2079 &sensor_dev_template_in_max,
2080 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002081};
2082
Julia Lawallc60fdf82015-12-12 17:36:39 +01002083static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002084 .templates = nct6775_attributes_in_template,
2085 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002086};
2087
2088static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002089show_fan(struct device *dev, struct device_attribute *attr, char *buf)
2090{
2091 struct nct6775_data *data = nct6775_update_device(dev);
2092 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2093 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002094
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002095 return sprintf(buf, "%d\n", data->rpm[nr]);
2096}
2097
2098static ssize_t
2099show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
2100{
2101 struct nct6775_data *data = nct6775_update_device(dev);
2102 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2103 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002104
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002105 return sprintf(buf, "%d\n",
2106 data->fan_from_reg_min(data->fan_min[nr],
2107 data->fan_div[nr]));
2108}
2109
2110static ssize_t
2111show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
2112{
2113 struct nct6775_data *data = nct6775_update_device(dev);
2114 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2115 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002116
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002117 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
2118}
2119
2120static ssize_t
2121store_fan_min(struct device *dev, struct device_attribute *attr,
2122 const char *buf, size_t count)
2123{
2124 struct nct6775_data *data = dev_get_drvdata(dev);
2125 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2126 int nr = sattr->index;
2127 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002128 unsigned int reg;
2129 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002130 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002131
2132 err = kstrtoul(buf, 10, &val);
2133 if (err < 0)
2134 return err;
2135
2136 mutex_lock(&data->update_lock);
2137 if (!data->has_fan_div) {
2138 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
2139 if (!val) {
2140 val = 0xff1f;
2141 } else {
2142 if (val > 1350000U)
2143 val = 135000U;
2144 val = 1350000U / val;
2145 val = (val & 0x1f) | ((val << 3) & 0xff00);
2146 }
2147 data->fan_min[nr] = val;
2148 goto write_min; /* Leave fan divider alone */
2149 }
2150 if (!val) {
2151 /* No min limit, alarm disabled */
2152 data->fan_min[nr] = 255;
2153 new_div = data->fan_div[nr]; /* No change */
2154 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
2155 goto write_div;
2156 }
2157 reg = 1350000U / val;
2158 if (reg >= 128 * 255) {
2159 /*
2160 * Speed below this value cannot possibly be represented,
2161 * even with the highest divider (128)
2162 */
2163 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002164 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002165 dev_warn(dev,
2166 "fan%u low limit %lu below minimum %u, set to minimum\n",
2167 nr + 1, val, data->fan_from_reg_min(254, 7));
2168 } else if (!reg) {
2169 /*
2170 * Speed above this value cannot possibly be represented,
2171 * even with the lowest divider (1)
2172 */
2173 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002174 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002175 dev_warn(dev,
2176 "fan%u low limit %lu above maximum %u, set to maximum\n",
2177 nr + 1, val, data->fan_from_reg_min(1, 0));
2178 } else {
2179 /*
2180 * Automatically pick the best divider, i.e. the one such
2181 * that the min limit will correspond to a register value
2182 * in the 96..192 range
2183 */
2184 new_div = 0;
2185 while (reg > 192 && new_div < 7) {
2186 reg >>= 1;
2187 new_div++;
2188 }
2189 data->fan_min[nr] = reg;
2190 }
2191
2192write_div:
2193 /*
2194 * Write both the fan clock divider (if it changed) and the new
2195 * fan min (unconditionally)
2196 */
2197 if (new_div != data->fan_div[nr]) {
2198 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2199 nr + 1, div_from_reg(data->fan_div[nr]),
2200 div_from_reg(new_div));
2201 data->fan_div[nr] = new_div;
2202 nct6775_write_fan_div_common(data, nr);
2203 /* Give the chip time to sample a new speed value */
2204 data->last_updated = jiffies;
2205 }
2206
2207write_min:
2208 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2209 mutex_unlock(&data->update_lock);
2210
2211 return count;
2212}
2213
Guenter Roeck5c25d952012-12-11 07:29:06 -08002214static ssize_t
2215show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2216{
2217 struct nct6775_data *data = nct6775_update_device(dev);
2218 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2219 int p = data->fan_pulses[sattr->index];
2220
2221 return sprintf(buf, "%d\n", p ? : 4);
2222}
2223
2224static ssize_t
2225store_fan_pulses(struct device *dev, struct device_attribute *attr,
2226 const char *buf, size_t count)
2227{
2228 struct nct6775_data *data = dev_get_drvdata(dev);
2229 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2230 int nr = sattr->index;
2231 unsigned long val;
2232 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002233 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002234
2235 err = kstrtoul(buf, 10, &val);
2236 if (err < 0)
2237 return err;
2238
2239 if (val > 4)
2240 return -EINVAL;
2241
2242 mutex_lock(&data->update_lock);
2243 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002244 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2245 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2246 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2247 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002248 mutex_unlock(&data->update_lock);
2249
2250 return count;
2251}
2252
Guenter Roeckf73cf632013-03-18 09:22:50 -07002253static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2254 struct attribute *attr, int index)
2255{
zhouchuangao036855a2020-05-11 11:43:06 +08002256 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002257 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002258 int fan = index / 6; /* fan index */
2259 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002260
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002261 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002262 return 0;
2263
2264 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2265 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002266 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002267 return 0;
Guenter Roeck81820052018-02-21 13:09:39 -08002268 if (nr == 3 && !data->REG_FAN_PULSES[fan])
2269 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002270 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002271 return 0;
2272 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002273 return 0;
2274
2275 return attr->mode;
2276}
2277
2278SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2279SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2280 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002281SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2282 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002283SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2284 store_fan_pulses, 0);
2285SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2286 store_fan_min, 0);
2287SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2288
2289/*
2290 * nct6775_fan_is_visible uses the index into the following array
2291 * to determine if attributes should be created or not.
2292 * Any change in order or content must be matched.
2293 */
2294static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2295 &sensor_dev_template_fan_input,
2296 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002297 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002298 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002299 &sensor_dev_template_fan_min, /* 4 */
2300 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002301 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002302};
2303
Julia Lawallc60fdf82015-12-12 17:36:39 +01002304static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002305 .templates = nct6775_attributes_fan_template,
2306 .is_visible = nct6775_fan_is_visible,
2307 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002308};
2309
2310static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002311show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2312{
2313 struct nct6775_data *data = nct6775_update_device(dev);
2314 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2315 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002316
Guenter Roeckaa136e52012-12-04 03:26:05 -08002317 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2318}
2319
2320static ssize_t
2321show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2322{
2323 struct nct6775_data *data = nct6775_update_device(dev);
2324 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2325 int nr = sattr->nr;
2326 int index = sattr->index;
2327
2328 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2329}
2330
2331static ssize_t
2332store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2333 size_t count)
2334{
2335 struct nct6775_data *data = dev_get_drvdata(dev);
2336 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2337 int nr = sattr->nr;
2338 int index = sattr->index;
2339 int err;
2340 long val;
2341
2342 err = kstrtol(buf, 10, &val);
2343 if (err < 0)
2344 return err;
2345
2346 mutex_lock(&data->update_lock);
2347 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2348 nct6775_write_temp(data, data->reg_temp[index][nr],
2349 data->temp[index][nr]);
2350 mutex_unlock(&data->update_lock);
2351 return count;
2352}
2353
2354static ssize_t
2355show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2356{
2357 struct nct6775_data *data = nct6775_update_device(dev);
2358 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2359
2360 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2361}
2362
2363static ssize_t
2364store_temp_offset(struct device *dev, struct device_attribute *attr,
2365 const char *buf, size_t count)
2366{
2367 struct nct6775_data *data = dev_get_drvdata(dev);
2368 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2369 int nr = sattr->index;
2370 long val;
2371 int err;
2372
2373 err = kstrtol(buf, 10, &val);
2374 if (err < 0)
2375 return err;
2376
2377 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2378
2379 mutex_lock(&data->update_lock);
2380 data->temp_offset[nr] = val;
2381 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2382 mutex_unlock(&data->update_lock);
2383
2384 return count;
2385}
2386
2387static ssize_t
2388show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2389{
2390 struct nct6775_data *data = nct6775_update_device(dev);
2391 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2392 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002393
Guenter Roeckaa136e52012-12-04 03:26:05 -08002394 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2395}
2396
2397static ssize_t
2398store_temp_type(struct device *dev, struct device_attribute *attr,
2399 const char *buf, size_t count)
2400{
2401 struct nct6775_data *data = nct6775_update_device(dev);
2402 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2403 int nr = sattr->index;
2404 unsigned long val;
2405 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002406 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002407
2408 err = kstrtoul(buf, 10, &val);
2409 if (err < 0)
2410 return err;
2411
2412 if (val != 1 && val != 3 && val != 4)
2413 return -EINVAL;
2414
2415 mutex_lock(&data->update_lock);
2416
2417 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002418 vbit = 0x02 << nr;
2419 dbit = data->DIODE_MASK << nr;
2420 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2421 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002422 switch (val) {
2423 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002424 vbat |= vbit;
2425 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002426 break;
2427 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002428 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002429 break;
2430 case 4: /* thermistor */
2431 break;
2432 }
2433 nct6775_write_value(data, data->REG_VBAT, vbat);
2434 nct6775_write_value(data, data->REG_DIODE, diode);
2435
2436 mutex_unlock(&data->update_lock);
2437 return count;
2438}
2439
Guenter Roeckf73cf632013-03-18 09:22:50 -07002440static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2441 struct attribute *attr, int index)
2442{
zhouchuangao036855a2020-05-11 11:43:06 +08002443 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002444 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002445 int temp = index / 10; /* temp index */
2446 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002447
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002448 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002449 return 0;
2450
Guenter Roeckcc66b302017-05-17 18:05:06 -07002451 if (nr == 1 && !data->temp_label)
2452 return 0;
2453
Guenter Roeckf73cf632013-03-18 09:22:50 -07002454 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2455 return 0; /* alarm */
2456
Guenter Roeck30846992013-06-24 22:21:59 -07002457 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2458 return 0; /* beep */
2459
2460 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002461 return 0;
2462
Guenter Roeck30846992013-06-24 22:21:59 -07002463 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002464 return 0;
2465
Guenter Roeck30846992013-06-24 22:21:59 -07002466 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002467 return 0;
2468
Guenter Roeck30846992013-06-24 22:21:59 -07002469 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002470 return 0;
2471
2472 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002473 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002474 return 0;
2475
2476 return attr->mode;
2477}
2478
2479SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2480SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2481SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2482 store_temp, 0, 1);
2483SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2484 show_temp, store_temp, 0, 2);
2485SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2486 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002487SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2488 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002489SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2490 show_temp_offset, store_temp_offset, 0);
2491SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2492 store_temp_type, 0);
2493SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002494SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2495 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002496
2497/*
2498 * nct6775_temp_is_visible uses the index into the following array
2499 * to determine if attributes should be created or not.
2500 * Any change in order or content must be matched.
2501 */
2502static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2503 &sensor_dev_template_temp_input,
2504 &sensor_dev_template_temp_label,
2505 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002506 &sensor_dev_template_temp_beep, /* 3 */
2507 &sensor_dev_template_temp_max, /* 4 */
2508 &sensor_dev_template_temp_max_hyst, /* 5 */
2509 &sensor_dev_template_temp_crit, /* 6 */
2510 &sensor_dev_template_temp_lcrit, /* 7 */
2511 &sensor_dev_template_temp_offset, /* 8 */
2512 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002513 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002514};
2515
Julia Lawallc60fdf82015-12-12 17:36:39 +01002516static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002517 .templates = nct6775_attributes_temp_template,
2518 .is_visible = nct6775_temp_is_visible,
2519 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002520};
2521
Guenter Roeckaa136e52012-12-04 03:26:05 -08002522static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002523show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2524{
2525 struct nct6775_data *data = nct6775_update_device(dev);
2526 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2527
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002528 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002529}
2530
2531static ssize_t
2532store_pwm_mode(struct device *dev, struct device_attribute *attr,
2533 const char *buf, size_t count)
2534{
2535 struct nct6775_data *data = dev_get_drvdata(dev);
2536 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2537 int nr = sattr->index;
2538 unsigned long val;
2539 int err;
2540 u8 reg;
2541
2542 err = kstrtoul(buf, 10, &val);
2543 if (err < 0)
2544 return err;
2545
2546 if (val > 1)
2547 return -EINVAL;
2548
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002549 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002550 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002551 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002552 return -EINVAL;
2553 return count;
2554 }
2555
2556 mutex_lock(&data->update_lock);
2557 data->pwm_mode[nr] = val;
2558 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2559 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002560 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002561 reg |= data->PWM_MODE_MASK[nr];
2562 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2563 mutex_unlock(&data->update_lock);
2564 return count;
2565}
2566
2567static ssize_t
2568show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2569{
2570 struct nct6775_data *data = nct6775_update_device(dev);
2571 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2572 int nr = sattr->nr;
2573 int index = sattr->index;
2574 int pwm;
2575
2576 /*
2577 * For automatic fan control modes, show current pwm readings.
2578 * Otherwise, show the configured value.
2579 */
2580 if (index == 0 && data->pwm_enable[nr] > manual)
2581 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2582 else
2583 pwm = data->pwm[index][nr];
2584
2585 return sprintf(buf, "%d\n", pwm);
2586}
2587
2588static ssize_t
2589store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2590 size_t count)
2591{
2592 struct nct6775_data *data = dev_get_drvdata(dev);
2593 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2594 int nr = sattr->nr;
2595 int index = sattr->index;
2596 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002597 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2598 int maxval[7]
2599 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002600 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002601 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002602
2603 err = kstrtoul(buf, 10, &val);
2604 if (err < 0)
2605 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002606 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002607
2608 mutex_lock(&data->update_lock);
2609 data->pwm[index][nr] = val;
2610 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002611 if (index == 2) { /* floor: disable if val == 0 */
2612 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2613 reg &= 0x7f;
2614 if (val)
2615 reg |= 0x80;
2616 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2617 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002618 mutex_unlock(&data->update_lock);
2619 return count;
2620}
2621
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002622/* Returns 0 if OK, -EINVAL otherwise */
2623static int check_trip_points(struct nct6775_data *data, int nr)
2624{
2625 int i;
2626
2627 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2628 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2629 return -EINVAL;
2630 }
2631 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2632 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2633 return -EINVAL;
2634 }
2635 /* validate critical temperature and pwm if enabled (pwm > 0) */
2636 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2637 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2638 data->auto_temp[nr][data->auto_pwm_num] ||
2639 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2640 data->auto_pwm[nr][data->auto_pwm_num])
2641 return -EINVAL;
2642 }
2643 return 0;
2644}
2645
2646static void pwm_update_registers(struct nct6775_data *data, int nr)
2647{
2648 u8 reg;
2649
2650 switch (data->pwm_enable[nr]) {
2651 case off:
2652 case manual:
2653 break;
2654 case speed_cruise:
2655 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2656 reg = (reg & ~data->tolerance_mask) |
2657 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2658 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2659 nct6775_write_value(data, data->REG_TARGET[nr],
2660 data->target_speed[nr] & 0xff);
2661 if (data->REG_TOLERANCE_H) {
2662 reg = (data->target_speed[nr] >> 8) & 0x0f;
2663 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2664 nct6775_write_value(data,
2665 data->REG_TOLERANCE_H[nr],
2666 reg);
2667 }
2668 break;
2669 case thermal_cruise:
2670 nct6775_write_value(data, data->REG_TARGET[nr],
2671 data->target_temp[nr]);
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05002672 fallthrough;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002673 default:
2674 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2675 reg = (reg & ~data->tolerance_mask) |
2676 data->temp_tolerance[0][nr];
2677 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2678 break;
2679 }
2680}
2681
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002682static ssize_t
2683show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2684{
2685 struct nct6775_data *data = nct6775_update_device(dev);
2686 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2687
2688 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2689}
2690
2691static ssize_t
2692store_pwm_enable(struct device *dev, struct device_attribute *attr,
2693 const char *buf, size_t count)
2694{
2695 struct nct6775_data *data = dev_get_drvdata(dev);
2696 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2697 int nr = sattr->index;
2698 unsigned long val;
2699 int err;
2700 u16 reg;
2701
2702 err = kstrtoul(buf, 10, &val);
2703 if (err < 0)
2704 return err;
2705
2706 if (val > sf4)
2707 return -EINVAL;
2708
2709 if (val == sf3 && data->kind != nct6775)
2710 return -EINVAL;
2711
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002712 if (val == sf4 && check_trip_points(data, nr)) {
2713 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2714 dev_err(dev, "Adjust trip points and try again\n");
2715 return -EINVAL;
2716 }
2717
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002718 mutex_lock(&data->update_lock);
2719 data->pwm_enable[nr] = val;
2720 if (val == off) {
2721 /*
2722 * turn off pwm control: select manual mode, set pwm to maximum
2723 */
2724 data->pwm[0][nr] = 255;
2725 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2726 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002727 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002728 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2729 reg &= 0x0f;
2730 reg |= pwm_enable_to_reg(val) << 4;
2731 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2732 mutex_unlock(&data->update_lock);
2733 return count;
2734}
2735
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002736static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002737show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002738{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002739 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002740
2741 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002742 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002743 continue;
2744 if (src == data->temp_src[i]) {
2745 sel = i + 1;
2746 break;
2747 }
2748 }
2749
2750 return sprintf(buf, "%d\n", sel);
2751}
2752
2753static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002754show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2755{
2756 struct nct6775_data *data = nct6775_update_device(dev);
2757 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2758 int index = sattr->index;
2759
2760 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2761}
2762
2763static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002764store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2765 const char *buf, size_t count)
2766{
2767 struct nct6775_data *data = nct6775_update_device(dev);
2768 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2769 int nr = sattr->index;
2770 unsigned long val;
2771 int err, reg, src;
2772
2773 err = kstrtoul(buf, 10, &val);
2774 if (err < 0)
2775 return err;
2776 if (val == 0 || val > NUM_TEMP)
2777 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002778 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002779 return -EINVAL;
2780
2781 mutex_lock(&data->update_lock);
2782 src = data->temp_src[val - 1];
2783 data->pwm_temp_sel[nr] = src;
2784 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2785 reg &= 0xe0;
2786 reg |= src;
2787 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2788 mutex_unlock(&data->update_lock);
2789
2790 return count;
2791}
2792
2793static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002794show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2795 char *buf)
2796{
2797 struct nct6775_data *data = nct6775_update_device(dev);
2798 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2799 int index = sattr->index;
2800
2801 return show_pwm_temp_sel_common(data, buf,
2802 data->pwm_weight_temp_sel[index]);
2803}
2804
2805static ssize_t
2806store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2807 const char *buf, size_t count)
2808{
2809 struct nct6775_data *data = nct6775_update_device(dev);
2810 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2811 int nr = sattr->index;
2812 unsigned long val;
2813 int err, reg, src;
2814
2815 err = kstrtoul(buf, 10, &val);
2816 if (err < 0)
2817 return err;
2818 if (val > NUM_TEMP)
2819 return -EINVAL;
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -05002820 val = array_index_nospec(val, NUM_TEMP + 1);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002821 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002822 !data->temp_src[val - 1]))
2823 return -EINVAL;
2824
2825 mutex_lock(&data->update_lock);
2826 if (val) {
2827 src = data->temp_src[val - 1];
2828 data->pwm_weight_temp_sel[nr] = src;
2829 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2830 reg &= 0xe0;
2831 reg |= (src | 0x80);
2832 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2833 } else {
2834 data->pwm_weight_temp_sel[nr] = 0;
2835 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2836 reg &= 0x7f;
2837 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2838 }
2839 mutex_unlock(&data->update_lock);
2840
2841 return count;
2842}
2843
2844static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002845show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2846{
2847 struct nct6775_data *data = nct6775_update_device(dev);
2848 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2849
2850 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2851}
2852
2853static ssize_t
2854store_target_temp(struct device *dev, struct device_attribute *attr,
2855 const char *buf, size_t count)
2856{
2857 struct nct6775_data *data = dev_get_drvdata(dev);
2858 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2859 int nr = sattr->index;
2860 unsigned long val;
2861 int err;
2862
2863 err = kstrtoul(buf, 10, &val);
2864 if (err < 0)
2865 return err;
2866
2867 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2868 data->target_temp_mask);
2869
2870 mutex_lock(&data->update_lock);
2871 data->target_temp[nr] = val;
2872 pwm_update_registers(data, nr);
2873 mutex_unlock(&data->update_lock);
2874 return count;
2875}
2876
2877static ssize_t
2878show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2879{
2880 struct nct6775_data *data = nct6775_update_device(dev);
2881 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2882 int nr = sattr->index;
2883
2884 return sprintf(buf, "%d\n",
2885 fan_from_reg16(data->target_speed[nr],
2886 data->fan_div[nr]));
2887}
2888
2889static ssize_t
2890store_target_speed(struct device *dev, struct device_attribute *attr,
2891 const char *buf, size_t count)
2892{
2893 struct nct6775_data *data = dev_get_drvdata(dev);
2894 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2895 int nr = sattr->index;
2896 unsigned long val;
2897 int err;
2898 u16 speed;
2899
2900 err = kstrtoul(buf, 10, &val);
2901 if (err < 0)
2902 return err;
2903
2904 val = clamp_val(val, 0, 1350000U);
2905 speed = fan_to_reg(val, data->fan_div[nr]);
2906
2907 mutex_lock(&data->update_lock);
2908 data->target_speed[nr] = speed;
2909 pwm_update_registers(data, nr);
2910 mutex_unlock(&data->update_lock);
2911 return count;
2912}
2913
2914static ssize_t
2915show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2916 char *buf)
2917{
2918 struct nct6775_data *data = nct6775_update_device(dev);
2919 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2920 int nr = sattr->nr;
2921 int index = sattr->index;
2922
2923 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2924}
2925
2926static ssize_t
2927store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2928 const char *buf, size_t count)
2929{
2930 struct nct6775_data *data = dev_get_drvdata(dev);
2931 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2932 int nr = sattr->nr;
2933 int index = sattr->index;
2934 unsigned long val;
2935 int err;
2936
2937 err = kstrtoul(buf, 10, &val);
2938 if (err < 0)
2939 return err;
2940
2941 /* Limit tolerance as needed */
2942 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2943
2944 mutex_lock(&data->update_lock);
2945 data->temp_tolerance[index][nr] = val;
2946 if (index)
2947 pwm_update_registers(data, nr);
2948 else
2949 nct6775_write_value(data,
2950 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2951 val);
2952 mutex_unlock(&data->update_lock);
2953 return count;
2954}
2955
2956/*
2957 * Fan speed tolerance is a tricky beast, since the associated register is
2958 * a tick counter, but the value is reported and configured as rpm.
2959 * Compute resulting low and high rpm values and report the difference.
Guenter Roeck61b6c662018-09-17 09:24:11 -07002960 * A fan speed tolerance only makes sense if a fan target speed has been
2961 * configured, so only display values other than 0 if that is the case.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002962 */
2963static ssize_t
2964show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2965 char *buf)
2966{
2967 struct nct6775_data *data = nct6775_update_device(dev);
2968 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2969 int nr = sattr->index;
Guenter Roeck61b6c662018-09-17 09:24:11 -07002970 int target = data->target_speed[nr];
2971 int tolerance = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002972
Guenter Roeck61b6c662018-09-17 09:24:11 -07002973 if (target) {
2974 int low = target - data->target_speed_tolerance[nr];
2975 int high = target + data->target_speed_tolerance[nr];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002976
Guenter Roeck61b6c662018-09-17 09:24:11 -07002977 if (low <= 0)
2978 low = 1;
2979 if (high > 0xffff)
2980 high = 0xffff;
2981 if (high < low)
2982 high = low;
2983
2984 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2985 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2986 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002987
2988 return sprintf(buf, "%d\n", tolerance);
2989}
2990
2991static ssize_t
2992store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2993 const char *buf, size_t count)
2994{
2995 struct nct6775_data *data = dev_get_drvdata(dev);
2996 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2997 int nr = sattr->index;
2998 unsigned long val;
2999 int err;
3000 int low, high;
3001
3002 err = kstrtoul(buf, 10, &val);
3003 if (err < 0)
3004 return err;
3005
3006 high = fan_from_reg16(data->target_speed[nr],
3007 data->fan_div[nr]) + val;
3008 low = fan_from_reg16(data->target_speed[nr],
3009 data->fan_div[nr]) - val;
3010 if (low <= 0)
3011 low = 1;
3012 if (high < low)
3013 high = low;
3014
3015 val = (fan_to_reg(low, data->fan_div[nr]) -
3016 fan_to_reg(high, data->fan_div[nr])) / 2;
3017
3018 /* Limit tolerance as needed */
3019 val = clamp_val(val, 0, data->speed_tolerance_limit);
3020
3021 mutex_lock(&data->update_lock);
3022 data->target_speed_tolerance[nr] = val;
3023 pwm_update_registers(data, nr);
3024 mutex_unlock(&data->update_lock);
3025 return count;
3026}
3027
Guenter Roeckf73cf632013-03-18 09:22:50 -07003028SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
3029SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
3030 store_pwm_mode, 0);
3031SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
3032 store_pwm_enable, 0);
3033SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
3034 show_pwm_temp_sel, store_pwm_temp_sel, 0);
3035SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
3036 show_target_temp, store_target_temp, 0);
3037SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
3038 show_target_speed, store_target_speed, 0);
3039SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
3040 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003041
3042/* Smart Fan registers */
3043
3044static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003045show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
3046{
3047 struct nct6775_data *data = nct6775_update_device(dev);
3048 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3049 int nr = sattr->nr;
3050 int index = sattr->index;
3051
3052 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
3053}
3054
3055static ssize_t
3056store_weight_temp(struct device *dev, struct device_attribute *attr,
3057 const char *buf, size_t count)
3058{
3059 struct nct6775_data *data = dev_get_drvdata(dev);
3060 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3061 int nr = sattr->nr;
3062 int index = sattr->index;
3063 unsigned long val;
3064 int err;
3065
3066 err = kstrtoul(buf, 10, &val);
3067 if (err < 0)
3068 return err;
3069
3070 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
3071
3072 mutex_lock(&data->update_lock);
3073 data->weight_temp[index][nr] = val;
3074 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
3075 mutex_unlock(&data->update_lock);
3076 return count;
3077}
3078
Guenter Roeckf73cf632013-03-18 09:22:50 -07003079SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
3080 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
3081SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
3082 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
3083SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
3084 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
3085SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
3086 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
3087SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
3088 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
3089SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
3090 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003091
3092static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003093show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
3094{
3095 struct nct6775_data *data = nct6775_update_device(dev);
3096 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3097 int nr = sattr->nr;
3098 int index = sattr->index;
3099
3100 return sprintf(buf, "%d\n",
3101 step_time_from_reg(data->fan_time[index][nr],
3102 data->pwm_mode[nr]));
3103}
3104
3105static ssize_t
3106store_fan_time(struct device *dev, struct device_attribute *attr,
3107 const char *buf, size_t count)
3108{
3109 struct nct6775_data *data = dev_get_drvdata(dev);
3110 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3111 int nr = sattr->nr;
3112 int index = sattr->index;
3113 unsigned long val;
3114 int err;
3115
3116 err = kstrtoul(buf, 10, &val);
3117 if (err < 0)
3118 return err;
3119
3120 val = step_time_to_reg(val, data->pwm_mode[nr]);
3121 mutex_lock(&data->update_lock);
3122 data->fan_time[index][nr] = val;
3123 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
3124 mutex_unlock(&data->update_lock);
3125 return count;
3126}
3127
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003128static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003129show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3130{
3131 struct nct6775_data *data = nct6775_update_device(dev);
3132 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3133
3134 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3135}
3136
3137static ssize_t
3138store_auto_pwm(struct device *dev, struct device_attribute *attr,
3139 const char *buf, size_t count)
3140{
3141 struct nct6775_data *data = dev_get_drvdata(dev);
3142 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3143 int nr = sattr->nr;
3144 int point = sattr->index;
3145 unsigned long val;
3146 int err;
3147 u8 reg;
3148
3149 err = kstrtoul(buf, 10, &val);
3150 if (err < 0)
3151 return err;
3152 if (val > 255)
3153 return -EINVAL;
3154
3155 if (point == data->auto_pwm_num) {
3156 if (data->kind != nct6775 && !val)
3157 return -EINVAL;
3158 if (data->kind != nct6779 && val)
3159 val = 0xff;
3160 }
3161
3162 mutex_lock(&data->update_lock);
3163 data->auto_pwm[nr][point] = val;
3164 if (point < data->auto_pwm_num) {
3165 nct6775_write_value(data,
3166 NCT6775_AUTO_PWM(data, nr, point),
3167 data->auto_pwm[nr][point]);
3168 } else {
3169 switch (data->kind) {
3170 case nct6775:
3171 /* disable if needed (pwm == 0) */
3172 reg = nct6775_read_value(data,
3173 NCT6775_REG_CRITICAL_ENAB[nr]);
3174 if (val)
3175 reg |= 0x02;
3176 else
3177 reg &= ~0x02;
3178 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3179 reg);
3180 break;
3181 case nct6776:
3182 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003183 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003184 case nct6116:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003185 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003186 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003187 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003188 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003189 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003190 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07003191 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07003192 case nct6798:
Guenter Roeck6c009502012-07-01 08:23:15 -07003193 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003194 val);
3195 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003196 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003197 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003198 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003199 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003200 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003201 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003202 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003203 reg);
3204 break;
3205 }
3206 }
3207 mutex_unlock(&data->update_lock);
3208 return count;
3209}
3210
3211static ssize_t
3212show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3213{
3214 struct nct6775_data *data = nct6775_update_device(dev);
3215 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3216 int nr = sattr->nr;
3217 int point = sattr->index;
3218
3219 /*
3220 * We don't know for sure if the temperature is signed or unsigned.
3221 * Assume it is unsigned.
3222 */
3223 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3224}
3225
3226static ssize_t
3227store_auto_temp(struct device *dev, struct device_attribute *attr,
3228 const char *buf, size_t count)
3229{
3230 struct nct6775_data *data = dev_get_drvdata(dev);
3231 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3232 int nr = sattr->nr;
3233 int point = sattr->index;
3234 unsigned long val;
3235 int err;
3236
3237 err = kstrtoul(buf, 10, &val);
3238 if (err)
3239 return err;
3240 if (val > 255000)
3241 return -EINVAL;
3242
3243 mutex_lock(&data->update_lock);
3244 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3245 if (point < data->auto_pwm_num) {
3246 nct6775_write_value(data,
3247 NCT6775_AUTO_TEMP(data, nr, point),
3248 data->auto_temp[nr][point]);
3249 } else {
3250 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3251 data->auto_temp[nr][point]);
3252 }
3253 mutex_unlock(&data->update_lock);
3254 return count;
3255}
3256
Guenter Roeckf73cf632013-03-18 09:22:50 -07003257static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3258 struct attribute *attr, int index)
3259{
zhouchuangao036855a2020-05-11 11:43:06 +08003260 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003261 struct nct6775_data *data = dev_get_drvdata(dev);
3262 int pwm = index / 36; /* pwm index */
3263 int nr = index % 36; /* attribute index */
3264
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003265 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003266 return 0;
3267
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003268 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3269 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3270 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003271 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3272 return 0;
3273 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3274 return 0;
3275 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3276 return 0;
3277
3278 if (nr >= 22 && nr <= 35) { /* auto point */
3279 int api = (nr - 22) / 2; /* auto point index */
3280
3281 if (api > data->auto_pwm_num)
3282 return 0;
3283 }
3284 return attr->mode;
3285}
3286
3287SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3288 show_fan_time, store_fan_time, 0, 0);
3289SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3290 show_fan_time, store_fan_time, 0, 1);
3291SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3292 show_fan_time, store_fan_time, 0, 2);
3293SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3294 store_pwm, 0, 1);
3295SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3296 store_pwm, 0, 2);
3297SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3298 show_temp_tolerance, store_temp_tolerance, 0, 0);
3299SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3300 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3301 0, 1);
3302
3303SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3304 0, 3);
3305
3306SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3307 store_pwm, 0, 4);
3308
3309SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3310 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3311SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3312 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3313
3314SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3315 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3316SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3317 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3318
3319SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3320 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3321SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3322 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3323
3324SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3325 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3326SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3327 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3328
3329SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3330 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3331SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3332 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3333
3334SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3335 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3336SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3337 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3338
3339SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3340 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3341SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3342 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3343
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003344/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003345 * nct6775_pwm_is_visible uses the index into the following array
3346 * to determine if attributes should be created or not.
3347 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003348 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003349static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3350 &sensor_dev_template_pwm,
3351 &sensor_dev_template_pwm_mode,
3352 &sensor_dev_template_pwm_enable,
3353 &sensor_dev_template_pwm_temp_sel,
3354 &sensor_dev_template_pwm_temp_tolerance,
3355 &sensor_dev_template_pwm_crit_temp_tolerance,
3356 &sensor_dev_template_pwm_target_temp,
3357 &sensor_dev_template_fan_target,
3358 &sensor_dev_template_fan_tolerance,
3359 &sensor_dev_template_pwm_stop_time,
3360 &sensor_dev_template_pwm_step_up_time,
3361 &sensor_dev_template_pwm_step_down_time,
3362 &sensor_dev_template_pwm_start,
3363 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003364 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003365 &sensor_dev_template_pwm_weight_temp_step,
3366 &sensor_dev_template_pwm_weight_temp_step_tol,
3367 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003368 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003369 &sensor_dev_template_pwm_max, /* 19 */
3370 &sensor_dev_template_pwm_step, /* 20 */
3371 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3372 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3373 &sensor_dev_template_pwm_auto_point1_temp,
3374 &sensor_dev_template_pwm_auto_point2_pwm,
3375 &sensor_dev_template_pwm_auto_point2_temp,
3376 &sensor_dev_template_pwm_auto_point3_pwm,
3377 &sensor_dev_template_pwm_auto_point3_temp,
3378 &sensor_dev_template_pwm_auto_point4_pwm,
3379 &sensor_dev_template_pwm_auto_point4_temp,
3380 &sensor_dev_template_pwm_auto_point5_pwm,
3381 &sensor_dev_template_pwm_auto_point5_temp,
3382 &sensor_dev_template_pwm_auto_point6_pwm,
3383 &sensor_dev_template_pwm_auto_point6_temp,
3384 &sensor_dev_template_pwm_auto_point7_pwm,
3385 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003386
Guenter Roeckf73cf632013-03-18 09:22:50 -07003387 NULL
3388};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003389
Julia Lawallc60fdf82015-12-12 17:36:39 +01003390static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003391 .templates = nct6775_attributes_pwm_template,
3392 .is_visible = nct6775_pwm_is_visible,
3393 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003394};
3395
3396static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003397cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003398{
3399 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003400
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003401 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3402}
3403
Julia Lawall93d72ac2016-12-22 13:05:23 +01003404static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003405
Guenter Roecka6bd5872012-12-04 03:13:34 -08003406/* Case open detection */
3407
3408static ssize_t
3409clear_caseopen(struct device *dev, struct device_attribute *attr,
3410 const char *buf, size_t count)
3411{
3412 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003413 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3414 unsigned long val;
3415 u8 reg;
3416 int ret;
3417
3418 if (kstrtoul(buf, 10, &val) || val != 0)
3419 return -EINVAL;
3420
3421 mutex_lock(&data->update_lock);
3422
3423 /*
3424 * Use CR registers to clear caseopen status.
3425 * The CR registers are the same for all chips, and not all chips
3426 * support clearing the caseopen status through "regular" registers.
3427 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003428 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003429 if (ret) {
3430 count = ret;
3431 goto error;
3432 }
3433
Guenter Roeckdf612d52013-07-08 13:15:04 -07003434 superio_select(data->sioreg, NCT6775_LD_ACPI);
3435 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003436 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003437 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003438 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003439 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3440 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003441
3442 data->valid = false; /* Force cache refresh */
3443error:
3444 mutex_unlock(&data->update_lock);
3445 return count;
3446}
3447
Guenter Roeckf73cf632013-03-18 09:22:50 -07003448static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3449 clear_caseopen, INTRUSION_ALARM_BASE);
3450static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3451 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003452static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3453 store_beep, INTRUSION_ALARM_BASE);
3454static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3455 store_beep, INTRUSION_ALARM_BASE + 1);
3456static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3457 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003458
3459static umode_t nct6775_other_is_visible(struct kobject *kobj,
3460 struct attribute *attr, int index)
3461{
zhouchuangao036855a2020-05-11 11:43:06 +08003462 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003463 struct nct6775_data *data = dev_get_drvdata(dev);
3464
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003465 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003466 return 0;
3467
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003468 if (index == 1 || index == 2) {
3469 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003470 return 0;
3471 }
3472
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003473 if (index == 3 || index == 4) {
3474 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003475 return 0;
3476 }
3477
Guenter Roeckf73cf632013-03-18 09:22:50 -07003478 return attr->mode;
3479}
3480
3481/*
3482 * nct6775_other_is_visible uses the index into the following array
3483 * to determine if attributes should be created or not.
3484 * Any change in order or content must be matched.
3485 */
3486static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003487 &dev_attr_cpu0_vid.attr, /* 0 */
3488 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3489 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3490 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3491 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3492 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003493
3494 NULL
3495};
3496
3497static const struct attribute_group nct6775_group_other = {
3498 .attrs = nct6775_attributes_other,
3499 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003500};
3501
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003502static inline void nct6775_init_device(struct nct6775_data *data)
3503{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003504 int i;
3505 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003506
3507 /* Start monitoring if needed */
3508 if (data->REG_CONFIG) {
3509 tmp = nct6775_read_value(data, data->REG_CONFIG);
3510 if (!(tmp & 0x01))
3511 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3512 }
3513
Guenter Roeckaa136e52012-12-04 03:26:05 -08003514 /* Enable temperature sensors if needed */
3515 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003516 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003517 continue;
3518 if (!data->reg_temp_config[i])
3519 continue;
3520 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3521 if (tmp & 0x01)
3522 nct6775_write_value(data, data->reg_temp_config[i],
3523 tmp & 0xfe);
3524 }
3525
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003526 /* Enable VBAT monitoring if needed */
3527 tmp = nct6775_read_value(data, data->REG_VBAT);
3528 if (!(tmp & 0x01))
3529 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003530
3531 diode = nct6775_read_value(data, data->REG_DIODE);
3532
3533 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003534 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003535 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003536 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3537 data->temp_type[i]
3538 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003539 else /* thermistor */
3540 data->temp_type[i] = 4;
3541 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003542}
3543
Guenter Roeckf73cf632013-03-18 09:22:50 -07003544static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003545nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003546{
Guenter Roeck1b206242018-02-21 13:09:38 -08003547 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003548 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003549 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003550 bool pwm6pin = false, pwm7pin = false;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003551 int sioreg = data->sioreg;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003552
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003553 /* Store SIO_REG_ENABLE for use during resume */
3554 superio_select(sioreg, NCT6775_LD_HWM);
3555 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3556
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003557 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3558 if (data->kind == nct6775) {
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003559 int cr2c = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003560
Guenter Roecka6c54f22018-09-18 09:34:06 -07003561 fan3pin = cr2c & BIT(6);
3562 pwm3pin = cr2c & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003563
3564 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003565 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003566 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003567 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003568 const char *board_vendor, *board_name;
3569
3570 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3571 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3572
3573 if (board_name && board_vendor &&
3574 !strcmp(board_vendor, "ASRock")) {
3575 /*
3576 * Auxiliary fan monitoring is not enabled on ASRock
3577 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3578 * Observed with BIOS version 2.00.
3579 */
3580 if (!strcmp(board_name, "Z77 Pro4-M")) {
3581 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3582 data->sio_reg_enable |= 0xe0;
3583 superio_outb(sioreg, SIO_REG_ENABLE,
3584 data->sio_reg_enable);
3585 }
3586 }
3587 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003588
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003589 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003590 fan3pin = gpok;
3591 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003592 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003593
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003594 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003595 fan4pin = gpok;
3596 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003597 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003598
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003599 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003600 fan5pin = gpok;
3601 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003602 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003603
3604 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003605 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003606 } else if (data->kind == nct6106) {
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003607 int cr24 = superio_inb(sioreg, 0x24);
3608
Guenter Roecka6c54f22018-09-18 09:34:06 -07003609 fan3pin = !(cr24 & 0x80);
3610 pwm3pin = cr24 & 0x08;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003611 } else if (data->kind == nct6116) {
3612 int cr1a = superio_inb(sioreg, 0x1a);
3613 int cr1b = superio_inb(sioreg, 0x1b);
3614 int cr24 = superio_inb(sioreg, 0x24);
3615 int cr2a = superio_inb(sioreg, 0x2a);
3616 int cr2b = superio_inb(sioreg, 0x2b);
3617 int cr2f = superio_inb(sioreg, 0x2f);
3618
3619 fan3pin = !(cr2b & 0x10);
3620 fan4pin = (cr2b & 0x80) || // pin 1(2)
3621 (!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66)
3622 fan5pin = (cr2b & 0x80) || // pin 126(127)
3623 (!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96)
3624
3625 pwm3pin = fan3pin && (cr24 & 0x08);
3626 pwm4pin = fan4pin;
3627 pwm5pin = fan5pin;
Guenter Roeck81820052018-02-21 13:09:39 -08003628 } else {
Guenter Roecke41da282018-09-18 20:48:29 -07003629 /*
3630 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
Guenter Roeck05996822018-09-19 20:26:16 -07003631 * NCT6797D, NCT6798D
Guenter Roecke41da282018-09-18 20:48:29 -07003632 */
3633 int cr1a = superio_inb(sioreg, 0x1a);
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003634 int cr1b = superio_inb(sioreg, 0x1b);
3635 int cr1c = superio_inb(sioreg, 0x1c);
3636 int cr1d = superio_inb(sioreg, 0x1d);
3637 int cr2a = superio_inb(sioreg, 0x2a);
3638 int cr2b = superio_inb(sioreg, 0x2b);
3639 int cr2d = superio_inb(sioreg, 0x2d);
3640 int cr2f = superio_inb(sioreg, 0x2f);
3641 bool dsw_en = cr2f & BIT(3);
Guenter Roecke41da282018-09-18 20:48:29 -07003642 bool ddr4_en = cr2f & BIT(4);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003643 int cre0;
Guenter Roeck2d888c52018-09-18 09:49:29 -07003644 int creb;
3645 int cred;
3646
3647 superio_select(sioreg, NCT6775_LD_12);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003648 cre0 = superio_inb(sioreg, 0xe0);
Guenter Roeck2d888c52018-09-18 09:49:29 -07003649 creb = superio_inb(sioreg, 0xeb);
3650 cred = superio_inb(sioreg, 0xed);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003651
Guenter Roecka6c54f22018-09-18 09:34:06 -07003652 fan3pin = !(cr1c & BIT(5));
3653 fan4pin = !(cr1c & BIT(6));
3654 fan5pin = !(cr1c & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003655
Guenter Roecka6c54f22018-09-18 09:34:06 -07003656 pwm3pin = !(cr1c & BIT(0));
3657 pwm4pin = !(cr1c & BIT(1));
3658 pwm5pin = !(cr1c & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003659
Guenter Roecke5c85222017-05-17 18:09:41 -07003660 switch (data->kind) {
3661 case nct6791:
Guenter Roecka6c54f22018-09-18 09:34:06 -07003662 fan6pin = cr2d & BIT(1);
3663 pwm6pin = cr2d & BIT(0);
Guenter Roecke5c85222017-05-17 18:09:41 -07003664 break;
Guenter Roeck7dcdbde2018-09-18 10:52:55 -07003665 case nct6792:
3666 fan6pin = !dsw_en && (cr2d & BIT(1));
3667 pwm6pin = !dsw_en && (cr2d & BIT(0));
3668 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003669 case nct6793:
Guenter Roeck2d999252018-09-18 11:03:25 -07003670 fan5pin |= cr1b & BIT(5);
3671 fan5pin |= creb & BIT(5);
3672
Guenter Roeck2a2ec4a2019-01-27 16:08:00 -08003673 fan6pin = !dsw_en && (cr2d & BIT(1));
3674 fan6pin |= creb & BIT(3);
Guenter Roeck2d999252018-09-18 11:03:25 -07003675
3676 pwm5pin |= cr2d & BIT(7);
3677 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3678
3679 pwm6pin = !dsw_en && (cr2d & BIT(0));
3680 pwm6pin |= creb & BIT(2);
3681 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003682 case nct6795:
Guenter Roeckb75a8062018-09-18 11:18:30 -07003683 fan5pin |= cr1b & BIT(5);
3684 fan5pin |= creb & BIT(5);
3685
3686 fan6pin = (cr2a & BIT(4)) &&
3687 (!dsw_en || (cred & BIT(4)));
3688 fan6pin |= creb & BIT(3);
3689
3690 pwm5pin |= cr2d & BIT(7);
3691 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3692
3693 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3694 pwm6pin |= creb & BIT(2);
3695 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003696 case nct6796:
Guenter Roecka4e0a082018-09-18 09:53:06 -07003697 fan5pin |= cr1b & BIT(5);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003698 fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
3699 fan5pin |= creb & BIT(5);
Guenter Roecke5c85222017-05-17 18:09:41 -07003700
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003701 fan6pin = (cr2a & BIT(4)) &&
Guenter Roeck2d999252018-09-18 11:03:25 -07003702 (!dsw_en || (cred & BIT(4)));
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003703 fan6pin |= creb & BIT(3);
Guenter Roeck81820052018-02-21 13:09:39 -08003704
Guenter Roeckb75a8062018-09-18 11:18:30 -07003705 fan7pin = !(cr2b & BIT(2));
Guenter Roeck81820052018-02-21 13:09:39 -08003706
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003707 pwm5pin |= cr2d & BIT(7);
3708 pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
3709 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3710
3711 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3712 pwm6pin |= creb & BIT(2);
3713
3714 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
Guenter Roecke5c85222017-05-17 18:09:41 -07003715 break;
Guenter Roecke41da282018-09-18 20:48:29 -07003716 case nct6797:
3717 fan5pin |= !ddr4_en && (cr1b & BIT(5));
3718 fan5pin |= creb & BIT(5);
3719
3720 fan6pin = cr2a & BIT(4);
3721 fan6pin |= creb & BIT(3);
3722
3723 fan7pin = cr1a & BIT(1);
3724
3725 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3726 pwm5pin |= !ddr4_en && (cr2d & BIT(7));
3727
3728 pwm6pin = creb & BIT(2);
3729 pwm6pin |= cred & BIT(2);
3730
3731 pwm7pin = cr1d & BIT(4);
3732 break;
Guenter Roeck05996822018-09-19 20:26:16 -07003733 case nct6798:
3734 fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
3735 fan6pin |= cr2a & BIT(4);
3736 fan6pin |= creb & BIT(5);
3737
3738 fan7pin = cr1b & BIT(5);
3739 fan7pin |= !(cr2b & BIT(2));
3740 fan7pin |= creb & BIT(3);
3741
3742 pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
3743 pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3));
3744 pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3745
3746 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
3747 pwm7pin |= cr2d & BIT(7);
3748 pwm7pin |= creb & BIT(2);
3749 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003750 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003751 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003752 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003753
3754 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003755 }
3756
David Bartley578ab5f2013-06-24 22:28:28 -07003757 /* fan 1 and 2 (0x03) are always present */
3758 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003759 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003760 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003761 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003762 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003763 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003764}
3765
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003766static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3767 int *available, int *mask)
3768{
3769 int i;
3770 u8 src;
3771
3772 for (i = 0; i < data->pwm_num && *available; i++) {
3773 int index;
3774
3775 if (!regp[i])
3776 continue;
3777 src = nct6775_read_value(data, regp[i]);
3778 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003779 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003780 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003781 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003782 continue;
3783
3784 index = __ffs(*available);
3785 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003786 *available &= ~BIT(index);
3787 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003788 }
3789}
3790
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003791static int nct6775_probe(struct platform_device *pdev)
3792{
3793 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003794 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003795 struct nct6775_data *data;
3796 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003797 int i, s, err = 0;
3798 int src, mask, available;
3799 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003800 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003801 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003802 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003803 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003804 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003805 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003806 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003807
3808 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3809 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3810 DRVNAME))
3811 return -EBUSY;
3812
3813 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3814 GFP_KERNEL);
3815 if (!data)
3816 return -ENOMEM;
3817
3818 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003819 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003820 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003821 mutex_init(&data->update_lock);
3822 data->name = nct6775_device_names[data->kind];
3823 data->bank = 0xff; /* Force initial bank selection */
3824 platform_set_drvdata(pdev, data);
3825
3826 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003827 case nct6106:
3828 data->in_num = 9;
3829 data->pwm_num = 3;
3830 data->auto_pwm_num = 4;
3831 data->temp_fixed_num = 3;
3832 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003833 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003834
3835 data->fan_from_reg = fan_from_reg13;
3836 data->fan_from_reg_min = fan_from_reg13;
3837
3838 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003839 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003840 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003841
3842 data->REG_VBAT = NCT6106_REG_VBAT;
3843 data->REG_DIODE = NCT6106_REG_DIODE;
3844 data->DIODE_MASK = NCT6106_DIODE_MASK;
3845 data->REG_VIN = NCT6106_REG_IN;
3846 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3847 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3848 data->REG_TARGET = NCT6106_REG_TARGET;
3849 data->REG_FAN = NCT6106_REG_FAN;
3850 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3851 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3852 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3853 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3854 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3855 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3856 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
Björn Gerhartf3d43e22019-07-15 18:33:55 +02003857 data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003858 data->REG_PWM[0] = NCT6116_REG_PWM;
Guenter Roeck6c009502012-07-01 08:23:15 -07003859 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3860 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3861 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3862 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3863 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3864 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3865 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3866 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3867 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3868 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3869 data->REG_CRITICAL_TEMP_TOLERANCE
3870 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3871 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3872 data->CRITICAL_PWM_ENABLE_MASK
3873 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3874 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3875 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3876 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003877 data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
Guenter Roeck6c009502012-07-01 08:23:15 -07003878 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3879 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3880 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3881 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3882 data->REG_ALARM = NCT6106_REG_ALARM;
3883 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003884 data->REG_BEEP = NCT6106_REG_BEEP;
3885 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003886
3887 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003888 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003889 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003890 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003891 reg_temp_over = NCT6106_REG_TEMP_OVER;
3892 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3893 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3894 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3895 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003896 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3897 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003898
3899 break;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003900 case nct6116:
3901 data->in_num = 9;
3902 data->pwm_num = 3;
3903 data->auto_pwm_num = 4;
3904 data->temp_fixed_num = 3;
3905 data->num_temp_alarms = 3;
3906 data->num_temp_beeps = 3;
3907
3908 data->fan_from_reg = fan_from_reg13;
3909 data->fan_from_reg_min = fan_from_reg13;
3910
3911 data->temp_label = nct6776_temp_label;
3912 data->temp_mask = NCT6776_TEMP_MASK;
3913 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
3914
3915 data->REG_VBAT = NCT6106_REG_VBAT;
3916 data->REG_DIODE = NCT6106_REG_DIODE;
3917 data->DIODE_MASK = NCT6106_DIODE_MASK;
3918 data->REG_VIN = NCT6106_REG_IN;
3919 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3920 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3921 data->REG_TARGET = NCT6116_REG_TARGET;
3922 data->REG_FAN = NCT6116_REG_FAN;
3923 data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
3924 data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
3925 data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
3926 data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
3927 data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
3928 data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
3929 data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
3930 data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
3931 data->REG_PWM[0] = NCT6116_REG_PWM;
3932 data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
3933 data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
3934 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3935 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3936 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3937 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3938 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3939 data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
3940 data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
3941 data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
3942 data->REG_CRITICAL_TEMP_TOLERANCE
3943 = NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
3944 data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
3945 data->CRITICAL_PWM_ENABLE_MASK
3946 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3947 data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
3948 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3949 data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
3950 data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
3951 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3952 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3953 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3954 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3955 data->REG_ALARM = NCT6106_REG_ALARM;
3956 data->ALARM_BITS = NCT6116_ALARM_BITS;
3957 data->REG_BEEP = NCT6106_REG_BEEP;
3958 data->BEEP_BITS = NCT6116_BEEP_BITS;
3959
3960 reg_temp = NCT6106_REG_TEMP;
3961 reg_temp_mon = NCT6106_REG_TEMP_MON;
3962 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
3963 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
3964 reg_temp_over = NCT6106_REG_TEMP_OVER;
3965 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3966 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3967 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3968 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
3969 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3970 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
3971
3972 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003973 case nct6775:
3974 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003975 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003976 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003977 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003978 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003979 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003980 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003981
3982 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003983 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003984
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003985 data->fan_from_reg = fan_from_reg16;
3986 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003987 data->target_temp_mask = 0x7f;
3988 data->tolerance_mask = 0x0f;
3989 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003990
Guenter Roeckaa136e52012-12-04 03:26:05 -08003991 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003992 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07003993 data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003994
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003995 data->REG_CONFIG = NCT6775_REG_CONFIG;
3996 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003997 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003998 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003999 data->REG_VIN = NCT6775_REG_IN;
4000 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4001 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004002 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004003 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004004 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004005 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004006 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004007 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004008 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
4009 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
4010 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004011 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004012 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4013 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
4014 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
4015 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004016 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004017 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4018 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
4019 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004020 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4021 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4022 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4023 data->REG_CRITICAL_TEMP_TOLERANCE
4024 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004025 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
4026 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004027 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004028 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4029 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4030 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4031 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004032 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004033 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004034
4035 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004036 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004037 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004038 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004039 reg_temp_over = NCT6775_REG_TEMP_OVER;
4040 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
4041 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
4042 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
4043 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
4044
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004045 break;
4046 case nct6776:
4047 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004048 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004049 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004050 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004051 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004052 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07004053 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004054
4055 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004056 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004057
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004058 data->fan_from_reg = fan_from_reg13;
4059 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004060 data->target_temp_mask = 0xff;
4061 data->tolerance_mask = 0x07;
4062 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004063
Guenter Roeckaa136e52012-12-04 03:26:05 -08004064 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004065 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004066 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004067
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004068 data->REG_CONFIG = NCT6775_REG_CONFIG;
4069 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004070 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004071 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004072 data->REG_VIN = NCT6775_REG_IN;
4073 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4074 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004075 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004076 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004077 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004078 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004079 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004080 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004081 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004082 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4083 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004084 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004085 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004086 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4087 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004088 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4089 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004090 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4091 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4092 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004093 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4094 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4095 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4096 data->REG_CRITICAL_TEMP_TOLERANCE
4097 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004098 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
4099 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004100 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004101 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4102 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4103 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4104 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004105 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004106 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004107
4108 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004109 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004110 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004111 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004112 reg_temp_over = NCT6775_REG_TEMP_OVER;
4113 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
4114 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
4115 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
4116 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
4117
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004118 break;
4119 case nct6779:
4120 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004121 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004122 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004123 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004124 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004125 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07004126 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004127
4128 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004129 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004130
Guenter Roeckf6de2982018-09-13 20:01:12 -07004131 data->fan_from_reg = fan_from_reg_rpm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004132 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004133 data->target_temp_mask = 0xff;
4134 data->tolerance_mask = 0x07;
4135 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004136
Guenter Roeckaa136e52012-12-04 03:26:05 -08004137 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004138 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004139 data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004140
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004141 data->REG_CONFIG = NCT6775_REG_CONFIG;
4142 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004143 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004144 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004145 data->REG_VIN = NCT6779_REG_IN;
4146 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4147 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004148 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004149 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004150 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004151 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004152 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004153 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004154 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004155 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4156 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004157 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004158 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004159 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4160 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004161 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4162 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004163 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4164 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4165 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004166 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4167 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4168 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4169 data->REG_CRITICAL_TEMP_TOLERANCE
4170 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004171 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4172 data->CRITICAL_PWM_ENABLE_MASK
4173 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4174 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004175 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4176 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004177 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004178 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4179 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4180 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4181 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004182 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004183 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004184
4185 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004186 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004187 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004188 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004189 reg_temp_over = NCT6779_REG_TEMP_OVER;
4190 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4191 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4192 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4193 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4194
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004195 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004196 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004197 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004198 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004199 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004200 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004201 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004202 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004203 data->in_num = 15;
Guenter Roecke41da282018-09-18 20:48:29 -07004204 data->pwm_num = (data->kind == nct6796 ||
Guenter Roeck05996822018-09-19 20:26:16 -07004205 data->kind == nct6797 ||
4206 data->kind == nct6798) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07004207 data->auto_pwm_num = 4;
4208 data->has_fan_div = false;
4209 data->temp_fixed_num = 6;
4210 data->num_temp_alarms = 2;
4211 data->num_temp_beeps = 2;
4212
4213 data->ALARM_BITS = NCT6791_ALARM_BITS;
4214 data->BEEP_BITS = NCT6779_BEEP_BITS;
4215
Guenter Roeckf6de2982018-09-13 20:01:12 -07004216 data->fan_from_reg = fan_from_reg_rpm;
David Bartley578ab5f2013-06-24 22:28:28 -07004217 data->fan_from_reg_min = fan_from_reg13;
4218 data->target_temp_mask = 0xff;
4219 data->tolerance_mask = 0x07;
4220 data->speed_tolerance_limit = 63;
4221
Guenter Roeck50224f42015-10-30 07:52:39 -07004222 switch (data->kind) {
4223 default:
4224 case nct6791:
4225 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004226 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004227 data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004228 break;
4229 case nct6792:
4230 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004231 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004232 data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004233 break;
4234 case nct6793:
4235 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004236 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004237 data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004238 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004239 case nct6795:
Guenter Roecke41da282018-09-18 20:48:29 -07004240 case nct6797:
Guenter Roeck419220d2017-05-17 18:19:18 -07004241 data->temp_label = nct6795_temp_label;
4242 data->temp_mask = NCT6795_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004243 data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
Guenter Roeck419220d2017-05-17 18:19:18 -07004244 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004245 case nct6796:
4246 data->temp_label = nct6796_temp_label;
4247 data->temp_mask = NCT6796_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004248 data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
Guenter Roeck81820052018-02-21 13:09:39 -08004249 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004250 case nct6798:
4251 data->temp_label = nct6798_temp_label;
4252 data->temp_mask = NCT6798_TEMP_MASK;
4253 data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
4254 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07004255 }
David Bartley578ab5f2013-06-24 22:28:28 -07004256
4257 data->REG_CONFIG = NCT6775_REG_CONFIG;
4258 data->REG_VBAT = NCT6775_REG_VBAT;
4259 data->REG_DIODE = NCT6775_REG_DIODE;
4260 data->DIODE_MASK = NCT6775_DIODE_MASK;
4261 data->REG_VIN = NCT6779_REG_IN;
4262 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4263 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
4264 data->REG_TARGET = NCT6775_REG_TARGET;
4265 data->REG_FAN = NCT6779_REG_FAN;
4266 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
4267 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
4268 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
4269 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
4270 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004271 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4272 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07004273 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
4274 data->REG_PWM[0] = NCT6775_REG_PWM;
4275 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4276 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004277 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
4278 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004279 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4280 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4281 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
4282 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4283 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4284 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4285 data->REG_CRITICAL_TEMP_TOLERANCE
4286 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
4287 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4288 data->CRITICAL_PWM_ENABLE_MASK
4289 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4290 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
4291 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4292 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4293 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004294 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4295 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4296 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4297 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004298 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004299 if (data->kind == nct6791)
4300 data->REG_BEEP = NCT6776_REG_BEEP;
4301 else
4302 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004303
4304 reg_temp = NCT6779_REG_TEMP;
4305 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004306 if (data->kind == nct6791) {
4307 reg_temp_mon = NCT6779_REG_TEMP_MON;
4308 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4309 } else {
4310 reg_temp_mon = NCT6792_REG_TEMP_MON;
4311 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4312 }
David Bartley578ab5f2013-06-24 22:28:28 -07004313 reg_temp_over = NCT6779_REG_TEMP_OVER;
4314 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4315 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4316 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4317 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4318
4319 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004320 default:
4321 return -ENODEV;
4322 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004323 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004324 data->have_temp = 0;
4325
4326 /*
4327 * On some boards, not all available temperature sources are monitored,
4328 * even though some of the monitoring registers are unused.
4329 * Get list of unused monitoring registers, then detect if any fan
4330 * controls are configured to use unmonitored temperature sources.
4331 * If so, assign the unmonitored temperature sources to available
4332 * monitoring registers.
4333 */
4334 mask = 0;
4335 available = 0;
4336 for (i = 0; i < num_reg_temp; i++) {
4337 if (reg_temp[i] == 0)
4338 continue;
4339
4340 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004341 if (!src || (mask & BIT(src)))
4342 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004343
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004344 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004345 }
4346
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004347 /*
4348 * Now find unmonitored temperature registers and enable monitoring
4349 * if additional monitoring registers are available.
4350 */
4351 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4352 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4353
Guenter Roeckaa136e52012-12-04 03:26:05 -08004354 mask = 0;
4355 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4356 for (i = 0; i < num_reg_temp; i++) {
4357 if (reg_temp[i] == 0)
4358 continue;
4359
4360 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004361 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004362 continue;
4363
Guenter Roeckcc66b302017-05-17 18:05:06 -07004364 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004365 dev_info(dev,
4366 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4367 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4368 continue;
4369 }
4370
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004371 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004372
4373 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4374 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004375 data->have_temp |= BIT(src - 1);
4376 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004377 data->reg_temp[0][src - 1] = reg_temp[i];
4378 data->reg_temp[1][src - 1] = reg_temp_over[i];
4379 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004380 if (reg_temp_crit_h && reg_temp_crit_h[i])
4381 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4382 else if (reg_temp_crit[src - 1])
4383 data->reg_temp[3][src - 1]
4384 = reg_temp_crit[src - 1];
4385 if (reg_temp_crit_l && reg_temp_crit_l[i])
4386 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004387 data->reg_temp_config[src - 1] = reg_temp_config[i];
4388 data->temp_src[src - 1] = src;
4389 continue;
4390 }
4391
4392 if (s >= NUM_TEMP)
4393 continue;
4394
4395 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004396 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004397 data->reg_temp[0][s] = reg_temp[i];
4398 data->reg_temp[1][s] = reg_temp_over[i];
4399 data->reg_temp[2][s] = reg_temp_hyst[i];
4400 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004401 if (reg_temp_crit_h && reg_temp_crit_h[i])
4402 data->reg_temp[3][s] = reg_temp_crit_h[i];
4403 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004404 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004405 if (reg_temp_crit_l && reg_temp_crit_l[i])
4406 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004407
4408 data->temp_src[s] = src;
4409 s++;
4410 }
4411
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004412 /*
4413 * Repeat with temperatures used for fan control.
4414 * This set of registers does not support limits.
4415 */
4416 for (i = 0; i < num_reg_temp_mon; i++) {
4417 if (reg_temp_mon[i] == 0)
4418 continue;
4419
4420 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004421 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004422 continue;
4423
Guenter Roeckcc66b302017-05-17 18:05:06 -07004424 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004425 dev_info(dev,
4426 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4427 src, i, data->REG_TEMP_SEL[i],
4428 reg_temp_mon[i]);
4429 continue;
4430 }
4431
Guenter Roeck7ce41902016-09-11 12:42:52 -07004432 /*
4433 * For virtual temperature sources, the 'virtual' temperature
4434 * for each fan reflects a different temperature, and there
4435 * are no duplicates.
4436 */
Guenter Roeck37196ba2018-09-13 19:43:58 -07004437 if (!(data->virt_temp_mask & BIT(src))) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004438 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004439 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004440 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004441 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004442
4443 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4444 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004445 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004446 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004447 data->have_temp |= BIT(src - 1);
4448 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004449 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4450 data->temp_src[src - 1] = src;
4451 continue;
4452 }
4453
4454 if (s >= NUM_TEMP)
4455 continue;
4456
4457 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004458 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004459 data->reg_temp[0][s] = reg_temp_mon[i];
4460 data->temp_src[s] = src;
4461 s++;
4462 }
4463
Guenter Roeckaa136e52012-12-04 03:26:05 -08004464#ifdef USE_ALTERNATE
4465 /*
4466 * Go through the list of alternate temp registers and enable
4467 * if possible.
4468 * The temperature is already monitored if the respective bit in <mask>
4469 * is set.
4470 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004471 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004472 if (!(data->temp_mask & BIT(i + 1)))
4473 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004474 if (!reg_temp_alternate[i])
4475 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004476 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004477 continue;
4478 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004479 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004480 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004481 data->have_temp |= BIT(i);
4482 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004483 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004484 if (i < num_reg_temp) {
4485 data->reg_temp[1][i] = reg_temp_over[i];
4486 data->reg_temp[2][i] = reg_temp_hyst[i];
4487 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004488 data->temp_src[i] = i + 1;
4489 continue;
4490 }
4491
4492 if (s >= NUM_TEMP) /* Abort if no more space */
4493 break;
4494
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004495 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004496 data->reg_temp[0][s] = reg_temp_alternate[i];
4497 data->temp_src[s] = i + 1;
4498 s++;
4499 }
4500#endif /* USE_ALTERNATE */
4501
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004502 /* Initialize the chip */
4503 nct6775_init_device(data);
4504
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004505 err = superio_enter(sio_data->sioreg);
4506 if (err)
4507 return err;
4508
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004509 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4510 switch (data->kind) {
4511 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004512 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004513 break;
4514 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004515 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004516 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004517 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004518 case nct6116:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004519 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004520 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004521 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004522 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004523 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004524 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004525 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004526 case nct6798:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004527 break;
4528 }
4529
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004530 /*
4531 * Read VID value
4532 * We can get the VID input values directly at logical device D 0xe3.
4533 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004534 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004535 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4536 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4537 data->vrm = vid_which_vrm();
4538 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004539
4540 if (fan_debounce) {
4541 u8 tmp;
4542
4543 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4544 tmp = superio_inb(sio_data->sioreg,
4545 NCT6775_REG_CR_FAN_DEBOUNCE);
4546 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004547 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004548 case nct6116:
Guenter Roeck6c009502012-07-01 08:23:15 -07004549 tmp |= 0xe0;
4550 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004551 case nct6775:
4552 tmp |= 0x1e;
4553 break;
4554 case nct6776:
4555 case nct6779:
4556 tmp |= 0x3e;
4557 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004558 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004559 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004560 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004561 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004562 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004563 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004564 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004565 tmp |= 0x7e;
4566 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004567 }
4568 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4569 tmp);
4570 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4571 data->name);
4572 }
4573
Guenter Roeckdf612d52013-07-08 13:15:04 -07004574 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004575
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004576 superio_exit(sio_data->sioreg);
4577
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004578 /* Read fan clock dividers immediately */
4579 nct6775_init_fan_common(dev, data);
4580
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004581 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004582 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4583 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004584 if (IS_ERR(group))
4585 return PTR_ERR(group);
4586
Axel Lin55bdee62014-07-24 08:59:34 +08004587 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004588
Guenter Roeckf73cf632013-03-18 09:22:50 -07004589 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4590 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004591 if (IS_ERR(group))
4592 return PTR_ERR(group);
4593
Axel Lin55bdee62014-07-24 08:59:34 +08004594 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004595
Guenter Roeckf73cf632013-03-18 09:22:50 -07004596 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4597 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004598 if (IS_ERR(group))
4599 return PTR_ERR(group);
4600
Axel Lin55bdee62014-07-24 08:59:34 +08004601 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004602
Guenter Roeckf73cf632013-03-18 09:22:50 -07004603 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4604 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004605 if (IS_ERR(group))
4606 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004607
Axel Lin55bdee62014-07-24 08:59:34 +08004608 data->groups[num_attr_groups++] = group;
4609 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004610
Guenter Roecka150d952013-07-11 22:55:22 -07004611 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4612 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004613 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004614}
4615
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004616static void nct6791_enable_io_mapping(int sioaddr)
4617{
4618 int val;
4619
4620 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4621 if (val & 0x10) {
4622 pr_info("Enabling hardware monitor logical device mappings.\n");
4623 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4624 val & ~0x10);
4625 }
4626}
4627
Guenter Roeck48e93182015-02-07 08:48:49 -08004628static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004629{
4630 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004631
4632 mutex_lock(&data->update_lock);
4633 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004634 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004635 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4636 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4637 }
4638 mutex_unlock(&data->update_lock);
4639
4640 return 0;
4641}
4642
Guenter Roeck48e93182015-02-07 08:48:49 -08004643static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004644{
4645 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004646 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004647 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004648 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004649
4650 mutex_lock(&data->update_lock);
4651 data->bank = 0xff; /* Force initial bank selection */
4652
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004653 err = superio_enter(sioreg);
4654 if (err)
4655 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004656
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004657 superio_select(sioreg, NCT6775_LD_HWM);
4658 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4659 if (reg != data->sio_reg_enable)
4660 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4661
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004662 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004663 data->kind == nct6793 || data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004664 data->kind == nct6796 || data->kind == nct6797 ||
4665 data->kind == nct6798)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004666 nct6791_enable_io_mapping(sioreg);
4667
4668 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004669
Guenter Roeck84d19d92012-12-04 08:01:39 -08004670 /* Restore limits */
4671 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004672 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004673 continue;
4674
4675 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4676 data->in[i][1]);
4677 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4678 data->in[i][2]);
4679 }
4680
Guenter Roeckc409fd42013-04-09 05:04:00 -07004681 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004682 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004683 continue;
4684
4685 nct6775_write_value(data, data->REG_FAN_MIN[i],
4686 data->fan_min[i]);
4687 }
4688
4689 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004690 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004691 continue;
4692
Guenter Roeckc409fd42013-04-09 05:04:00 -07004693 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004694 if (data->reg_temp[j][i])
4695 nct6775_write_temp(data, data->reg_temp[j][i],
4696 data->temp[j][i]);
4697 }
4698
4699 /* Restore other settings */
4700 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004701 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004702 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4703 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4704 }
4705
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004706abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004707 /* Force re-reading all values */
4708 data->valid = false;
4709 mutex_unlock(&data->update_lock);
4710
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004711 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004712}
4713
Guenter Roeck48e93182015-02-07 08:48:49 -08004714static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004715
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004716static struct platform_driver nct6775_driver = {
4717 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004718 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004719 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004720 },
4721 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004722};
4723
4724/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004725static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004726{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004727 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004728 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004729 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004730
4731 err = superio_enter(sioaddr);
4732 if (err)
4733 return err;
4734
Guenter Roeckfc72af32016-08-03 22:07:18 -07004735 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4736 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4737 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004738 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004739
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004740 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004741 case SIO_NCT6106_ID:
4742 sio_data->kind = nct6106;
4743 break;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004744 case SIO_NCT6116_ID:
4745 sio_data->kind = nct6116;
4746 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004747 case SIO_NCT6775_ID:
4748 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004749 break;
4750 case SIO_NCT6776_ID:
4751 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004752 break;
4753 case SIO_NCT6779_ID:
4754 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004755 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004756 case SIO_NCT6791_ID:
4757 sio_data->kind = nct6791;
4758 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004759 case SIO_NCT6792_ID:
4760 sio_data->kind = nct6792;
4761 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004762 case SIO_NCT6793_ID:
4763 sio_data->kind = nct6793;
4764 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004765 case SIO_NCT6795_ID:
4766 sio_data->kind = nct6795;
4767 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004768 case SIO_NCT6796_ID:
4769 sio_data->kind = nct6796;
4770 break;
Guenter Roecke41da282018-09-18 20:48:29 -07004771 case SIO_NCT6797_ID:
4772 sio_data->kind = nct6797;
4773 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004774 case SIO_NCT6798_ID:
4775 sio_data->kind = nct6798;
4776 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004777 default:
4778 if (val != 0xffff)
4779 pr_debug("unsupported chip ID: 0x%04x\n", val);
4780 superio_exit(sioaddr);
4781 return -ENODEV;
4782 }
4783
4784 /* We have a known chip, find the HWM I/O address */
4785 superio_select(sioaddr, NCT6775_LD_HWM);
4786 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4787 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004788 addr = val & IOREGION_ALIGNMENT;
4789 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004790 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4791 superio_exit(sioaddr);
4792 return -ENODEV;
4793 }
4794
4795 /* Activate logical device if needed */
4796 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4797 if (!(val & 0x01)) {
4798 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4799 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4800 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004801
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004802 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004803 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004804 sio_data->kind == nct6796 || sio_data->kind == nct6797 ||
4805 sio_data->kind == nct6798)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004806 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004807
4808 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004809 pr_info("Found %s or compatible chip at %#x:%#x\n",
4810 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004811 sio_data->sioreg = sioaddr;
4812
Guenter Roeck698a7c22013-04-05 07:35:25 -07004813 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004814}
4815
4816/*
4817 * when Super-I/O functions move to a separate file, the Super-I/O
4818 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004819 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004820 * must keep track of the device
4821 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004822static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004823
4824static int __init sensors_nct6775_init(void)
4825{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004826 int i, err;
4827 bool found = false;
4828 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004829 struct resource res;
4830 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004831 int sioaddr[2] = { 0x2e, 0x4e };
4832
4833 err = platform_driver_register(&nct6775_driver);
4834 if (err)
4835 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004836
4837 /*
4838 * initialize sio_data->kind and sio_data->sioreg.
4839 *
4840 * when Super-I/O functions move to a separate file, the Super-I/O
4841 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4842 * nct6775 hardware monitor, and call probe()
4843 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004844 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4845 address = nct6775_find(sioaddr[i], &sio_data);
4846 if (address <= 0)
4847 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004848
Guenter Roeck698a7c22013-04-05 07:35:25 -07004849 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004850
Guenter Roeck698a7c22013-04-05 07:35:25 -07004851 pdev[i] = platform_device_alloc(DRVNAME, address);
4852 if (!pdev[i]) {
4853 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004854 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004855 }
4856
4857 err = platform_device_add_data(pdev[i], &sio_data,
4858 sizeof(struct nct6775_sio_data));
4859 if (err)
4860 goto exit_device_put;
4861
4862 memset(&res, 0, sizeof(res));
4863 res.name = DRVNAME;
4864 res.start = address + IOREGION_OFFSET;
4865 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4866 res.flags = IORESOURCE_IO;
4867
4868 err = acpi_check_resource_conflict(&res);
4869 if (err) {
4870 platform_device_put(pdev[i]);
4871 pdev[i] = NULL;
4872 continue;
4873 }
4874
4875 err = platform_device_add_resources(pdev[i], &res, 1);
4876 if (err)
4877 goto exit_device_put;
4878
4879 /* platform_device_add calls probe() */
4880 err = platform_device_add(pdev[i]);
4881 if (err)
4882 goto exit_device_put;
4883 }
4884 if (!found) {
4885 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004886 goto exit_unregister;
4887 }
4888
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004889 return 0;
4890
4891exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004892 platform_device_put(pdev[i]);
4893exit_device_unregister:
4894 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004895 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004896 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004897 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004898exit_unregister:
4899 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004900 return err;
4901}
4902
4903static void __exit sensors_nct6775_exit(void)
4904{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004905 int i;
4906
4907 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4908 if (pdev[i])
4909 platform_device_unregister(pdev[i]);
4910 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004911 platform_driver_unregister(&nct6775_driver);
4912}
4913
4914MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004915MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004916MODULE_LICENSE("GPL");
4917
4918module_init(sensors_nct6775_init);
4919module_exit(sensors_nct6775_exit);