blob: 37149909f8a8bad2adce18a0dcbfb4a214e2bccb [file] [log] [blame]
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001/*
2 * nct6775 - Driver for the hardware monitoring functionality of
3 * Nuvoton NCT677x Super-I/O chips
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from w83627ehf driver
Jean Delvare7c81c60f2014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070042 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck419220d2017-05-17 18:19:18 -070043 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
Guenter Roeck81820052018-02-21 13:09:39 -080044 * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070045 *
46 * #temp lists the number of monitored temperature sources (first value) plus
47 * the number of directly connectable temperature sensors (second value).
48 */
49
50#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51
52#include <linux/module.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/jiffies.h>
56#include <linux/platform_device.h>
57#include <linux/hwmon.h>
58#include <linux/hwmon-sysfs.h>
59#include <linux/hwmon-vid.h>
60#include <linux/err.h>
61#include <linux/mutex.h>
62#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070063#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080064#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070065#include <linux/io.h>
66#include "lm75.h"
67
Guenter Roeckaa136e52012-12-04 03:26:05 -080068#define USE_ALTERNATE
69
Guenter Roeck419220d2017-05-17 18:19:18 -070070enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
Guenter Roeck81820052018-02-21 13:09:39 -080071 nct6795, nct6796 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070072
73/* used to set data->name = nct6775_device_names[data->sio_kind] */
74static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070075 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070076 "nct6775",
77 "nct6776",
78 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070079 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080080 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070081 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070082 "nct6795",
Guenter Roeck81820052018-02-21 13:09:39 -080083 "nct6796",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070084};
85
86static const char * const nct6775_sio_names[] __initconst = {
87 "NCT6106D",
88 "NCT6775F",
89 "NCT6776D/F",
90 "NCT6779D",
91 "NCT6791D",
92 "NCT6792D",
93 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -070094 "NCT6795D",
Guenter Roeck81820052018-02-21 13:09:39 -080095 "NCT6796D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070096};
97
98static unsigned short force_id;
99module_param(force_id, ushort, 0);
100MODULE_PARM_DESC(force_id, "Override the detected device ID");
101
Guenter Roeck47ece962012-12-04 07:59:32 -0800102static unsigned short fan_debounce;
103module_param(fan_debounce, ushort, 0);
104MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
105
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700106#define DRVNAME "nct6775"
107
108/*
109 * Super-I/O constants and functions
110 */
111
Guenter Roecka6bd5872012-12-04 03:13:34 -0800112#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700113#define NCT6775_LD_HWM 0x0b
114#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700115#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700116
117#define SIO_REG_LDSEL 0x07 /* Logical device select */
118#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
119#define SIO_REG_ENABLE 0x30 /* Logical device enable */
120#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
121
Guenter Roeck6c009502012-07-01 08:23:15 -0700122#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700123#define SIO_NCT6775_ID 0xb470
124#define SIO_NCT6776_ID 0xc330
125#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700126#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800127#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700128#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700129#define SIO_NCT6795_ID 0xd350
Guenter Roeck81820052018-02-21 13:09:39 -0800130#define SIO_NCT6796_ID 0xd420
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700131#define SIO_ID_MASK 0xFFF0
132
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800133enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
134
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700135static inline void
136superio_outb(int ioreg, int reg, int val)
137{
138 outb(reg, ioreg);
139 outb(val, ioreg + 1);
140}
141
142static inline int
143superio_inb(int ioreg, int reg)
144{
145 outb(reg, ioreg);
146 return inb(ioreg + 1);
147}
148
149static inline void
150superio_select(int ioreg, int ld)
151{
152 outb(SIO_REG_LDSEL, ioreg);
153 outb(ld, ioreg + 1);
154}
155
156static inline int
157superio_enter(int ioreg)
158{
159 /*
160 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
161 */
162 if (!request_muxed_region(ioreg, 2, DRVNAME))
163 return -EBUSY;
164
165 outb(0x87, ioreg);
166 outb(0x87, ioreg);
167
168 return 0;
169}
170
171static inline void
172superio_exit(int ioreg)
173{
174 outb(0xaa, ioreg);
175 outb(0x02, ioreg);
176 outb(0x02, ioreg + 1);
177 release_region(ioreg, 2);
178}
179
180/*
181 * ISA constants
182 */
183
184#define IOREGION_ALIGNMENT (~7)
185#define IOREGION_OFFSET 5
186#define IOREGION_LENGTH 2
187#define ADDR_REG_OFFSET 0
188#define DATA_REG_OFFSET 1
189
190#define NCT6775_REG_BANK 0x4E
191#define NCT6775_REG_CONFIG 0x40
192
193/*
194 * Not currently used:
195 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
196 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
197 * REG_MAN_ID is at port 0x4f
198 * REG_CHIP_ID is at port 0x58
199 */
200
Guenter Roeckaa136e52012-12-04 03:26:05 -0800201#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
202#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
203
Guenter Roeck6c009502012-07-01 08:23:15 -0700204#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700205#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700206
Guenter Roeck81820052018-02-21 13:09:39 -0800207#define NUM_FAN 7
David Bartley578ab5f2013-06-24 22:28:28 -0700208
Guenter Roeck7ce41902016-09-11 12:42:52 -0700209#define TEMP_SOURCE_VIRTUAL 0x1f
210
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700211/* Common and NCT6775 specific data */
212
213/* Voltage min/max registers for nr=7..14 are in bank 5 */
214
215static const u16 NCT6775_REG_IN_MAX[] = {
216 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
217 0x55c, 0x55e, 0x560, 0x562 };
218static const u16 NCT6775_REG_IN_MIN[] = {
219 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
220 0x55d, 0x55f, 0x561, 0x563 };
221static const u16 NCT6775_REG_IN[] = {
222 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
223};
224
225#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800226#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700227#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700228
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800229#define NCT6775_REG_FANDIV1 0x506
230#define NCT6775_REG_FANDIV2 0x507
231
Guenter Roeck47ece962012-12-04 07:59:32 -0800232#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
233
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700234static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
235
Guenter Roeck30846992013-06-24 22:21:59 -0700236/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700237
238static const s8 NCT6775_ALARM_BITS[] = {
239 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
240 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
241 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700242 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700243 -1, -1, -1, /* unused */
244 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
245 12, -1 }; /* intrusion0, intrusion1 */
246
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800247#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800248#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800249#define INTRUSION_ALARM_BASE 30
250
Guenter Roeck30846992013-06-24 22:21:59 -0700251static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
252
253/*
254 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
255 * 30..31 intrusion
256 */
257static const s8 NCT6775_BEEP_BITS[] = {
258 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
259 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
260 21, /* global beep enable */
261 6, 7, 11, 28, -1, /* fan1..fan5 */
262 -1, -1, -1, /* unused */
263 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
264 12, -1 }; /* intrusion0, intrusion1 */
265
266#define BEEP_ENABLE_BASE 15
267
Guenter Roecka6bd5872012-12-04 03:13:34 -0800268static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
269static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
270
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800271/* DC or PWM output fan configuration */
272static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
273static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
274
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800275/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800276
David Bartley578ab5f2013-06-24 22:28:28 -0700277static const u16 NCT6775_REG_TARGET[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800278 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
David Bartley578ab5f2013-06-24 22:28:28 -0700279static const u16 NCT6775_REG_FAN_MODE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800280 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800281static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800282 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800283static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800284 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800285static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800286 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
David Bartley578ab5f2013-06-24 22:28:28 -0700287static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800288 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800289static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
290static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
291
292static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800293 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
David Bartley578ab5f2013-06-24 22:28:28 -0700294static const u16 NCT6775_REG_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800295 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
David Bartley578ab5f2013-06-24 22:28:28 -0700296static const u16 NCT6775_REG_PWM_READ[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800297 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800298
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800299static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
300static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800301static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700302static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
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 Roeckaa136e52012-12-04 03:26:05 -0800375
Guenter Roeckcc66b302017-05-17 18:05:06 -0700376static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
377 [13] = 0x661,
378 [14] = 0x662,
379 [15] = 0x664,
380};
381
382static const u16 NCT6775_REG_TEMP_CRIT[32] = {
383 [4] = 0xa00,
384 [5] = 0xa01,
385 [6] = 0xa02,
386 [7] = 0xa03,
387 [8] = 0xa04,
388 [9] = 0xa05,
389 [10] = 0xa06,
390 [11] = 0xa07
391};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800392
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700393/* NCT6776 specific data */
394
Guenter Roeck728d2942015-08-31 16:13:47 -0700395/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
396#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
397#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
398
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700399static const s8 NCT6776_ALARM_BITS[] = {
400 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
401 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
402 -1, /* unused */
403 6, 7, 11, 10, 23, /* fan1..fan5 */
404 -1, -1, -1, /* unused */
405 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
406 12, 9 }; /* intrusion0, intrusion1 */
407
Guenter Roeck30846992013-06-24 22:21:59 -0700408static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
409
410static const s8 NCT6776_BEEP_BITS[] = {
411 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
412 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
413 24, /* global beep enable */
414 25, 26, 27, 28, 29, /* fan1..fan5 */
415 -1, -1, -1, /* unused */
416 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
417 30, 31 }; /* intrusion0, intrusion1 */
418
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800419static const u16 NCT6776_REG_TOLERANCE_H[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800420 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800421
David Bartley578ab5f2013-06-24 22:28:28 -0700422static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
423static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800424
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800425static const u16 NCT6776_REG_FAN_MIN[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800426 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800427static const u16 NCT6776_REG_FAN_PULSES[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800428 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800429
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800430static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700431 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800432
Guenter Roeckaa136e52012-12-04 03:26:05 -0800433static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
434 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
435
436static const char *const nct6776_temp_label[] = {
437 "",
438 "SYSTIN",
439 "CPUTIN",
440 "AUXTIN",
441 "SMBUSMASTER 0",
442 "SMBUSMASTER 1",
443 "SMBUSMASTER 2",
444 "SMBUSMASTER 3",
445 "SMBUSMASTER 4",
446 "SMBUSMASTER 5",
447 "SMBUSMASTER 6",
448 "SMBUSMASTER 7",
449 "PECI Agent 0",
450 "PECI Agent 1",
451 "PCH_CHIP_CPU_MAX_TEMP",
452 "PCH_CHIP_TEMP",
453 "PCH_CPU_TEMP",
454 "PCH_MCH_TEMP",
455 "PCH_DIM0_TEMP",
456 "PCH_DIM1_TEMP",
457 "PCH_DIM2_TEMP",
458 "PCH_DIM3_TEMP",
459 "BYTE_TEMP"
460};
461
Guenter Roeckcc66b302017-05-17 18:05:06 -0700462#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800463
Guenter Roeckcc66b302017-05-17 18:05:06 -0700464static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
465 [14] = 0x401,
466 [15] = 0x402,
467 [16] = 0x404,
468};
469
470static const u16 NCT6776_REG_TEMP_CRIT[32] = {
471 [11] = 0x709,
472 [12] = 0x70a,
473};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800474
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700475/* NCT6779 specific data */
476
477static const u16 NCT6779_REG_IN[] = {
478 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
479 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
480
481static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
482 0x459, 0x45A, 0x45B, 0x568 };
483
484static const s8 NCT6779_ALARM_BITS[] = {
485 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
486 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
487 -1, /* unused */
488 6, 7, 11, 10, 23, /* fan1..fan5 */
489 -1, -1, -1, /* unused */
490 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
491 12, 9 }; /* intrusion0, intrusion1 */
492
Guenter Roeck30846992013-06-24 22:21:59 -0700493static const s8 NCT6779_BEEP_BITS[] = {
494 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
495 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
496 24, /* global beep enable */
497 25, 26, 27, 28, 29, /* fan1..fan5 */
498 -1, -1, -1, /* unused */
499 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
500 30, 31 }; /* intrusion0, intrusion1 */
501
David Bartley578ab5f2013-06-24 22:28:28 -0700502static const u16 NCT6779_REG_FAN[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800503 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x660 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800504static const u16 NCT6779_REG_FAN_PULSES[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800505 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800506
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800507static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800508 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700509#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800510static const u16 NCT6779_REG_CRITICAL_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800511 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800512
Guenter Roeckaa136e52012-12-04 03:26:05 -0800513static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800514static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800515static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
516 0x18, 0x152 };
517static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
518 0x3a, 0x153 };
519static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
520 0x39, 0x155 };
521
522static const u16 NCT6779_REG_TEMP_OFFSET[] = {
523 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
524
525static const char *const nct6779_temp_label[] = {
526 "",
527 "SYSTIN",
528 "CPUTIN",
529 "AUXTIN0",
530 "AUXTIN1",
531 "AUXTIN2",
532 "AUXTIN3",
533 "",
534 "SMBUSMASTER 0",
535 "SMBUSMASTER 1",
536 "SMBUSMASTER 2",
537 "SMBUSMASTER 3",
538 "SMBUSMASTER 4",
539 "SMBUSMASTER 5",
540 "SMBUSMASTER 6",
541 "SMBUSMASTER 7",
542 "PECI Agent 0",
543 "PECI Agent 1",
544 "PCH_CHIP_CPU_MAX_TEMP",
545 "PCH_CHIP_TEMP",
546 "PCH_CPU_TEMP",
547 "PCH_MCH_TEMP",
548 "PCH_DIM0_TEMP",
549 "PCH_DIM1_TEMP",
550 "PCH_DIM2_TEMP",
551 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700552 "BYTE_TEMP",
553 "",
554 "",
555 "",
556 "",
557 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800558};
559
Guenter Roeckcc66b302017-05-17 18:05:06 -0700560#define NCT6779_TEMP_MASK 0x07ffff7e
561#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck9a383712015-08-29 15:29:25 -0700562
Guenter Roeckcc66b302017-05-17 18:05:06 -0700563static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800564 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
565 0, 0, 0, 0, 0, 0, 0, 0,
566 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
567 0x408, 0 };
568
Guenter Roeckcc66b302017-05-17 18:05:06 -0700569static const u16 NCT6779_REG_TEMP_CRIT[32] = {
570 [15] = 0x709,
571 [16] = 0x70a,
572};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800573
David Bartley578ab5f2013-06-24 22:28:28 -0700574/* NCT6791 specific data */
575
576#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
577
Guenter Roecke2617262018-02-21 13:09:36 -0800578static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
579static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
580static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
581static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
582static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
583static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800584
David Bartley578ab5f2013-06-24 22:28:28 -0700585static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
586 0x459, 0x45A, 0x45B, 0x568, 0x45D };
587
588static const s8 NCT6791_ALARM_BITS[] = {
589 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
590 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
591 -1, /* unused */
592 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
593 -1, -1, /* unused */
594 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
595 12, 9 }; /* intrusion0, intrusion1 */
596
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700597/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800598
599static const u16 NCT6792_REG_TEMP_MON[] = {
600 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
601static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
602 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700603
Guenter Roeck50224f42015-10-30 07:52:39 -0700604static const char *const nct6792_temp_label[] = {
605 "",
606 "SYSTIN",
607 "CPUTIN",
608 "AUXTIN0",
609 "AUXTIN1",
610 "AUXTIN2",
611 "AUXTIN3",
612 "",
613 "SMBUSMASTER 0",
614 "SMBUSMASTER 1",
615 "SMBUSMASTER 2",
616 "SMBUSMASTER 3",
617 "SMBUSMASTER 4",
618 "SMBUSMASTER 5",
619 "SMBUSMASTER 6",
620 "SMBUSMASTER 7",
621 "PECI Agent 0",
622 "PECI Agent 1",
623 "PCH_CHIP_CPU_MAX_TEMP",
624 "PCH_CHIP_TEMP",
625 "PCH_CPU_TEMP",
626 "PCH_MCH_TEMP",
627 "PCH_DIM0_TEMP",
628 "PCH_DIM1_TEMP",
629 "PCH_DIM2_TEMP",
630 "PCH_DIM3_TEMP",
631 "BYTE_TEMP",
632 "PECI Agent 0 Calibration",
633 "PECI Agent 1 Calibration",
634 "",
635 "",
636 "Virtual_TEMP"
637};
638
Guenter Roeckcc66b302017-05-17 18:05:06 -0700639#define NCT6792_TEMP_MASK 0x9fffff7e
640
Guenter Roeck50224f42015-10-30 07:52:39 -0700641static const char *const nct6793_temp_label[] = {
642 "",
643 "SYSTIN",
644 "CPUTIN",
645 "AUXTIN0",
646 "AUXTIN1",
647 "AUXTIN2",
648 "AUXTIN3",
649 "",
650 "SMBUSMASTER 0",
651 "SMBUSMASTER 1",
652 "",
653 "",
654 "",
655 "",
656 "",
657 "",
658 "PECI Agent 0",
659 "PECI Agent 1",
660 "PCH_CHIP_CPU_MAX_TEMP",
661 "PCH_CHIP_TEMP",
662 "PCH_CPU_TEMP",
663 "PCH_MCH_TEMP",
664 "Agent0 Dimm0 ",
665 "Agent0 Dimm1",
666 "Agent1 Dimm0",
667 "Agent1 Dimm1",
668 "BYTE_TEMP0",
669 "BYTE_TEMP1",
670 "PECI Agent 0 Calibration",
671 "PECI Agent 1 Calibration",
672 "",
673 "Virtual_TEMP"
674};
675
Guenter Roeckcc66b302017-05-17 18:05:06 -0700676#define NCT6793_TEMP_MASK 0xbfff037e
677
Guenter Roeck419220d2017-05-17 18:19:18 -0700678static const char *const nct6795_temp_label[] = {
679 "",
680 "SYSTIN",
681 "CPUTIN",
682 "AUXTIN0",
683 "AUXTIN1",
684 "AUXTIN2",
685 "AUXTIN3",
686 "",
687 "SMBUSMASTER 0",
688 "SMBUSMASTER 1",
689 "SMBUSMASTER 2",
690 "SMBUSMASTER 3",
691 "SMBUSMASTER 4",
692 "SMBUSMASTER 5",
693 "SMBUSMASTER 6",
694 "SMBUSMASTER 7",
695 "PECI Agent 0",
696 "PECI Agent 1",
697 "PCH_CHIP_CPU_MAX_TEMP",
698 "PCH_CHIP_TEMP",
699 "PCH_CPU_TEMP",
700 "PCH_MCH_TEMP",
701 "PCH_DIM0_TEMP",
702 "PCH_DIM1_TEMP",
703 "PCH_DIM2_TEMP",
704 "PCH_DIM3_TEMP",
705 "BYTE_TEMP0",
706 "BYTE_TEMP1",
707 "PECI Agent 0 Calibration",
708 "PECI Agent 1 Calibration",
709 "",
710 "Virtual_TEMP"
711};
712
713#define NCT6795_TEMP_MASK 0xbfffff7e
714
Guenter Roeck81820052018-02-21 13:09:39 -0800715static const char *const nct6796_temp_label[] = {
716 "",
717 "SYSTIN",
718 "CPUTIN",
719 "AUXTIN0",
720 "AUXTIN1",
721 "AUXTIN2",
722 "AUXTIN3",
723 "AUXTIN4",
724 "SMBUSMASTER 0",
725 "SMBUSMASTER 1",
726 "",
727 "",
728 "",
729 "",
730 "",
731 "",
732 "PECI Agent 0",
733 "PECI Agent 1",
734 "PCH_CHIP_CPU_MAX_TEMP",
735 "PCH_CHIP_TEMP",
736 "PCH_CPU_TEMP",
737 "PCH_MCH_TEMP",
738 "PCH_DIM0_TEMP",
739 "PCH_DIM1_TEMP",
740 "PCH_DIM2_TEMP",
741 "PCH_DIM3_TEMP",
742 "BYTE_TEMP0",
743 "BYTE_TEMP1",
744 "PECI Agent 0 Calibration",
745 "PECI Agent 1 Calibration",
746 "",
747 "Virtual_TEMP"
748};
749
750#define NCT6796_TEMP_MASK 0xbfff03fe
751
Guenter Roeck6c009502012-07-01 08:23:15 -0700752/* NCT6102D/NCT6106D specific data */
753
754#define NCT6106_REG_VBAT 0x318
755#define NCT6106_REG_DIODE 0x319
756#define NCT6106_DIODE_MASK 0x01
757
758static const u16 NCT6106_REG_IN_MAX[] = {
759 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
760static const u16 NCT6106_REG_IN_MIN[] = {
761 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
762static const u16 NCT6106_REG_IN[] = {
763 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
764
765static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800766static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700767static const u16 NCT6106_REG_TEMP_HYST[] = {
768 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
769static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700770 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
771static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
772 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
773static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
774 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700775static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
776static const u16 NCT6106_REG_TEMP_CONFIG[] = {
777 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
778
779static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
780static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
781static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
782static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
783
784static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
785static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
786static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
787static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
788static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
789static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
790static const u16 NCT6106_REG_TEMP_SOURCE[] = {
791 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
792
793static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
794static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
795 0x11b, 0x12b, 0x13b };
796
797static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
798#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
799static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
800
801static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
802static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
803static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
804static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
805static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
806static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
807
808static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
809
810static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
811static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
812static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
813static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
814static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
815static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
816
817static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
818static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
819
820static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
821 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
822
823static const s8 NCT6106_ALARM_BITS[] = {
824 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
825 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
826 -1, /* unused */
827 32, 33, 34, -1, -1, /* fan1..fan5 */
828 -1, -1, -1, /* unused */
829 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
830 48, -1 /* intrusion0, intrusion1 */
831};
832
Guenter Roeck30846992013-06-24 22:21:59 -0700833static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
834 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
835
836static const s8 NCT6106_BEEP_BITS[] = {
837 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
838 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
839 32, /* global beep enable */
840 24, 25, 26, 27, 28, /* fan1..fan5 */
841 -1, -1, -1, /* unused */
842 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
843 34, -1 /* intrusion0, intrusion1 */
844};
845
Guenter Roeckcc66b302017-05-17 18:05:06 -0700846static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
847 [14] = 0x51,
848 [15] = 0x52,
849 [16] = 0x54,
850};
Guenter Roeck6c009502012-07-01 08:23:15 -0700851
Guenter Roeckcc66b302017-05-17 18:05:06 -0700852static const u16 NCT6106_REG_TEMP_CRIT[32] = {
853 [11] = 0x204,
854 [12] = 0x205,
855};
Guenter Roeck6c009502012-07-01 08:23:15 -0700856
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800857static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
858{
859 if (mode == 0 && pwm == 255)
860 return off;
861 return mode + 1;
862}
863
864static int pwm_enable_to_reg(enum pwm_enable mode)
865{
866 if (mode == off)
867 return 0;
868 return mode - 1;
869}
870
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700871/*
872 * Conversions
873 */
874
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800875/* 1 is DC mode, output in ms */
876static unsigned int step_time_from_reg(u8 reg, u8 mode)
877{
878 return mode ? 400 * reg : 100 * reg;
879}
880
881static u8 step_time_to_reg(unsigned int msec, u8 mode)
882{
883 return clamp_val((mode ? (msec + 200) / 400 :
884 (msec + 50) / 100), 1, 255);
885}
886
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800887static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
888{
889 if (reg == 0 || reg == 255)
890 return 0;
891 return 1350000U / (reg << divreg);
892}
893
894static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
895{
896 if ((reg & 0xff1f) == 0xff1f)
897 return 0;
898
899 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
900
901 if (reg == 0)
902 return 0;
903
904 return 1350000U / reg;
905}
906
907static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
908{
909 if (reg == 0 || reg == 0xffff)
910 return 0;
911
912 /*
913 * Even though the registers are 16 bit wide, the fan divisor
914 * still applies.
915 */
916 return 1350000U / (reg << divreg);
917}
918
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800919static u16 fan_to_reg(u32 fan, unsigned int divreg)
920{
921 if (!fan)
922 return 0;
923
924 return (1350000U / fan) >> divreg;
925}
926
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800927static inline unsigned int
928div_from_reg(u8 reg)
929{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700930 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800931}
932
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700933/*
934 * Some of the voltage inputs have internal scaling, the tables below
935 * contain 8 (the ADC LSB in mV) * scaling factor * 100
936 */
937static const u16 scale_in[15] = {
938 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
939 800, 800
940};
941
942static inline long in_from_reg(u8 reg, u8 nr)
943{
944 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
945}
946
947static inline u8 in_to_reg(u32 val, u8 nr)
948{
949 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
950}
951
952/*
953 * Data structures and manipulation thereof
954 */
955
956struct nct6775_data {
957 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700958 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700959 enum kinds kind;
960 const char *name;
961
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700962 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700963
Guenter Roeckb7a61352013-04-02 22:14:06 -0700964 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
965 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800966 */
967 u8 temp_src[NUM_TEMP];
968 u16 reg_temp_config[NUM_TEMP];
969 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700970 u32 temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800971
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700972 u16 REG_CONFIG;
973 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800974 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700975 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700976
977 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700978 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700979
980 const u16 *REG_VIN;
981 const u16 *REG_IN_MINMAX[2];
982
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800983 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800984 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800985 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800986 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800987 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700988 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800989 const u16 *REG_FAN_TIME[3];
990
991 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800992
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800993 const u8 *REG_PWM_MODE;
994 const u8 *PWM_MODE_MASK;
995
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800996 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
997 * [3]=pwm_max, [4]=pwm_step,
998 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800999 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001000 const u16 *REG_PWM_READ;
1001
Guenter Roeck6c009502012-07-01 08:23:15 -07001002 const u16 *REG_CRITICAL_PWM_ENABLE;
1003 u8 CRITICAL_PWM_ENABLE_MASK;
1004 const u16 *REG_CRITICAL_PWM;
1005
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001006 const u16 *REG_AUTO_TEMP;
1007 const u16 *REG_AUTO_PWM;
1008
1009 const u16 *REG_CRITICAL_TEMP;
1010 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
1011
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001012 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001013 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001014 const u16 *REG_WEIGHT_TEMP_SEL;
1015 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
1016
Guenter Roeckaa136e52012-12-04 03:26:05 -08001017 const u16 *REG_TEMP_OFFSET;
1018
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001019 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07001020 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001021
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001022 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
1023 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
1024
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001025 struct mutex update_lock;
1026 bool valid; /* true if following fields are valid */
1027 unsigned long last_updated; /* In jiffies */
1028
1029 /* Register values */
1030 u8 bank; /* current register bank */
1031 u8 in_num; /* number of in inputs we have */
1032 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -07001033 unsigned int rpm[NUM_FAN];
1034 u16 fan_min[NUM_FAN];
1035 u8 fan_pulses[NUM_FAN];
1036 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001037 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001038 u8 has_fan; /* some fan inputs can be disabled */
1039 u8 has_fan_min; /* some fans don't have min register */
1040 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001041
Guenter Roeck6c009502012-07-01 08:23:15 -07001042 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001043 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001044 u8 temp_fixed_num; /* 3 or 6 */
1045 u8 temp_type[NUM_TEMP_FIXED];
1046 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001047 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1048 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001049 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001050 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001051
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001052 u8 pwm_num; /* number of pwm */
Guenter Roeck57fec3a2018-06-18 09:21:46 -07001053 u8 pwm_mode[NUM_FAN]; /* 0->DC variable voltage,
1054 * 1->PWM variable duty cycle
David Bartley578ab5f2013-06-24 22:28:28 -07001055 */
1056 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001057 /* 0->off
1058 * 1->manual
1059 * 2->thermal cruise mode (also called SmartFan I)
1060 * 3->fan speed cruise mode
1061 * 4->SmartFan III
1062 * 5->enhanced variable thermal cruise (SmartFan IV)
1063 */
David Bartley578ab5f2013-06-24 22:28:28 -07001064 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1065 * [3]=pwm_max, [4]=pwm_step,
1066 * [5]=weight_duty_step, [6]=weight_duty_base
1067 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001068
David Bartley578ab5f2013-06-24 22:28:28 -07001069 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001070 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001071 u32 target_speed[NUM_FAN];
1072 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001073 u8 speed_tolerance_limit;
1074
David Bartley578ab5f2013-06-24 22:28:28 -07001075 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001076 u8 tolerance_mask;
1077
David Bartley578ab5f2013-06-24 22:28:28 -07001078 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001079
1080 /* Automatic fan speed control registers */
1081 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001082 u8 auto_pwm[NUM_FAN][7];
1083 u8 auto_temp[NUM_FAN][7];
1084 u8 pwm_temp_sel[NUM_FAN];
1085 u8 pwm_weight_temp_sel[NUM_FAN];
1086 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1087 * 2->temp_base
1088 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001089
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001090 u8 vid;
1091 u8 vrm;
1092
Guenter Roeckf73cf632013-03-18 09:22:50 -07001093 bool have_vid;
1094
Guenter Roeckaa136e52012-12-04 03:26:05 -08001095 u16 have_temp;
1096 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001097 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001098
Guenter Roeck84d19d92012-12-04 08:01:39 -08001099 /* Remember extra register values over suspend/resume */
1100 u8 vbat;
1101 u8 fandiv1;
1102 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001103 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001104};
1105
1106struct nct6775_sio_data {
1107 int sioreg;
1108 enum kinds kind;
1109};
1110
Guenter Roeckf73cf632013-03-18 09:22:50 -07001111struct sensor_device_template {
1112 struct device_attribute dev_attr;
1113 union {
1114 struct {
1115 u8 nr;
1116 u8 index;
1117 } s;
1118 int index;
1119 } u;
1120 bool s2; /* true if both index and nr are used */
1121};
1122
1123struct sensor_device_attr_u {
1124 union {
1125 struct sensor_device_attribute a1;
1126 struct sensor_device_attribute_2 a2;
1127 } u;
1128 char name[32];
1129};
1130
1131#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1132 .attr = {.name = _template, .mode = _mode }, \
1133 .show = _show, \
1134 .store = _store, \
1135}
1136
1137#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1138 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1139 .u.index = _index, \
1140 .s2 = false }
1141
1142#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1143 _nr, _index) \
1144 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1145 .u.s.index = _index, \
1146 .u.s.nr = _nr, \
1147 .s2 = true }
1148
1149#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1150static struct sensor_device_template sensor_dev_template_##_name \
1151 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1152 _index)
1153
1154#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1155 _nr, _index) \
1156static struct sensor_device_template sensor_dev_template_##_name \
1157 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1158 _nr, _index)
1159
1160struct sensor_template_group {
1161 struct sensor_device_template **templates;
1162 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1163 int base;
1164};
1165
1166static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001167nct6775_create_attr_group(struct device *dev,
1168 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001169 int repeat)
1170{
1171 struct attribute_group *group;
1172 struct sensor_device_attr_u *su;
1173 struct sensor_device_attribute *a;
1174 struct sensor_device_attribute_2 *a2;
1175 struct attribute **attrs;
1176 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001177 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001178
1179 if (repeat <= 0)
1180 return ERR_PTR(-EINVAL);
1181
1182 t = tg->templates;
1183 for (count = 0; *t; t++, count++)
1184 ;
1185
1186 if (count == 0)
1187 return ERR_PTR(-EINVAL);
1188
1189 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1190 if (group == NULL)
1191 return ERR_PTR(-ENOMEM);
1192
Kees Cooka86854d2018-06-12 14:07:58 -07001193 attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001194 GFP_KERNEL);
1195 if (attrs == NULL)
1196 return ERR_PTR(-ENOMEM);
1197
Kees Cooka86854d2018-06-12 14:07:58 -07001198 su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001199 GFP_KERNEL);
1200 if (su == NULL)
1201 return ERR_PTR(-ENOMEM);
1202
1203 group->attrs = attrs;
1204 group->is_visible = tg->is_visible;
1205
1206 for (i = 0; i < repeat; i++) {
1207 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001208 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001209 snprintf(su->name, sizeof(su->name),
1210 (*t)->dev_attr.attr.name, tg->base + i);
1211 if ((*t)->s2) {
1212 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001213 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001214 a2->dev_attr.attr.name = su->name;
1215 a2->nr = (*t)->u.s.nr + i;
1216 a2->index = (*t)->u.s.index;
1217 a2->dev_attr.attr.mode =
1218 (*t)->dev_attr.attr.mode;
1219 a2->dev_attr.show = (*t)->dev_attr.show;
1220 a2->dev_attr.store = (*t)->dev_attr.store;
1221 *attrs = &a2->dev_attr.attr;
1222 } else {
1223 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001224 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001225 a->dev_attr.attr.name = su->name;
1226 a->index = (*t)->u.index + i;
1227 a->dev_attr.attr.mode =
1228 (*t)->dev_attr.attr.mode;
1229 a->dev_attr.show = (*t)->dev_attr.show;
1230 a->dev_attr.store = (*t)->dev_attr.store;
1231 *attrs = &a->dev_attr.attr;
1232 }
1233 attrs++;
1234 su++;
1235 t++;
1236 }
1237 }
1238
Guenter Roeckf73cf632013-03-18 09:22:50 -07001239 return group;
1240}
1241
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001242static bool is_word_sized(struct nct6775_data *data, u16 reg)
1243{
1244 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001245 case nct6106:
1246 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1247 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1248 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001249 case nct6775:
1250 return (((reg & 0xff00) == 0x100 ||
1251 (reg & 0xff00) == 0x200) &&
1252 ((reg & 0x00ff) == 0x50 ||
1253 (reg & 0x00ff) == 0x53 ||
1254 (reg & 0x00ff) == 0x55)) ||
1255 (reg & 0xfff0) == 0x630 ||
1256 reg == 0x640 || reg == 0x642 ||
1257 reg == 0x662 ||
1258 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1259 reg == 0x73 || reg == 0x75 || reg == 0x77;
1260 case nct6776:
1261 return (((reg & 0xff00) == 0x100 ||
1262 (reg & 0xff00) == 0x200) &&
1263 ((reg & 0x00ff) == 0x50 ||
1264 (reg & 0x00ff) == 0x53 ||
1265 (reg & 0x00ff) == 0x55)) ||
1266 (reg & 0xfff0) == 0x630 ||
1267 reg == 0x402 ||
1268 reg == 0x640 || reg == 0x642 ||
1269 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1270 reg == 0x73 || reg == 0x75 || reg == 0x77;
1271 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001272 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001273 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001274 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001275 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001276 case nct6796:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001277 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001278 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001279 reg == 0x402 ||
1280 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001281 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck81820052018-02-21 13:09:39 -08001282 reg == 0x64c || reg == 0x660 ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001283 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001284 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001285 }
1286 return false;
1287}
1288
1289/*
1290 * On older chips, only registers 0x50-0x5f are banked.
1291 * On more recent chips, all registers are banked.
1292 * Assume that is the case and set the bank number for each access.
1293 * Cache the bank number so it only needs to be set if it changes.
1294 */
1295static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1296{
1297 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001298
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001299 if (data->bank != bank) {
1300 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1301 outb_p(bank, data->addr + DATA_REG_OFFSET);
1302 data->bank = bank;
1303 }
1304}
1305
1306static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1307{
1308 int res, word_sized = is_word_sized(data, reg);
1309
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001310 nct6775_set_bank(data, reg);
1311 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1312 res = inb_p(data->addr + DATA_REG_OFFSET);
1313 if (word_sized) {
1314 outb_p((reg & 0xff) + 1,
1315 data->addr + ADDR_REG_OFFSET);
1316 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1317 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001318 return res;
1319}
1320
1321static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1322{
1323 int word_sized = is_word_sized(data, reg);
1324
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001325 nct6775_set_bank(data, reg);
1326 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1327 if (word_sized) {
1328 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1329 outb_p((reg & 0xff) + 1,
1330 data->addr + ADDR_REG_OFFSET);
1331 }
1332 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001333 return 0;
1334}
1335
Guenter Roeckaa136e52012-12-04 03:26:05 -08001336/* We left-align 8-bit temperature values to make the code simpler */
1337static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1338{
1339 u16 res;
1340
1341 res = nct6775_read_value(data, reg);
1342 if (!is_word_sized(data, reg))
1343 res <<= 8;
1344
1345 return res;
1346}
1347
1348static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1349{
1350 if (!is_word_sized(data, reg))
1351 value >>= 8;
1352 return nct6775_write_value(data, reg, value);
1353}
1354
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001355/* This function assumes that the caller holds data->update_lock */
1356static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1357{
1358 u8 reg;
1359
1360 switch (nr) {
1361 case 0:
1362 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1363 | (data->fan_div[0] & 0x7);
1364 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1365 break;
1366 case 1:
1367 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1368 | ((data->fan_div[1] << 4) & 0x70);
1369 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1370 break;
1371 case 2:
1372 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1373 | (data->fan_div[2] & 0x7);
1374 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1375 break;
1376 case 3:
1377 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1378 | ((data->fan_div[3] << 4) & 0x70);
1379 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1380 break;
1381 }
1382}
1383
1384static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1385{
1386 if (data->kind == nct6775)
1387 nct6775_write_fan_div(data, nr);
1388}
1389
1390static void nct6775_update_fan_div(struct nct6775_data *data)
1391{
1392 u8 i;
1393
1394 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1395 data->fan_div[0] = i & 0x7;
1396 data->fan_div[1] = (i & 0x70) >> 4;
1397 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1398 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001399 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001400 data->fan_div[3] = (i & 0x70) >> 4;
1401}
1402
1403static void nct6775_update_fan_div_common(struct nct6775_data *data)
1404{
1405 if (data->kind == nct6775)
1406 nct6775_update_fan_div(data);
1407}
1408
1409static void nct6775_init_fan_div(struct nct6775_data *data)
1410{
1411 int i;
1412
1413 nct6775_update_fan_div_common(data);
1414 /*
1415 * For all fans, start with highest divider value if the divider
1416 * register is not initialized. This ensures that we get a
1417 * reading from the fan count register, even if it is not optimal.
1418 * We'll compute a better divider later on.
1419 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001420 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001421 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001422 continue;
1423 if (data->fan_div[i] == 0) {
1424 data->fan_div[i] = 7;
1425 nct6775_write_fan_div_common(data, i);
1426 }
1427 }
1428}
1429
1430static void nct6775_init_fan_common(struct device *dev,
1431 struct nct6775_data *data)
1432{
1433 int i;
1434 u8 reg;
1435
1436 if (data->has_fan_div)
1437 nct6775_init_fan_div(data);
1438
1439 /*
1440 * If fan_min is not set (0), set it to 0xff to disable it. This
1441 * prevents the unnecessary warning when fanX_min is reported as 0.
1442 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001443 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001444 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001445 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1446 if (!reg)
1447 nct6775_write_value(data, data->REG_FAN_MIN[i],
1448 data->has_fan_div ? 0xff
1449 : 0xff1f);
1450 }
1451 }
1452}
1453
1454static void nct6775_select_fan_div(struct device *dev,
1455 struct nct6775_data *data, int nr, u16 reg)
1456{
1457 u8 fan_div = data->fan_div[nr];
1458 u16 fan_min;
1459
1460 if (!data->has_fan_div)
1461 return;
1462
1463 /*
1464 * If we failed to measure the fan speed, or the reported value is not
1465 * in the optimal range, and the clock divider can be modified,
1466 * let's try that for next time.
1467 */
1468 if (reg == 0x00 && fan_div < 0x07)
1469 fan_div++;
1470 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1471 fan_div--;
1472
1473 if (fan_div != data->fan_div[nr]) {
1474 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1475 nr + 1, div_from_reg(data->fan_div[nr]),
1476 div_from_reg(fan_div));
1477
1478 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001479 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001480 fan_min = data->fan_min[nr];
1481 if (fan_div > data->fan_div[nr]) {
1482 if (fan_min != 255 && fan_min > 1)
1483 fan_min >>= 1;
1484 } else {
1485 if (fan_min != 255) {
1486 fan_min <<= 1;
1487 if (fan_min > 254)
1488 fan_min = 254;
1489 }
1490 }
1491 if (fan_min != data->fan_min[nr]) {
1492 data->fan_min[nr] = fan_min;
1493 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1494 fan_min);
1495 }
1496 }
1497 data->fan_div[nr] = fan_div;
1498 nct6775_write_fan_div_common(data, nr);
1499 }
1500}
1501
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001502static void nct6775_update_pwm(struct device *dev)
1503{
1504 struct nct6775_data *data = dev_get_drvdata(dev);
1505 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001506 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001507 bool duty_is_dc;
1508
1509 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001510 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001511 continue;
1512
1513 duty_is_dc = data->REG_PWM_MODE[i] &&
1514 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1515 & data->PWM_MODE_MASK[i]);
Guenter Roeck415eb2a2018-03-26 19:50:31 -07001516 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001517
1518 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1519 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1520 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1521 data->pwm[j][i]
1522 = nct6775_read_value(data,
1523 data->REG_PWM[j][i]);
1524 }
1525 }
1526
1527 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1528 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001529
1530 if (!data->temp_tolerance[0][i] ||
1531 data->pwm_enable[i] != speed_cruise)
1532 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1533 if (!data->target_speed_tolerance[i] ||
1534 data->pwm_enable[i] == speed_cruise) {
1535 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001536
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001537 if (data->REG_TOLERANCE_H) {
1538 t |= (nct6775_read_value(data,
1539 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1540 }
1541 data->target_speed_tolerance[i] = t;
1542 }
1543
1544 data->temp_tolerance[1][i] =
1545 nct6775_read_value(data,
1546 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1547
1548 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1549 data->pwm_temp_sel[i] = reg & 0x1f;
1550 /* If fan can stop, report floor as 0 */
1551 if (reg & 0x80)
1552 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001553
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001554 if (!data->REG_WEIGHT_TEMP_SEL[i])
1555 continue;
1556
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001557 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1558 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1559 /* If weight is disabled, report weight source as 0 */
1560 if (j == 1 && !(reg & 0x80))
1561 data->pwm_weight_temp_sel[i] = 0;
1562
1563 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001564 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001565 data->weight_temp[j][i]
1566 = nct6775_read_value(data,
1567 data->REG_WEIGHT_TEMP[j][i]);
1568 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001569 }
1570}
1571
1572static void nct6775_update_pwm_limits(struct device *dev)
1573{
1574 struct nct6775_data *data = dev_get_drvdata(dev);
1575 int i, j;
1576 u8 reg;
1577 u16 reg_t;
1578
1579 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001580 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001581 continue;
1582
Guenter Roeckc409fd42013-04-09 05:04:00 -07001583 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001584 data->fan_time[j][i] =
1585 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1586 }
1587
1588 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1589 /* Update only in matching mode or if never updated */
1590 if (!data->target_temp[i] ||
1591 data->pwm_enable[i] == thermal_cruise)
1592 data->target_temp[i] = reg_t & data->target_temp_mask;
1593 if (!data->target_speed[i] ||
1594 data->pwm_enable[i] == speed_cruise) {
1595 if (data->REG_TOLERANCE_H) {
1596 reg_t |= (nct6775_read_value(data,
1597 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1598 }
1599 data->target_speed[i] = reg_t;
1600 }
1601
1602 for (j = 0; j < data->auto_pwm_num; j++) {
1603 data->auto_pwm[i][j] =
1604 nct6775_read_value(data,
1605 NCT6775_AUTO_PWM(data, i, j));
1606 data->auto_temp[i][j] =
1607 nct6775_read_value(data,
1608 NCT6775_AUTO_TEMP(data, i, j));
1609 }
1610
1611 /* critical auto_pwm temperature data */
1612 data->auto_temp[i][data->auto_pwm_num] =
1613 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1614
1615 switch (data->kind) {
1616 case nct6775:
1617 reg = nct6775_read_value(data,
1618 NCT6775_REG_CRITICAL_ENAB[i]);
1619 data->auto_pwm[i][data->auto_pwm_num] =
1620 (reg & 0x02) ? 0xff : 0x00;
1621 break;
1622 case nct6776:
1623 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1624 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001625 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001626 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001627 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001628 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001629 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001630 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001631 case nct6796:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001632 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001633 data->REG_CRITICAL_PWM_ENABLE[i]);
1634 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1635 reg = nct6775_read_value(data,
1636 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001637 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001638 reg = 0xff;
1639 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001640 break;
1641 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001642 }
1643}
1644
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001645static struct nct6775_data *nct6775_update_device(struct device *dev)
1646{
1647 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001648 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001649
1650 mutex_lock(&data->update_lock);
1651
Guenter Roeck6445e662013-04-21 09:13:28 -07001652 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001653 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001654 /* Fan clock dividers */
1655 nct6775_update_fan_div_common(data);
1656
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001657 /* Measured voltages and limits */
1658 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001659 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001660 continue;
1661
1662 data->in[i][0] = nct6775_read_value(data,
1663 data->REG_VIN[i]);
1664 data->in[i][1] = nct6775_read_value(data,
1665 data->REG_IN_MINMAX[0][i]);
1666 data->in[i][2] = nct6775_read_value(data,
1667 data->REG_IN_MINMAX[1][i]);
1668 }
1669
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001670 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001671 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001672 u16 reg;
1673
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001674 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001675 continue;
1676
1677 reg = nct6775_read_value(data, data->REG_FAN[i]);
1678 data->rpm[i] = data->fan_from_reg(reg,
1679 data->fan_div[i]);
1680
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001681 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001682 data->fan_min[i] = nct6775_read_value(data,
1683 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001684 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001685 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1686 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001687
1688 nct6775_select_fan_div(dev, data, i, reg);
1689 }
1690
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001691 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001692 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001693
Guenter Roeckaa136e52012-12-04 03:26:05 -08001694 /* Measured temperatures and limits */
1695 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001696 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001697 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001698 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001699 if (data->reg_temp[j][i])
1700 data->temp[j][i]
1701 = nct6775_read_temp(data,
1702 data->reg_temp[j][i]);
1703 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001704 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001705 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001706 continue;
1707 data->temp_offset[i]
1708 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1709 }
1710
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001711 data->alarms = 0;
1712 for (i = 0; i < NUM_REG_ALARM; i++) {
1713 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001714
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001715 if (!data->REG_ALARM[i])
1716 continue;
1717 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1718 data->alarms |= ((u64)alarm) << (i << 3);
1719 }
1720
Guenter Roeck30846992013-06-24 22:21:59 -07001721 data->beeps = 0;
1722 for (i = 0; i < NUM_REG_BEEP; i++) {
1723 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001724
Guenter Roeck30846992013-06-24 22:21:59 -07001725 if (!data->REG_BEEP[i])
1726 continue;
1727 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1728 data->beeps |= ((u64)beep) << (i << 3);
1729 }
1730
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001731 data->last_updated = jiffies;
1732 data->valid = true;
1733 }
1734
1735 mutex_unlock(&data->update_lock);
1736 return data;
1737}
1738
1739/*
1740 * Sysfs callback functions
1741 */
1742static ssize_t
1743show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1744{
1745 struct nct6775_data *data = nct6775_update_device(dev);
1746 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001747 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001748 int nr = sattr->nr;
1749
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001750 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1751}
1752
1753static ssize_t
1754store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1755 size_t count)
1756{
1757 struct nct6775_data *data = dev_get_drvdata(dev);
1758 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001759 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001760 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001761 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001762 int err;
1763
1764 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001765 if (err < 0)
1766 return err;
1767 mutex_lock(&data->update_lock);
1768 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001769 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001770 data->in[nr][index]);
1771 mutex_unlock(&data->update_lock);
1772 return count;
1773}
1774
1775static ssize_t
1776show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1777{
1778 struct nct6775_data *data = nct6775_update_device(dev);
1779 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1780 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001781
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001782 return sprintf(buf, "%u\n",
1783 (unsigned int)((data->alarms >> nr) & 0x01));
1784}
1785
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001786static int find_temp_source(struct nct6775_data *data, int index, int count)
1787{
1788 int source = data->temp_src[index];
1789 int nr;
1790
1791 for (nr = 0; nr < count; nr++) {
1792 int src;
1793
1794 src = nct6775_read_value(data,
1795 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1796 if (src == source)
1797 return nr;
1798 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001799 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001800}
1801
1802static ssize_t
1803show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1804{
1805 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1806 struct nct6775_data *data = nct6775_update_device(dev);
1807 unsigned int alarm = 0;
1808 int nr;
1809
1810 /*
1811 * For temperatures, there is no fixed mapping from registers to alarm
1812 * bits. Alarm bits are determined by the temperature source mapping.
1813 */
1814 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1815 if (nr >= 0) {
1816 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001817
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001818 alarm = (data->alarms >> bit) & 0x01;
1819 }
1820 return sprintf(buf, "%u\n", alarm);
1821}
1822
Guenter Roeck30846992013-06-24 22:21:59 -07001823static ssize_t
1824show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1825{
1826 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1827 struct nct6775_data *data = nct6775_update_device(dev);
1828 int nr = data->BEEP_BITS[sattr->index];
1829
1830 return sprintf(buf, "%u\n",
1831 (unsigned int)((data->beeps >> nr) & 0x01));
1832}
1833
1834static ssize_t
1835store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1836 size_t count)
1837{
1838 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1839 struct nct6775_data *data = dev_get_drvdata(dev);
1840 int nr = data->BEEP_BITS[sattr->index];
1841 int regindex = nr >> 3;
1842 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001843 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001844
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001845 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001846 if (err < 0)
1847 return err;
1848 if (val > 1)
1849 return -EINVAL;
1850
1851 mutex_lock(&data->update_lock);
1852 if (val)
1853 data->beeps |= (1ULL << nr);
1854 else
1855 data->beeps &= ~(1ULL << nr);
1856 nct6775_write_value(data, data->REG_BEEP[regindex],
1857 (data->beeps >> (regindex << 3)) & 0xff);
1858 mutex_unlock(&data->update_lock);
1859 return count;
1860}
1861
1862static ssize_t
1863show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1864{
1865 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1866 struct nct6775_data *data = nct6775_update_device(dev);
1867 unsigned int beep = 0;
1868 int nr;
1869
1870 /*
1871 * For temperatures, there is no fixed mapping from registers to beep
1872 * enable bits. Beep enable bits are determined by the temperature
1873 * source mapping.
1874 */
1875 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1876 if (nr >= 0) {
1877 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001878
Guenter Roeck30846992013-06-24 22:21:59 -07001879 beep = (data->beeps >> bit) & 0x01;
1880 }
1881 return sprintf(buf, "%u\n", beep);
1882}
1883
1884static ssize_t
1885store_temp_beep(struct device *dev, struct device_attribute *attr,
1886 const char *buf, size_t count)
1887{
1888 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1889 struct nct6775_data *data = dev_get_drvdata(dev);
1890 int nr, bit, regindex;
1891 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001892 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001893
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001894 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001895 if (err < 0)
1896 return err;
1897 if (val > 1)
1898 return -EINVAL;
1899
1900 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1901 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001902 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001903
1904 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1905 regindex = bit >> 3;
1906
1907 mutex_lock(&data->update_lock);
1908 if (val)
1909 data->beeps |= (1ULL << bit);
1910 else
1911 data->beeps &= ~(1ULL << bit);
1912 nct6775_write_value(data, data->REG_BEEP[regindex],
1913 (data->beeps >> (regindex << 3)) & 0xff);
1914 mutex_unlock(&data->update_lock);
1915
1916 return count;
1917}
1918
Guenter Roeckf73cf632013-03-18 09:22:50 -07001919static umode_t nct6775_in_is_visible(struct kobject *kobj,
1920 struct attribute *attr, int index)
1921{
1922 struct device *dev = container_of(kobj, struct device, kobj);
1923 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001924 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001925
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001926 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001927 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001928
Guenter Roeckf73cf632013-03-18 09:22:50 -07001929 return attr->mode;
1930}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001931
Guenter Roeckf73cf632013-03-18 09:22:50 -07001932SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1933SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001934SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1935 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001936SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1937 store_in_reg, 0, 1);
1938SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1939 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001940
Guenter Roeckf73cf632013-03-18 09:22:50 -07001941/*
1942 * nct6775_in_is_visible uses the index into the following array
1943 * to determine if attributes should be created or not.
1944 * Any change in order or content must be matched.
1945 */
1946static struct sensor_device_template *nct6775_attributes_in_template[] = {
1947 &sensor_dev_template_in_input,
1948 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001949 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001950 &sensor_dev_template_in_min,
1951 &sensor_dev_template_in_max,
1952 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001953};
1954
Julia Lawallc60fdf82015-12-12 17:36:39 +01001955static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001956 .templates = nct6775_attributes_in_template,
1957 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001958};
1959
1960static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001961show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1962{
1963 struct nct6775_data *data = nct6775_update_device(dev);
1964 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1965 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001966
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001967 return sprintf(buf, "%d\n", data->rpm[nr]);
1968}
1969
1970static ssize_t
1971show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1972{
1973 struct nct6775_data *data = nct6775_update_device(dev);
1974 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1975 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001976
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001977 return sprintf(buf, "%d\n",
1978 data->fan_from_reg_min(data->fan_min[nr],
1979 data->fan_div[nr]));
1980}
1981
1982static ssize_t
1983show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1984{
1985 struct nct6775_data *data = nct6775_update_device(dev);
1986 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1987 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001988
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001989 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1990}
1991
1992static ssize_t
1993store_fan_min(struct device *dev, struct device_attribute *attr,
1994 const char *buf, size_t count)
1995{
1996 struct nct6775_data *data = dev_get_drvdata(dev);
1997 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1998 int nr = sattr->index;
1999 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002000 unsigned int reg;
2001 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002002 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002003
2004 err = kstrtoul(buf, 10, &val);
2005 if (err < 0)
2006 return err;
2007
2008 mutex_lock(&data->update_lock);
2009 if (!data->has_fan_div) {
2010 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
2011 if (!val) {
2012 val = 0xff1f;
2013 } else {
2014 if (val > 1350000U)
2015 val = 135000U;
2016 val = 1350000U / val;
2017 val = (val & 0x1f) | ((val << 3) & 0xff00);
2018 }
2019 data->fan_min[nr] = val;
2020 goto write_min; /* Leave fan divider alone */
2021 }
2022 if (!val) {
2023 /* No min limit, alarm disabled */
2024 data->fan_min[nr] = 255;
2025 new_div = data->fan_div[nr]; /* No change */
2026 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
2027 goto write_div;
2028 }
2029 reg = 1350000U / val;
2030 if (reg >= 128 * 255) {
2031 /*
2032 * Speed below this value cannot possibly be represented,
2033 * even with the highest divider (128)
2034 */
2035 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002036 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002037 dev_warn(dev,
2038 "fan%u low limit %lu below minimum %u, set to minimum\n",
2039 nr + 1, val, data->fan_from_reg_min(254, 7));
2040 } else if (!reg) {
2041 /*
2042 * Speed above this value cannot possibly be represented,
2043 * even with the lowest divider (1)
2044 */
2045 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002046 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002047 dev_warn(dev,
2048 "fan%u low limit %lu above maximum %u, set to maximum\n",
2049 nr + 1, val, data->fan_from_reg_min(1, 0));
2050 } else {
2051 /*
2052 * Automatically pick the best divider, i.e. the one such
2053 * that the min limit will correspond to a register value
2054 * in the 96..192 range
2055 */
2056 new_div = 0;
2057 while (reg > 192 && new_div < 7) {
2058 reg >>= 1;
2059 new_div++;
2060 }
2061 data->fan_min[nr] = reg;
2062 }
2063
2064write_div:
2065 /*
2066 * Write both the fan clock divider (if it changed) and the new
2067 * fan min (unconditionally)
2068 */
2069 if (new_div != data->fan_div[nr]) {
2070 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2071 nr + 1, div_from_reg(data->fan_div[nr]),
2072 div_from_reg(new_div));
2073 data->fan_div[nr] = new_div;
2074 nct6775_write_fan_div_common(data, nr);
2075 /* Give the chip time to sample a new speed value */
2076 data->last_updated = jiffies;
2077 }
2078
2079write_min:
2080 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2081 mutex_unlock(&data->update_lock);
2082
2083 return count;
2084}
2085
Guenter Roeck5c25d952012-12-11 07:29:06 -08002086static ssize_t
2087show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2088{
2089 struct nct6775_data *data = nct6775_update_device(dev);
2090 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2091 int p = data->fan_pulses[sattr->index];
2092
2093 return sprintf(buf, "%d\n", p ? : 4);
2094}
2095
2096static ssize_t
2097store_fan_pulses(struct device *dev, struct device_attribute *attr,
2098 const char *buf, size_t count)
2099{
2100 struct nct6775_data *data = dev_get_drvdata(dev);
2101 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2102 int nr = sattr->index;
2103 unsigned long val;
2104 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002105 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002106
2107 err = kstrtoul(buf, 10, &val);
2108 if (err < 0)
2109 return err;
2110
2111 if (val > 4)
2112 return -EINVAL;
2113
2114 mutex_lock(&data->update_lock);
2115 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002116 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2117 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2118 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2119 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002120 mutex_unlock(&data->update_lock);
2121
2122 return count;
2123}
2124
Guenter Roeckf73cf632013-03-18 09:22:50 -07002125static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2126 struct attribute *attr, int index)
2127{
2128 struct device *dev = container_of(kobj, struct device, kobj);
2129 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002130 int fan = index / 6; /* fan index */
2131 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002132
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002133 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002134 return 0;
2135
2136 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2137 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002138 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002139 return 0;
Guenter Roeck81820052018-02-21 13:09:39 -08002140 if (nr == 3 && !data->REG_FAN_PULSES[fan])
2141 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002142 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002143 return 0;
2144 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002145 return 0;
2146
2147 return attr->mode;
2148}
2149
2150SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2151SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2152 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002153SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2154 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002155SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2156 store_fan_pulses, 0);
2157SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2158 store_fan_min, 0);
2159SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2160
2161/*
2162 * nct6775_fan_is_visible uses the index into the following array
2163 * to determine if attributes should be created or not.
2164 * Any change in order or content must be matched.
2165 */
2166static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2167 &sensor_dev_template_fan_input,
2168 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002169 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002170 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002171 &sensor_dev_template_fan_min, /* 4 */
2172 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002173 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002174};
2175
Julia Lawallc60fdf82015-12-12 17:36:39 +01002176static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002177 .templates = nct6775_attributes_fan_template,
2178 .is_visible = nct6775_fan_is_visible,
2179 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002180};
2181
2182static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002183show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2184{
2185 struct nct6775_data *data = nct6775_update_device(dev);
2186 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2187 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002188
Guenter Roeckaa136e52012-12-04 03:26:05 -08002189 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2190}
2191
2192static ssize_t
2193show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2194{
2195 struct nct6775_data *data = nct6775_update_device(dev);
2196 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2197 int nr = sattr->nr;
2198 int index = sattr->index;
2199
2200 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2201}
2202
2203static ssize_t
2204store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2205 size_t count)
2206{
2207 struct nct6775_data *data = dev_get_drvdata(dev);
2208 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2209 int nr = sattr->nr;
2210 int index = sattr->index;
2211 int err;
2212 long val;
2213
2214 err = kstrtol(buf, 10, &val);
2215 if (err < 0)
2216 return err;
2217
2218 mutex_lock(&data->update_lock);
2219 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2220 nct6775_write_temp(data, data->reg_temp[index][nr],
2221 data->temp[index][nr]);
2222 mutex_unlock(&data->update_lock);
2223 return count;
2224}
2225
2226static ssize_t
2227show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2228{
2229 struct nct6775_data *data = nct6775_update_device(dev);
2230 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2231
2232 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2233}
2234
2235static ssize_t
2236store_temp_offset(struct device *dev, struct device_attribute *attr,
2237 const char *buf, size_t count)
2238{
2239 struct nct6775_data *data = dev_get_drvdata(dev);
2240 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2241 int nr = sattr->index;
2242 long val;
2243 int err;
2244
2245 err = kstrtol(buf, 10, &val);
2246 if (err < 0)
2247 return err;
2248
2249 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2250
2251 mutex_lock(&data->update_lock);
2252 data->temp_offset[nr] = val;
2253 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2254 mutex_unlock(&data->update_lock);
2255
2256 return count;
2257}
2258
2259static ssize_t
2260show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2261{
2262 struct nct6775_data *data = nct6775_update_device(dev);
2263 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2264 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002265
Guenter Roeckaa136e52012-12-04 03:26:05 -08002266 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2267}
2268
2269static ssize_t
2270store_temp_type(struct device *dev, struct device_attribute *attr,
2271 const char *buf, size_t count)
2272{
2273 struct nct6775_data *data = nct6775_update_device(dev);
2274 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2275 int nr = sattr->index;
2276 unsigned long val;
2277 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002278 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002279
2280 err = kstrtoul(buf, 10, &val);
2281 if (err < 0)
2282 return err;
2283
2284 if (val != 1 && val != 3 && val != 4)
2285 return -EINVAL;
2286
2287 mutex_lock(&data->update_lock);
2288
2289 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002290 vbit = 0x02 << nr;
2291 dbit = data->DIODE_MASK << nr;
2292 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2293 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002294 switch (val) {
2295 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002296 vbat |= vbit;
2297 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002298 break;
2299 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002300 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002301 break;
2302 case 4: /* thermistor */
2303 break;
2304 }
2305 nct6775_write_value(data, data->REG_VBAT, vbat);
2306 nct6775_write_value(data, data->REG_DIODE, diode);
2307
2308 mutex_unlock(&data->update_lock);
2309 return count;
2310}
2311
Guenter Roeckf73cf632013-03-18 09:22:50 -07002312static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2313 struct attribute *attr, int index)
2314{
2315 struct device *dev = container_of(kobj, struct device, kobj);
2316 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002317 int temp = index / 10; /* temp index */
2318 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002319
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002320 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002321 return 0;
2322
Guenter Roeckcc66b302017-05-17 18:05:06 -07002323 if (nr == 1 && !data->temp_label)
2324 return 0;
2325
Guenter Roeckf73cf632013-03-18 09:22:50 -07002326 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2327 return 0; /* alarm */
2328
Guenter Roeck30846992013-06-24 22:21:59 -07002329 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2330 return 0; /* beep */
2331
2332 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002333 return 0;
2334
Guenter Roeck30846992013-06-24 22:21:59 -07002335 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002336 return 0;
2337
Guenter Roeck30846992013-06-24 22:21:59 -07002338 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002339 return 0;
2340
Guenter Roeck30846992013-06-24 22:21:59 -07002341 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002342 return 0;
2343
2344 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002345 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002346 return 0;
2347
2348 return attr->mode;
2349}
2350
2351SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2352SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2353SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2354 store_temp, 0, 1);
2355SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2356 show_temp, store_temp, 0, 2);
2357SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2358 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002359SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2360 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002361SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2362 show_temp_offset, store_temp_offset, 0);
2363SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2364 store_temp_type, 0);
2365SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002366SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2367 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002368
2369/*
2370 * nct6775_temp_is_visible uses the index into the following array
2371 * to determine if attributes should be created or not.
2372 * Any change in order or content must be matched.
2373 */
2374static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2375 &sensor_dev_template_temp_input,
2376 &sensor_dev_template_temp_label,
2377 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002378 &sensor_dev_template_temp_beep, /* 3 */
2379 &sensor_dev_template_temp_max, /* 4 */
2380 &sensor_dev_template_temp_max_hyst, /* 5 */
2381 &sensor_dev_template_temp_crit, /* 6 */
2382 &sensor_dev_template_temp_lcrit, /* 7 */
2383 &sensor_dev_template_temp_offset, /* 8 */
2384 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002385 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002386};
2387
Julia Lawallc60fdf82015-12-12 17:36:39 +01002388static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002389 .templates = nct6775_attributes_temp_template,
2390 .is_visible = nct6775_temp_is_visible,
2391 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002392};
2393
Guenter Roeckaa136e52012-12-04 03:26:05 -08002394static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002395show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2396{
2397 struct nct6775_data *data = nct6775_update_device(dev);
2398 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2399
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002400 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002401}
2402
2403static ssize_t
2404store_pwm_mode(struct device *dev, struct device_attribute *attr,
2405 const char *buf, size_t count)
2406{
2407 struct nct6775_data *data = dev_get_drvdata(dev);
2408 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2409 int nr = sattr->index;
2410 unsigned long val;
2411 int err;
2412 u8 reg;
2413
2414 err = kstrtoul(buf, 10, &val);
2415 if (err < 0)
2416 return err;
2417
2418 if (val > 1)
2419 return -EINVAL;
2420
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002421 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002422 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002423 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002424 return -EINVAL;
2425 return count;
2426 }
2427
2428 mutex_lock(&data->update_lock);
2429 data->pwm_mode[nr] = val;
2430 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2431 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002432 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002433 reg |= data->PWM_MODE_MASK[nr];
2434 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2435 mutex_unlock(&data->update_lock);
2436 return count;
2437}
2438
2439static ssize_t
2440show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2441{
2442 struct nct6775_data *data = nct6775_update_device(dev);
2443 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2444 int nr = sattr->nr;
2445 int index = sattr->index;
2446 int pwm;
2447
2448 /*
2449 * For automatic fan control modes, show current pwm readings.
2450 * Otherwise, show the configured value.
2451 */
2452 if (index == 0 && data->pwm_enable[nr] > manual)
2453 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2454 else
2455 pwm = data->pwm[index][nr];
2456
2457 return sprintf(buf, "%d\n", pwm);
2458}
2459
2460static ssize_t
2461store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2462 size_t count)
2463{
2464 struct nct6775_data *data = dev_get_drvdata(dev);
2465 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2466 int nr = sattr->nr;
2467 int index = sattr->index;
2468 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002469 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2470 int maxval[7]
2471 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002472 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002473 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002474
2475 err = kstrtoul(buf, 10, &val);
2476 if (err < 0)
2477 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002478 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002479
2480 mutex_lock(&data->update_lock);
2481 data->pwm[index][nr] = val;
2482 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002483 if (index == 2) { /* floor: disable if val == 0 */
2484 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2485 reg &= 0x7f;
2486 if (val)
2487 reg |= 0x80;
2488 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2489 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002490 mutex_unlock(&data->update_lock);
2491 return count;
2492}
2493
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002494/* Returns 0 if OK, -EINVAL otherwise */
2495static int check_trip_points(struct nct6775_data *data, int nr)
2496{
2497 int i;
2498
2499 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2500 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2501 return -EINVAL;
2502 }
2503 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2504 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2505 return -EINVAL;
2506 }
2507 /* validate critical temperature and pwm if enabled (pwm > 0) */
2508 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2509 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2510 data->auto_temp[nr][data->auto_pwm_num] ||
2511 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2512 data->auto_pwm[nr][data->auto_pwm_num])
2513 return -EINVAL;
2514 }
2515 return 0;
2516}
2517
2518static void pwm_update_registers(struct nct6775_data *data, int nr)
2519{
2520 u8 reg;
2521
2522 switch (data->pwm_enable[nr]) {
2523 case off:
2524 case manual:
2525 break;
2526 case speed_cruise:
2527 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2528 reg = (reg & ~data->tolerance_mask) |
2529 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2530 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2531 nct6775_write_value(data, data->REG_TARGET[nr],
2532 data->target_speed[nr] & 0xff);
2533 if (data->REG_TOLERANCE_H) {
2534 reg = (data->target_speed[nr] >> 8) & 0x0f;
2535 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2536 nct6775_write_value(data,
2537 data->REG_TOLERANCE_H[nr],
2538 reg);
2539 }
2540 break;
2541 case thermal_cruise:
2542 nct6775_write_value(data, data->REG_TARGET[nr],
2543 data->target_temp[nr]);
2544 /* intentional */
2545 default:
2546 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2547 reg = (reg & ~data->tolerance_mask) |
2548 data->temp_tolerance[0][nr];
2549 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2550 break;
2551 }
2552}
2553
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002554static ssize_t
2555show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2556{
2557 struct nct6775_data *data = nct6775_update_device(dev);
2558 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2559
2560 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2561}
2562
2563static ssize_t
2564store_pwm_enable(struct device *dev, struct device_attribute *attr,
2565 const char *buf, size_t count)
2566{
2567 struct nct6775_data *data = dev_get_drvdata(dev);
2568 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2569 int nr = sattr->index;
2570 unsigned long val;
2571 int err;
2572 u16 reg;
2573
2574 err = kstrtoul(buf, 10, &val);
2575 if (err < 0)
2576 return err;
2577
2578 if (val > sf4)
2579 return -EINVAL;
2580
2581 if (val == sf3 && data->kind != nct6775)
2582 return -EINVAL;
2583
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002584 if (val == sf4 && check_trip_points(data, nr)) {
2585 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2586 dev_err(dev, "Adjust trip points and try again\n");
2587 return -EINVAL;
2588 }
2589
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002590 mutex_lock(&data->update_lock);
2591 data->pwm_enable[nr] = val;
2592 if (val == off) {
2593 /*
2594 * turn off pwm control: select manual mode, set pwm to maximum
2595 */
2596 data->pwm[0][nr] = 255;
2597 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2598 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002599 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002600 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2601 reg &= 0x0f;
2602 reg |= pwm_enable_to_reg(val) << 4;
2603 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2604 mutex_unlock(&data->update_lock);
2605 return count;
2606}
2607
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002608static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002609show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002610{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002611 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002612
2613 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002614 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002615 continue;
2616 if (src == data->temp_src[i]) {
2617 sel = i + 1;
2618 break;
2619 }
2620 }
2621
2622 return sprintf(buf, "%d\n", sel);
2623}
2624
2625static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002626show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2627{
2628 struct nct6775_data *data = nct6775_update_device(dev);
2629 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2630 int index = sattr->index;
2631
2632 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2633}
2634
2635static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002636store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2637 const char *buf, size_t count)
2638{
2639 struct nct6775_data *data = nct6775_update_device(dev);
2640 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2641 int nr = sattr->index;
2642 unsigned long val;
2643 int err, reg, src;
2644
2645 err = kstrtoul(buf, 10, &val);
2646 if (err < 0)
2647 return err;
2648 if (val == 0 || val > NUM_TEMP)
2649 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002650 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002651 return -EINVAL;
2652
2653 mutex_lock(&data->update_lock);
2654 src = data->temp_src[val - 1];
2655 data->pwm_temp_sel[nr] = src;
2656 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2657 reg &= 0xe0;
2658 reg |= src;
2659 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2660 mutex_unlock(&data->update_lock);
2661
2662 return count;
2663}
2664
2665static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002666show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2667 char *buf)
2668{
2669 struct nct6775_data *data = nct6775_update_device(dev);
2670 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2671 int index = sattr->index;
2672
2673 return show_pwm_temp_sel_common(data, buf,
2674 data->pwm_weight_temp_sel[index]);
2675}
2676
2677static ssize_t
2678store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2679 const char *buf, size_t count)
2680{
2681 struct nct6775_data *data = nct6775_update_device(dev);
2682 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2683 int nr = sattr->index;
2684 unsigned long val;
2685 int err, reg, src;
2686
2687 err = kstrtoul(buf, 10, &val);
2688 if (err < 0)
2689 return err;
2690 if (val > NUM_TEMP)
2691 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002692 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002693 !data->temp_src[val - 1]))
2694 return -EINVAL;
2695
2696 mutex_lock(&data->update_lock);
2697 if (val) {
2698 src = data->temp_src[val - 1];
2699 data->pwm_weight_temp_sel[nr] = src;
2700 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2701 reg &= 0xe0;
2702 reg |= (src | 0x80);
2703 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2704 } else {
2705 data->pwm_weight_temp_sel[nr] = 0;
2706 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2707 reg &= 0x7f;
2708 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2709 }
2710 mutex_unlock(&data->update_lock);
2711
2712 return count;
2713}
2714
2715static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002716show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2717{
2718 struct nct6775_data *data = nct6775_update_device(dev);
2719 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2720
2721 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2722}
2723
2724static ssize_t
2725store_target_temp(struct device *dev, struct device_attribute *attr,
2726 const char *buf, size_t count)
2727{
2728 struct nct6775_data *data = dev_get_drvdata(dev);
2729 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2730 int nr = sattr->index;
2731 unsigned long val;
2732 int err;
2733
2734 err = kstrtoul(buf, 10, &val);
2735 if (err < 0)
2736 return err;
2737
2738 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2739 data->target_temp_mask);
2740
2741 mutex_lock(&data->update_lock);
2742 data->target_temp[nr] = val;
2743 pwm_update_registers(data, nr);
2744 mutex_unlock(&data->update_lock);
2745 return count;
2746}
2747
2748static ssize_t
2749show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2750{
2751 struct nct6775_data *data = nct6775_update_device(dev);
2752 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2753 int nr = sattr->index;
2754
2755 return sprintf(buf, "%d\n",
2756 fan_from_reg16(data->target_speed[nr],
2757 data->fan_div[nr]));
2758}
2759
2760static ssize_t
2761store_target_speed(struct device *dev, struct device_attribute *attr,
2762 const char *buf, size_t count)
2763{
2764 struct nct6775_data *data = dev_get_drvdata(dev);
2765 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2766 int nr = sattr->index;
2767 unsigned long val;
2768 int err;
2769 u16 speed;
2770
2771 err = kstrtoul(buf, 10, &val);
2772 if (err < 0)
2773 return err;
2774
2775 val = clamp_val(val, 0, 1350000U);
2776 speed = fan_to_reg(val, data->fan_div[nr]);
2777
2778 mutex_lock(&data->update_lock);
2779 data->target_speed[nr] = speed;
2780 pwm_update_registers(data, nr);
2781 mutex_unlock(&data->update_lock);
2782 return count;
2783}
2784
2785static ssize_t
2786show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2787 char *buf)
2788{
2789 struct nct6775_data *data = nct6775_update_device(dev);
2790 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2791 int nr = sattr->nr;
2792 int index = sattr->index;
2793
2794 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2795}
2796
2797static ssize_t
2798store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2799 const char *buf, size_t count)
2800{
2801 struct nct6775_data *data = dev_get_drvdata(dev);
2802 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2803 int nr = sattr->nr;
2804 int index = sattr->index;
2805 unsigned long val;
2806 int err;
2807
2808 err = kstrtoul(buf, 10, &val);
2809 if (err < 0)
2810 return err;
2811
2812 /* Limit tolerance as needed */
2813 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2814
2815 mutex_lock(&data->update_lock);
2816 data->temp_tolerance[index][nr] = val;
2817 if (index)
2818 pwm_update_registers(data, nr);
2819 else
2820 nct6775_write_value(data,
2821 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2822 val);
2823 mutex_unlock(&data->update_lock);
2824 return count;
2825}
2826
2827/*
2828 * Fan speed tolerance is a tricky beast, since the associated register is
2829 * a tick counter, but the value is reported and configured as rpm.
2830 * Compute resulting low and high rpm values and report the difference.
2831 */
2832static ssize_t
2833show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2834 char *buf)
2835{
2836 struct nct6775_data *data = nct6775_update_device(dev);
2837 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2838 int nr = sattr->index;
2839 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2840 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2841 int tolerance;
2842
2843 if (low <= 0)
2844 low = 1;
2845 if (high > 0xffff)
2846 high = 0xffff;
2847 if (high < low)
2848 high = low;
2849
2850 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2851 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2852
2853 return sprintf(buf, "%d\n", tolerance);
2854}
2855
2856static ssize_t
2857store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2858 const char *buf, size_t count)
2859{
2860 struct nct6775_data *data = dev_get_drvdata(dev);
2861 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2862 int nr = sattr->index;
2863 unsigned long val;
2864 int err;
2865 int low, high;
2866
2867 err = kstrtoul(buf, 10, &val);
2868 if (err < 0)
2869 return err;
2870
2871 high = fan_from_reg16(data->target_speed[nr],
2872 data->fan_div[nr]) + val;
2873 low = fan_from_reg16(data->target_speed[nr],
2874 data->fan_div[nr]) - val;
2875 if (low <= 0)
2876 low = 1;
2877 if (high < low)
2878 high = low;
2879
2880 val = (fan_to_reg(low, data->fan_div[nr]) -
2881 fan_to_reg(high, data->fan_div[nr])) / 2;
2882
2883 /* Limit tolerance as needed */
2884 val = clamp_val(val, 0, data->speed_tolerance_limit);
2885
2886 mutex_lock(&data->update_lock);
2887 data->target_speed_tolerance[nr] = val;
2888 pwm_update_registers(data, nr);
2889 mutex_unlock(&data->update_lock);
2890 return count;
2891}
2892
Guenter Roeckf73cf632013-03-18 09:22:50 -07002893SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2894SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2895 store_pwm_mode, 0);
2896SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2897 store_pwm_enable, 0);
2898SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2899 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2900SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2901 show_target_temp, store_target_temp, 0);
2902SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2903 show_target_speed, store_target_speed, 0);
2904SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2905 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002906
2907/* Smart Fan registers */
2908
2909static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002910show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2911{
2912 struct nct6775_data *data = nct6775_update_device(dev);
2913 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2914 int nr = sattr->nr;
2915 int index = sattr->index;
2916
2917 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2918}
2919
2920static ssize_t
2921store_weight_temp(struct device *dev, struct device_attribute *attr,
2922 const char *buf, size_t count)
2923{
2924 struct nct6775_data *data = dev_get_drvdata(dev);
2925 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2926 int nr = sattr->nr;
2927 int index = sattr->index;
2928 unsigned long val;
2929 int err;
2930
2931 err = kstrtoul(buf, 10, &val);
2932 if (err < 0)
2933 return err;
2934
2935 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2936
2937 mutex_lock(&data->update_lock);
2938 data->weight_temp[index][nr] = val;
2939 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2940 mutex_unlock(&data->update_lock);
2941 return count;
2942}
2943
Guenter Roeckf73cf632013-03-18 09:22:50 -07002944SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2945 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2946SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2947 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2948SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2949 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2950SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2951 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2952SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2953 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2954SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2955 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002956
2957static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002958show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2959{
2960 struct nct6775_data *data = nct6775_update_device(dev);
2961 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2962 int nr = sattr->nr;
2963 int index = sattr->index;
2964
2965 return sprintf(buf, "%d\n",
2966 step_time_from_reg(data->fan_time[index][nr],
2967 data->pwm_mode[nr]));
2968}
2969
2970static ssize_t
2971store_fan_time(struct device *dev, struct device_attribute *attr,
2972 const char *buf, size_t count)
2973{
2974 struct nct6775_data *data = dev_get_drvdata(dev);
2975 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2976 int nr = sattr->nr;
2977 int index = sattr->index;
2978 unsigned long val;
2979 int err;
2980
2981 err = kstrtoul(buf, 10, &val);
2982 if (err < 0)
2983 return err;
2984
2985 val = step_time_to_reg(val, data->pwm_mode[nr]);
2986 mutex_lock(&data->update_lock);
2987 data->fan_time[index][nr] = val;
2988 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2989 mutex_unlock(&data->update_lock);
2990 return count;
2991}
2992
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002993static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002994show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2995{
2996 struct nct6775_data *data = nct6775_update_device(dev);
2997 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2998
2999 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3000}
3001
3002static ssize_t
3003store_auto_pwm(struct device *dev, struct device_attribute *attr,
3004 const char *buf, size_t count)
3005{
3006 struct nct6775_data *data = dev_get_drvdata(dev);
3007 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3008 int nr = sattr->nr;
3009 int point = sattr->index;
3010 unsigned long val;
3011 int err;
3012 u8 reg;
3013
3014 err = kstrtoul(buf, 10, &val);
3015 if (err < 0)
3016 return err;
3017 if (val > 255)
3018 return -EINVAL;
3019
3020 if (point == data->auto_pwm_num) {
3021 if (data->kind != nct6775 && !val)
3022 return -EINVAL;
3023 if (data->kind != nct6779 && val)
3024 val = 0xff;
3025 }
3026
3027 mutex_lock(&data->update_lock);
3028 data->auto_pwm[nr][point] = val;
3029 if (point < data->auto_pwm_num) {
3030 nct6775_write_value(data,
3031 NCT6775_AUTO_PWM(data, nr, point),
3032 data->auto_pwm[nr][point]);
3033 } else {
3034 switch (data->kind) {
3035 case nct6775:
3036 /* disable if needed (pwm == 0) */
3037 reg = nct6775_read_value(data,
3038 NCT6775_REG_CRITICAL_ENAB[nr]);
3039 if (val)
3040 reg |= 0x02;
3041 else
3042 reg &= ~0x02;
3043 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3044 reg);
3045 break;
3046 case nct6776:
3047 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003048 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003049 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003050 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003051 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003052 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003053 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003054 case nct6796:
Guenter Roeck6c009502012-07-01 08:23:15 -07003055 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003056 val);
3057 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003058 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003059 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003060 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003061 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003062 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003063 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003064 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003065 reg);
3066 break;
3067 }
3068 }
3069 mutex_unlock(&data->update_lock);
3070 return count;
3071}
3072
3073static ssize_t
3074show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3075{
3076 struct nct6775_data *data = nct6775_update_device(dev);
3077 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3078 int nr = sattr->nr;
3079 int point = sattr->index;
3080
3081 /*
3082 * We don't know for sure if the temperature is signed or unsigned.
3083 * Assume it is unsigned.
3084 */
3085 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3086}
3087
3088static ssize_t
3089store_auto_temp(struct device *dev, struct device_attribute *attr,
3090 const char *buf, size_t count)
3091{
3092 struct nct6775_data *data = dev_get_drvdata(dev);
3093 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3094 int nr = sattr->nr;
3095 int point = sattr->index;
3096 unsigned long val;
3097 int err;
3098
3099 err = kstrtoul(buf, 10, &val);
3100 if (err)
3101 return err;
3102 if (val > 255000)
3103 return -EINVAL;
3104
3105 mutex_lock(&data->update_lock);
3106 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3107 if (point < data->auto_pwm_num) {
3108 nct6775_write_value(data,
3109 NCT6775_AUTO_TEMP(data, nr, point),
3110 data->auto_temp[nr][point]);
3111 } else {
3112 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3113 data->auto_temp[nr][point]);
3114 }
3115 mutex_unlock(&data->update_lock);
3116 return count;
3117}
3118
Guenter Roeckf73cf632013-03-18 09:22:50 -07003119static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3120 struct attribute *attr, int index)
3121{
3122 struct device *dev = container_of(kobj, struct device, kobj);
3123 struct nct6775_data *data = dev_get_drvdata(dev);
3124 int pwm = index / 36; /* pwm index */
3125 int nr = index % 36; /* attribute index */
3126
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003127 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003128 return 0;
3129
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003130 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3131 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3132 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003133 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3134 return 0;
3135 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3136 return 0;
3137 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3138 return 0;
3139
3140 if (nr >= 22 && nr <= 35) { /* auto point */
3141 int api = (nr - 22) / 2; /* auto point index */
3142
3143 if (api > data->auto_pwm_num)
3144 return 0;
3145 }
3146 return attr->mode;
3147}
3148
3149SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3150 show_fan_time, store_fan_time, 0, 0);
3151SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3152 show_fan_time, store_fan_time, 0, 1);
3153SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3154 show_fan_time, store_fan_time, 0, 2);
3155SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3156 store_pwm, 0, 1);
3157SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3158 store_pwm, 0, 2);
3159SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3160 show_temp_tolerance, store_temp_tolerance, 0, 0);
3161SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3162 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3163 0, 1);
3164
3165SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3166 0, 3);
3167
3168SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3169 store_pwm, 0, 4);
3170
3171SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3172 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3173SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3174 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3175
3176SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3177 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3178SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3179 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3180
3181SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3182 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3183SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3184 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3185
3186SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3187 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3188SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3189 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3190
3191SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3192 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3193SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3194 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3195
3196SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3197 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3198SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3199 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3200
3201SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3202 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3203SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3204 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3205
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003206/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003207 * nct6775_pwm_is_visible uses the index into the following array
3208 * to determine if attributes should be created or not.
3209 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003210 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003211static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3212 &sensor_dev_template_pwm,
3213 &sensor_dev_template_pwm_mode,
3214 &sensor_dev_template_pwm_enable,
3215 &sensor_dev_template_pwm_temp_sel,
3216 &sensor_dev_template_pwm_temp_tolerance,
3217 &sensor_dev_template_pwm_crit_temp_tolerance,
3218 &sensor_dev_template_pwm_target_temp,
3219 &sensor_dev_template_fan_target,
3220 &sensor_dev_template_fan_tolerance,
3221 &sensor_dev_template_pwm_stop_time,
3222 &sensor_dev_template_pwm_step_up_time,
3223 &sensor_dev_template_pwm_step_down_time,
3224 &sensor_dev_template_pwm_start,
3225 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003226 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003227 &sensor_dev_template_pwm_weight_temp_step,
3228 &sensor_dev_template_pwm_weight_temp_step_tol,
3229 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003230 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003231 &sensor_dev_template_pwm_max, /* 19 */
3232 &sensor_dev_template_pwm_step, /* 20 */
3233 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3234 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3235 &sensor_dev_template_pwm_auto_point1_temp,
3236 &sensor_dev_template_pwm_auto_point2_pwm,
3237 &sensor_dev_template_pwm_auto_point2_temp,
3238 &sensor_dev_template_pwm_auto_point3_pwm,
3239 &sensor_dev_template_pwm_auto_point3_temp,
3240 &sensor_dev_template_pwm_auto_point4_pwm,
3241 &sensor_dev_template_pwm_auto_point4_temp,
3242 &sensor_dev_template_pwm_auto_point5_pwm,
3243 &sensor_dev_template_pwm_auto_point5_temp,
3244 &sensor_dev_template_pwm_auto_point6_pwm,
3245 &sensor_dev_template_pwm_auto_point6_temp,
3246 &sensor_dev_template_pwm_auto_point7_pwm,
3247 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003248
Guenter Roeckf73cf632013-03-18 09:22:50 -07003249 NULL
3250};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003251
Julia Lawallc60fdf82015-12-12 17:36:39 +01003252static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003253 .templates = nct6775_attributes_pwm_template,
3254 .is_visible = nct6775_pwm_is_visible,
3255 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003256};
3257
3258static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003259cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003260{
3261 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003262
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003263 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3264}
3265
Julia Lawall93d72ac2016-12-22 13:05:23 +01003266static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003267
Guenter Roecka6bd5872012-12-04 03:13:34 -08003268/* Case open detection */
3269
3270static ssize_t
3271clear_caseopen(struct device *dev, struct device_attribute *attr,
3272 const char *buf, size_t count)
3273{
3274 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003275 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3276 unsigned long val;
3277 u8 reg;
3278 int ret;
3279
3280 if (kstrtoul(buf, 10, &val) || val != 0)
3281 return -EINVAL;
3282
3283 mutex_lock(&data->update_lock);
3284
3285 /*
3286 * Use CR registers to clear caseopen status.
3287 * The CR registers are the same for all chips, and not all chips
3288 * support clearing the caseopen status through "regular" registers.
3289 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003290 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003291 if (ret) {
3292 count = ret;
3293 goto error;
3294 }
3295
Guenter Roeckdf612d52013-07-08 13:15:04 -07003296 superio_select(data->sioreg, NCT6775_LD_ACPI);
3297 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003298 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003299 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003300 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003301 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3302 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003303
3304 data->valid = false; /* Force cache refresh */
3305error:
3306 mutex_unlock(&data->update_lock);
3307 return count;
3308}
3309
Guenter Roeckf73cf632013-03-18 09:22:50 -07003310static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3311 clear_caseopen, INTRUSION_ALARM_BASE);
3312static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3313 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003314static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3315 store_beep, INTRUSION_ALARM_BASE);
3316static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3317 store_beep, INTRUSION_ALARM_BASE + 1);
3318static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3319 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003320
3321static umode_t nct6775_other_is_visible(struct kobject *kobj,
3322 struct attribute *attr, int index)
3323{
3324 struct device *dev = container_of(kobj, struct device, kobj);
3325 struct nct6775_data *data = dev_get_drvdata(dev);
3326
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003327 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003328 return 0;
3329
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003330 if (index == 1 || index == 2) {
3331 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003332 return 0;
3333 }
3334
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003335 if (index == 3 || index == 4) {
3336 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003337 return 0;
3338 }
3339
Guenter Roeckf73cf632013-03-18 09:22:50 -07003340 return attr->mode;
3341}
3342
3343/*
3344 * nct6775_other_is_visible uses the index into the following array
3345 * to determine if attributes should be created or not.
3346 * Any change in order or content must be matched.
3347 */
3348static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003349 &dev_attr_cpu0_vid.attr, /* 0 */
3350 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3351 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3352 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3353 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3354 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003355
3356 NULL
3357};
3358
3359static const struct attribute_group nct6775_group_other = {
3360 .attrs = nct6775_attributes_other,
3361 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003362};
3363
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003364static inline void nct6775_init_device(struct nct6775_data *data)
3365{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003366 int i;
3367 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003368
3369 /* Start monitoring if needed */
3370 if (data->REG_CONFIG) {
3371 tmp = nct6775_read_value(data, data->REG_CONFIG);
3372 if (!(tmp & 0x01))
3373 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3374 }
3375
Guenter Roeckaa136e52012-12-04 03:26:05 -08003376 /* Enable temperature sensors if needed */
3377 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003378 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003379 continue;
3380 if (!data->reg_temp_config[i])
3381 continue;
3382 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3383 if (tmp & 0x01)
3384 nct6775_write_value(data, data->reg_temp_config[i],
3385 tmp & 0xfe);
3386 }
3387
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003388 /* Enable VBAT monitoring if needed */
3389 tmp = nct6775_read_value(data, data->REG_VBAT);
3390 if (!(tmp & 0x01))
3391 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003392
3393 diode = nct6775_read_value(data, data->REG_DIODE);
3394
3395 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003396 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003397 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003398 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3399 data->temp_type[i]
3400 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003401 else /* thermistor */
3402 data->temp_type[i] = 4;
3403 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003404}
3405
Guenter Roeckf73cf632013-03-18 09:22:50 -07003406static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003407nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003408{
Guenter Roeck1b206242018-02-21 13:09:38 -08003409 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003410 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003411 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003412 bool pwm6pin = false, pwm7pin = false;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003413 int sioreg = data->sioreg;
3414 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003415
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003416 /* Store SIO_REG_ENABLE for use during resume */
3417 superio_select(sioreg, NCT6775_LD_HWM);
3418 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3419
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003420 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3421 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003422 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003423
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003424 fan3pin = regval & BIT(6);
3425 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003426
3427 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003428 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003429 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003430 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003431 const char *board_vendor, *board_name;
3432
3433 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3434 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3435
3436 if (board_name && board_vendor &&
3437 !strcmp(board_vendor, "ASRock")) {
3438 /*
3439 * Auxiliary fan monitoring is not enabled on ASRock
3440 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3441 * Observed with BIOS version 2.00.
3442 */
3443 if (!strcmp(board_name, "Z77 Pro4-M")) {
3444 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3445 data->sio_reg_enable |= 0xe0;
3446 superio_outb(sioreg, SIO_REG_ENABLE,
3447 data->sio_reg_enable);
3448 }
3449 }
3450 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003451
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003452 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003453 fan3pin = gpok;
3454 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003455 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003456
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003457 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003458 fan4pin = gpok;
3459 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003460 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003461
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003462 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003463 fan5pin = gpok;
3464 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003465 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003466
3467 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003468 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003469 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003470 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003471 fan3pin = !(regval & 0x80);
3472 pwm3pin = regval & 0x08;
Guenter Roeck81820052018-02-21 13:09:39 -08003473 } else {
3474 /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
3475 int regval_1b, regval_2a, regval_2f;
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003476 bool dsw_en;
Guenter Roecke5c85222017-05-17 18:09:41 -07003477
Guenter Roeckdf612d52013-07-08 13:15:04 -07003478 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003479
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003480 fan3pin = !(regval & BIT(5));
3481 fan4pin = !(regval & BIT(6));
3482 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003483
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003484 pwm3pin = !(regval & BIT(0));
3485 pwm4pin = !(regval & BIT(1));
3486 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003487
Guenter Roecke5c85222017-05-17 18:09:41 -07003488 regval = superio_inb(sioreg, 0x2d);
3489 switch (data->kind) {
3490 case nct6791:
3491 case nct6792:
3492 fan6pin = regval & BIT(1);
3493 pwm6pin = regval & BIT(0);
3494 break;
3495 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003496 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003497 case nct6796:
Guenter Roecke5c85222017-05-17 18:09:41 -07003498 regval_1b = superio_inb(sioreg, 0x1b);
3499 regval_2a = superio_inb(sioreg, 0x2a);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003500 regval_2f = superio_inb(sioreg, 0x2f);
3501 dsw_en = regval_2f & BIT(3);
David Bartley578ab5f2013-06-24 22:28:28 -07003502
Guenter Roecke5c85222017-05-17 18:09:41 -07003503 if (!pwm5pin)
3504 pwm5pin = regval & BIT(7);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003505
Guenter Roecke5c85222017-05-17 18:09:41 -07003506 if (!fan5pin)
3507 fan5pin = regval_1b & BIT(5);
3508
Guenter Roeck81820052018-02-21 13:09:39 -08003509 superio_select(sioreg, NCT6775_LD_12);
3510 if (data->kind != nct6796) {
3511 int regval_eb = superio_inb(sioreg, 0xeb);
3512
3513 if (!dsw_en) {
3514 fan6pin = regval & BIT(1);
3515 pwm6pin = regval & BIT(0);
3516 }
3517
3518 if (!fan5pin)
3519 fan5pin = regval_eb & BIT(5);
3520 if (!pwm5pin)
3521 pwm5pin = (regval_eb & BIT(4)) &&
3522 !(regval_2a & BIT(0));
3523 if (!fan6pin)
3524 fan6pin = regval_eb & BIT(3);
3525 if (!pwm6pin)
3526 pwm6pin = regval_eb & BIT(2);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003527 }
3528
Guenter Roeck81820052018-02-21 13:09:39 -08003529 if (data->kind == nct6795 || data->kind == nct6796) {
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003530 int regval_ed = superio_inb(sioreg, 0xed);
3531
3532 if (!fan6pin)
3533 fan6pin = (regval_2a & BIT(4)) &&
3534 (!dsw_en ||
3535 (dsw_en && (regval_ed & BIT(4))));
3536 if (!pwm6pin)
3537 pwm6pin = (regval_2a & BIT(3)) &&
3538 (regval_ed & BIT(2));
3539 }
Guenter Roeck81820052018-02-21 13:09:39 -08003540
3541 if (data->kind == nct6796) {
3542 int regval_1d = superio_inb(sioreg, 0x1d);
3543 int regval_2b = superio_inb(sioreg, 0x2b);
3544
3545 fan7pin = !(regval_2b & BIT(2));
3546 pwm7pin = !(regval_1d & (BIT(2) | BIT(3)));
3547 }
3548
Guenter Roecke5c85222017-05-17 18:09:41 -07003549 break;
3550 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003551 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003552 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003553
3554 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003555 }
3556
David Bartley578ab5f2013-06-24 22:28:28 -07003557 /* fan 1 and 2 (0x03) are always present */
3558 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003559 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003560 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003561 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003562 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003563 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003564}
3565
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003566static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3567 int *available, int *mask)
3568{
3569 int i;
3570 u8 src;
3571
3572 for (i = 0; i < data->pwm_num && *available; i++) {
3573 int index;
3574
3575 if (!regp[i])
3576 continue;
3577 src = nct6775_read_value(data, regp[i]);
3578 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003579 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003580 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003581 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003582 continue;
3583
3584 index = __ffs(*available);
3585 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003586 *available &= ~BIT(index);
3587 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003588 }
3589}
3590
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003591static int nct6775_probe(struct platform_device *pdev)
3592{
3593 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003594 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003595 struct nct6775_data *data;
3596 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003597 int i, s, err = 0;
3598 int src, mask, available;
3599 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003600 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003601 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003602 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003603 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003604 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003605 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003606 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003607
3608 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3609 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3610 DRVNAME))
3611 return -EBUSY;
3612
3613 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3614 GFP_KERNEL);
3615 if (!data)
3616 return -ENOMEM;
3617
3618 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003619 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003620 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003621 mutex_init(&data->update_lock);
3622 data->name = nct6775_device_names[data->kind];
3623 data->bank = 0xff; /* Force initial bank selection */
3624 platform_set_drvdata(pdev, data);
3625
3626 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003627 case nct6106:
3628 data->in_num = 9;
3629 data->pwm_num = 3;
3630 data->auto_pwm_num = 4;
3631 data->temp_fixed_num = 3;
3632 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003633 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003634
3635 data->fan_from_reg = fan_from_reg13;
3636 data->fan_from_reg_min = fan_from_reg13;
3637
3638 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003639 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003640
3641 data->REG_VBAT = NCT6106_REG_VBAT;
3642 data->REG_DIODE = NCT6106_REG_DIODE;
3643 data->DIODE_MASK = NCT6106_DIODE_MASK;
3644 data->REG_VIN = NCT6106_REG_IN;
3645 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3646 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3647 data->REG_TARGET = NCT6106_REG_TARGET;
3648 data->REG_FAN = NCT6106_REG_FAN;
3649 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3650 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3651 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3652 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3653 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3654 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3655 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3656 data->REG_PWM[0] = NCT6106_REG_PWM;
3657 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3658 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3659 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3660 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3661 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3662 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3663 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3664 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3665 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3666 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3667 data->REG_CRITICAL_TEMP_TOLERANCE
3668 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3669 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3670 data->CRITICAL_PWM_ENABLE_MASK
3671 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3672 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3673 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3674 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3675 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3676 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3677 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3678 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3679 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3680 data->REG_ALARM = NCT6106_REG_ALARM;
3681 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003682 data->REG_BEEP = NCT6106_REG_BEEP;
3683 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003684
3685 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003686 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003687 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003688 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003689 reg_temp_over = NCT6106_REG_TEMP_OVER;
3690 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3691 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3692 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3693 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003694 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3695 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003696
3697 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003698 case nct6775:
3699 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003700 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003701 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003702 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003703 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003704 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003705 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003706
3707 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003708 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003709
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003710 data->fan_from_reg = fan_from_reg16;
3711 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003712 data->target_temp_mask = 0x7f;
3713 data->tolerance_mask = 0x0f;
3714 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003715
Guenter Roeckaa136e52012-12-04 03:26:05 -08003716 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003717 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003718
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003719 data->REG_CONFIG = NCT6775_REG_CONFIG;
3720 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003721 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003722 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003723 data->REG_VIN = NCT6775_REG_IN;
3724 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3725 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003726 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003727 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003728 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003729 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003730 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003731 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003732 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3733 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3734 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003735 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003736 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3737 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3738 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3739 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003740 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003741 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3742 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3743 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003744 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3745 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3746 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3747 data->REG_CRITICAL_TEMP_TOLERANCE
3748 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003749 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3750 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003751 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003752 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3753 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3754 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3755 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003756 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003757 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003758
3759 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003760 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003761 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003762 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003763 reg_temp_over = NCT6775_REG_TEMP_OVER;
3764 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3765 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3766 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3767 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3768
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003769 break;
3770 case nct6776:
3771 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003772 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003773 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003774 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003775 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003776 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003777 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003778
3779 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003780 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003781
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003782 data->fan_from_reg = fan_from_reg13;
3783 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003784 data->target_temp_mask = 0xff;
3785 data->tolerance_mask = 0x07;
3786 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003787
Guenter Roeckaa136e52012-12-04 03:26:05 -08003788 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003789 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003790
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003791 data->REG_CONFIG = NCT6775_REG_CONFIG;
3792 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003793 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003794 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003795 data->REG_VIN = NCT6775_REG_IN;
3796 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3797 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003798 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003799 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003800 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003801 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003802 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003803 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003804 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003805 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3806 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003807 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003808 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003809 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3810 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003811 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3812 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003813 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3814 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3815 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003816 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3817 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3818 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3819 data->REG_CRITICAL_TEMP_TOLERANCE
3820 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003821 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3822 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003823 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003824 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3825 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3826 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3827 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003828 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003829 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003830
3831 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003832 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003833 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003834 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003835 reg_temp_over = NCT6775_REG_TEMP_OVER;
3836 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3837 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3838 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3839 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3840
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003841 break;
3842 case nct6779:
3843 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003844 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003845 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003846 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003847 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003848 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003849 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003850
3851 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003852 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003853
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003854 data->fan_from_reg = fan_from_reg13;
3855 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003856 data->target_temp_mask = 0xff;
3857 data->tolerance_mask = 0x07;
3858 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003859
Guenter Roeckaa136e52012-12-04 03:26:05 -08003860 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003861 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003862
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003863 data->REG_CONFIG = NCT6775_REG_CONFIG;
3864 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003865 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003866 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003867 data->REG_VIN = NCT6779_REG_IN;
3868 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3869 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003870 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003871 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003872 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003873 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003874 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003875 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003876 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003877 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3878 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003879 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003880 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003881 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3882 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003883 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3884 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003885 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3886 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3887 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003888 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3889 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3890 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3891 data->REG_CRITICAL_TEMP_TOLERANCE
3892 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003893 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3894 data->CRITICAL_PWM_ENABLE_MASK
3895 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3896 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003897 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3898 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003899 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003900 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3901 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3902 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3903 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003904 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003905 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003906
3907 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003908 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003909 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003910 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003911 reg_temp_over = NCT6779_REG_TEMP_OVER;
3912 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3913 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3914 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3915 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3916
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003917 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003918 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003919 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003920 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003921 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003922 case nct6796:
David Bartley578ab5f2013-06-24 22:28:28 -07003923 data->in_num = 15;
Guenter Roeck81820052018-02-21 13:09:39 -08003924 data->pwm_num = (data->kind == nct6796) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07003925 data->auto_pwm_num = 4;
3926 data->has_fan_div = false;
3927 data->temp_fixed_num = 6;
3928 data->num_temp_alarms = 2;
3929 data->num_temp_beeps = 2;
3930
3931 data->ALARM_BITS = NCT6791_ALARM_BITS;
3932 data->BEEP_BITS = NCT6779_BEEP_BITS;
3933
3934 data->fan_from_reg = fan_from_reg13;
3935 data->fan_from_reg_min = fan_from_reg13;
3936 data->target_temp_mask = 0xff;
3937 data->tolerance_mask = 0x07;
3938 data->speed_tolerance_limit = 63;
3939
Guenter Roeck50224f42015-10-30 07:52:39 -07003940 switch (data->kind) {
3941 default:
3942 case nct6791:
3943 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003944 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003945 break;
3946 case nct6792:
3947 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003948 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003949 break;
3950 case nct6793:
3951 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003952 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003953 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003954 case nct6795:
3955 data->temp_label = nct6795_temp_label;
3956 data->temp_mask = NCT6795_TEMP_MASK;
3957 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003958 case nct6796:
3959 data->temp_label = nct6796_temp_label;
3960 data->temp_mask = NCT6796_TEMP_MASK;
3961 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07003962 }
David Bartley578ab5f2013-06-24 22:28:28 -07003963
3964 data->REG_CONFIG = NCT6775_REG_CONFIG;
3965 data->REG_VBAT = NCT6775_REG_VBAT;
3966 data->REG_DIODE = NCT6775_REG_DIODE;
3967 data->DIODE_MASK = NCT6775_DIODE_MASK;
3968 data->REG_VIN = NCT6779_REG_IN;
3969 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3970 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3971 data->REG_TARGET = NCT6775_REG_TARGET;
3972 data->REG_FAN = NCT6779_REG_FAN;
3973 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3974 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3975 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3976 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3977 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003978 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3979 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003980 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3981 data->REG_PWM[0] = NCT6775_REG_PWM;
3982 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3983 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003984 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3985 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003986 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3987 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3988 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3989 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3990 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3991 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3992 data->REG_CRITICAL_TEMP_TOLERANCE
3993 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3994 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3995 data->CRITICAL_PWM_ENABLE_MASK
3996 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3997 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3998 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3999 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4000 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004001 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4002 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4003 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4004 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004005 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004006 if (data->kind == nct6791)
4007 data->REG_BEEP = NCT6776_REG_BEEP;
4008 else
4009 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004010
4011 reg_temp = NCT6779_REG_TEMP;
4012 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004013 if (data->kind == nct6791) {
4014 reg_temp_mon = NCT6779_REG_TEMP_MON;
4015 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4016 } else {
4017 reg_temp_mon = NCT6792_REG_TEMP_MON;
4018 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4019 }
David Bartley578ab5f2013-06-24 22:28:28 -07004020 reg_temp_over = NCT6779_REG_TEMP_OVER;
4021 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4022 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4023 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4024 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4025
4026 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004027 default:
4028 return -ENODEV;
4029 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004030 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004031 data->have_temp = 0;
4032
4033 /*
4034 * On some boards, not all available temperature sources are monitored,
4035 * even though some of the monitoring registers are unused.
4036 * Get list of unused monitoring registers, then detect if any fan
4037 * controls are configured to use unmonitored temperature sources.
4038 * If so, assign the unmonitored temperature sources to available
4039 * monitoring registers.
4040 */
4041 mask = 0;
4042 available = 0;
4043 for (i = 0; i < num_reg_temp; i++) {
4044 if (reg_temp[i] == 0)
4045 continue;
4046
4047 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004048 if (!src || (mask & BIT(src)))
4049 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004050
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004051 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004052 }
4053
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004054 /*
4055 * Now find unmonitored temperature registers and enable monitoring
4056 * if additional monitoring registers are available.
4057 */
4058 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4059 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4060
Guenter Roeckaa136e52012-12-04 03:26:05 -08004061 mask = 0;
4062 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4063 for (i = 0; i < num_reg_temp; i++) {
4064 if (reg_temp[i] == 0)
4065 continue;
4066
4067 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004068 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004069 continue;
4070
Guenter Roeckcc66b302017-05-17 18:05:06 -07004071 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004072 dev_info(dev,
4073 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4074 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4075 continue;
4076 }
4077
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004078 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004079
4080 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4081 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004082 data->have_temp |= BIT(src - 1);
4083 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004084 data->reg_temp[0][src - 1] = reg_temp[i];
4085 data->reg_temp[1][src - 1] = reg_temp_over[i];
4086 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004087 if (reg_temp_crit_h && reg_temp_crit_h[i])
4088 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4089 else if (reg_temp_crit[src - 1])
4090 data->reg_temp[3][src - 1]
4091 = reg_temp_crit[src - 1];
4092 if (reg_temp_crit_l && reg_temp_crit_l[i])
4093 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004094 data->reg_temp_config[src - 1] = reg_temp_config[i];
4095 data->temp_src[src - 1] = src;
4096 continue;
4097 }
4098
4099 if (s >= NUM_TEMP)
4100 continue;
4101
4102 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004103 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004104 data->reg_temp[0][s] = reg_temp[i];
4105 data->reg_temp[1][s] = reg_temp_over[i];
4106 data->reg_temp[2][s] = reg_temp_hyst[i];
4107 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004108 if (reg_temp_crit_h && reg_temp_crit_h[i])
4109 data->reg_temp[3][s] = reg_temp_crit_h[i];
4110 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004111 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004112 if (reg_temp_crit_l && reg_temp_crit_l[i])
4113 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004114
4115 data->temp_src[s] = src;
4116 s++;
4117 }
4118
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004119 /*
4120 * Repeat with temperatures used for fan control.
4121 * This set of registers does not support limits.
4122 */
4123 for (i = 0; i < num_reg_temp_mon; i++) {
4124 if (reg_temp_mon[i] == 0)
4125 continue;
4126
4127 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004128 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004129 continue;
4130
Guenter Roeckcc66b302017-05-17 18:05:06 -07004131 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004132 dev_info(dev,
4133 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4134 src, i, data->REG_TEMP_SEL[i],
4135 reg_temp_mon[i]);
4136 continue;
4137 }
4138
Guenter Roeck7ce41902016-09-11 12:42:52 -07004139 /*
4140 * For virtual temperature sources, the 'virtual' temperature
4141 * for each fan reflects a different temperature, and there
4142 * are no duplicates.
4143 */
4144 if (src != TEMP_SOURCE_VIRTUAL) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004145 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004146 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004147 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004148 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004149
4150 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4151 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004152 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004153 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004154 data->have_temp |= BIT(src - 1);
4155 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004156 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4157 data->temp_src[src - 1] = src;
4158 continue;
4159 }
4160
4161 if (s >= NUM_TEMP)
4162 continue;
4163
4164 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004165 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004166 data->reg_temp[0][s] = reg_temp_mon[i];
4167 data->temp_src[s] = src;
4168 s++;
4169 }
4170
Guenter Roeckaa136e52012-12-04 03:26:05 -08004171#ifdef USE_ALTERNATE
4172 /*
4173 * Go through the list of alternate temp registers and enable
4174 * if possible.
4175 * The temperature is already monitored if the respective bit in <mask>
4176 * is set.
4177 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004178 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004179 if (!(data->temp_mask & BIT(i + 1)))
4180 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004181 if (!reg_temp_alternate[i])
4182 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004183 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004184 continue;
4185 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004186 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004187 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004188 data->have_temp |= BIT(i);
4189 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004190 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004191 if (i < num_reg_temp) {
4192 data->reg_temp[1][i] = reg_temp_over[i];
4193 data->reg_temp[2][i] = reg_temp_hyst[i];
4194 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004195 data->temp_src[i] = i + 1;
4196 continue;
4197 }
4198
4199 if (s >= NUM_TEMP) /* Abort if no more space */
4200 break;
4201
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004202 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004203 data->reg_temp[0][s] = reg_temp_alternate[i];
4204 data->temp_src[s] = i + 1;
4205 s++;
4206 }
4207#endif /* USE_ALTERNATE */
4208
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004209 /* Initialize the chip */
4210 nct6775_init_device(data);
4211
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004212 err = superio_enter(sio_data->sioreg);
4213 if (err)
4214 return err;
4215
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004216 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4217 switch (data->kind) {
4218 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004219 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004220 break;
4221 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004222 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004223 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004224 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004225 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004226 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004227 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004228 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004229 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004230 case nct6796:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004231 break;
4232 }
4233
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004234 /*
4235 * Read VID value
4236 * We can get the VID input values directly at logical device D 0xe3.
4237 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004238 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004239 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4240 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4241 data->vrm = vid_which_vrm();
4242 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004243
4244 if (fan_debounce) {
4245 u8 tmp;
4246
4247 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4248 tmp = superio_inb(sio_data->sioreg,
4249 NCT6775_REG_CR_FAN_DEBOUNCE);
4250 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004251 case nct6106:
4252 tmp |= 0xe0;
4253 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004254 case nct6775:
4255 tmp |= 0x1e;
4256 break;
4257 case nct6776:
4258 case nct6779:
4259 tmp |= 0x3e;
4260 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004261 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004262 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004263 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004264 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004265 case nct6796:
David Bartley578ab5f2013-06-24 22:28:28 -07004266 tmp |= 0x7e;
4267 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004268 }
4269 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4270 tmp);
4271 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4272 data->name);
4273 }
4274
Guenter Roeckdf612d52013-07-08 13:15:04 -07004275 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004276
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004277 superio_exit(sio_data->sioreg);
4278
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004279 /* Read fan clock dividers immediately */
4280 nct6775_init_fan_common(dev, data);
4281
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004282 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004283 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4284 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004285 if (IS_ERR(group))
4286 return PTR_ERR(group);
4287
Axel Lin55bdee62014-07-24 08:59:34 +08004288 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004289
Guenter Roeckf73cf632013-03-18 09:22:50 -07004290 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4291 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004292 if (IS_ERR(group))
4293 return PTR_ERR(group);
4294
Axel Lin55bdee62014-07-24 08:59:34 +08004295 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004296
Guenter Roeckf73cf632013-03-18 09:22:50 -07004297 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4298 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004299 if (IS_ERR(group))
4300 return PTR_ERR(group);
4301
Axel Lin55bdee62014-07-24 08:59:34 +08004302 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004303
Guenter Roeckf73cf632013-03-18 09:22:50 -07004304 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4305 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004306 if (IS_ERR(group))
4307 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004308
Axel Lin55bdee62014-07-24 08:59:34 +08004309 data->groups[num_attr_groups++] = group;
4310 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004311
Guenter Roecka150d952013-07-11 22:55:22 -07004312 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4313 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004314 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004315}
4316
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004317static void nct6791_enable_io_mapping(int sioaddr)
4318{
4319 int val;
4320
4321 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4322 if (val & 0x10) {
4323 pr_info("Enabling hardware monitor logical device mappings.\n");
4324 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4325 val & ~0x10);
4326 }
4327}
4328
Guenter Roeck48e93182015-02-07 08:48:49 -08004329static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004330{
4331 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004332
4333 mutex_lock(&data->update_lock);
4334 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004335 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004336 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4337 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4338 }
4339 mutex_unlock(&data->update_lock);
4340
4341 return 0;
4342}
4343
Guenter Roeck48e93182015-02-07 08:48:49 -08004344static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004345{
4346 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004347 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004348 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004349 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004350
4351 mutex_lock(&data->update_lock);
4352 data->bank = 0xff; /* Force initial bank selection */
4353
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004354 err = superio_enter(sioreg);
4355 if (err)
4356 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004357
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004358 superio_select(sioreg, NCT6775_LD_HWM);
4359 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4360 if (reg != data->sio_reg_enable)
4361 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4362
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004363 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004364 data->kind == nct6793 || data->kind == nct6795 ||
4365 data->kind == nct6796)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004366 nct6791_enable_io_mapping(sioreg);
4367
4368 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004369
Guenter Roeck84d19d92012-12-04 08:01:39 -08004370 /* Restore limits */
4371 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004372 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004373 continue;
4374
4375 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4376 data->in[i][1]);
4377 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4378 data->in[i][2]);
4379 }
4380
Guenter Roeckc409fd42013-04-09 05:04:00 -07004381 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004382 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004383 continue;
4384
4385 nct6775_write_value(data, data->REG_FAN_MIN[i],
4386 data->fan_min[i]);
4387 }
4388
4389 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004390 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004391 continue;
4392
Guenter Roeckc409fd42013-04-09 05:04:00 -07004393 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004394 if (data->reg_temp[j][i])
4395 nct6775_write_temp(data, data->reg_temp[j][i],
4396 data->temp[j][i]);
4397 }
4398
4399 /* Restore other settings */
4400 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004401 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004402 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4403 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4404 }
4405
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004406abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004407 /* Force re-reading all values */
4408 data->valid = false;
4409 mutex_unlock(&data->update_lock);
4410
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004411 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004412}
4413
Guenter Roeck48e93182015-02-07 08:48:49 -08004414static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004415
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004416static struct platform_driver nct6775_driver = {
4417 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004418 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004419 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004420 },
4421 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004422};
4423
4424/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004425static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004426{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004427 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004428 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004429 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004430
4431 err = superio_enter(sioaddr);
4432 if (err)
4433 return err;
4434
Guenter Roeckfc72af32016-08-03 22:07:18 -07004435 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4436 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4437 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004438 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004439
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004440 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004441 case SIO_NCT6106_ID:
4442 sio_data->kind = nct6106;
4443 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004444 case SIO_NCT6775_ID:
4445 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004446 break;
4447 case SIO_NCT6776_ID:
4448 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004449 break;
4450 case SIO_NCT6779_ID:
4451 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004452 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004453 case SIO_NCT6791_ID:
4454 sio_data->kind = nct6791;
4455 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004456 case SIO_NCT6792_ID:
4457 sio_data->kind = nct6792;
4458 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004459 case SIO_NCT6793_ID:
4460 sio_data->kind = nct6793;
4461 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004462 case SIO_NCT6795_ID:
4463 sio_data->kind = nct6795;
4464 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004465 case SIO_NCT6796_ID:
4466 sio_data->kind = nct6796;
4467 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004468 default:
4469 if (val != 0xffff)
4470 pr_debug("unsupported chip ID: 0x%04x\n", val);
4471 superio_exit(sioaddr);
4472 return -ENODEV;
4473 }
4474
4475 /* We have a known chip, find the HWM I/O address */
4476 superio_select(sioaddr, NCT6775_LD_HWM);
4477 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4478 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004479 addr = val & IOREGION_ALIGNMENT;
4480 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004481 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4482 superio_exit(sioaddr);
4483 return -ENODEV;
4484 }
4485
4486 /* Activate logical device if needed */
4487 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4488 if (!(val & 0x01)) {
4489 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4490 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4491 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004492
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004493 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004494 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
4495 sio_data->kind == nct6796)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004496 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004497
4498 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004499 pr_info("Found %s or compatible chip at %#x:%#x\n",
4500 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004501 sio_data->sioreg = sioaddr;
4502
Guenter Roeck698a7c22013-04-05 07:35:25 -07004503 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004504}
4505
4506/*
4507 * when Super-I/O functions move to a separate file, the Super-I/O
4508 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004509 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004510 * must keep track of the device
4511 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004512static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004513
4514static int __init sensors_nct6775_init(void)
4515{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004516 int i, err;
4517 bool found = false;
4518 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004519 struct resource res;
4520 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004521 int sioaddr[2] = { 0x2e, 0x4e };
4522
4523 err = platform_driver_register(&nct6775_driver);
4524 if (err)
4525 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004526
4527 /*
4528 * initialize sio_data->kind and sio_data->sioreg.
4529 *
4530 * when Super-I/O functions move to a separate file, the Super-I/O
4531 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4532 * nct6775 hardware monitor, and call probe()
4533 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004534 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4535 address = nct6775_find(sioaddr[i], &sio_data);
4536 if (address <= 0)
4537 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004538
Guenter Roeck698a7c22013-04-05 07:35:25 -07004539 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004540
Guenter Roeck698a7c22013-04-05 07:35:25 -07004541 pdev[i] = platform_device_alloc(DRVNAME, address);
4542 if (!pdev[i]) {
4543 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004544 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004545 }
4546
4547 err = platform_device_add_data(pdev[i], &sio_data,
4548 sizeof(struct nct6775_sio_data));
4549 if (err)
4550 goto exit_device_put;
4551
4552 memset(&res, 0, sizeof(res));
4553 res.name = DRVNAME;
4554 res.start = address + IOREGION_OFFSET;
4555 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4556 res.flags = IORESOURCE_IO;
4557
4558 err = acpi_check_resource_conflict(&res);
4559 if (err) {
4560 platform_device_put(pdev[i]);
4561 pdev[i] = NULL;
4562 continue;
4563 }
4564
4565 err = platform_device_add_resources(pdev[i], &res, 1);
4566 if (err)
4567 goto exit_device_put;
4568
4569 /* platform_device_add calls probe() */
4570 err = platform_device_add(pdev[i]);
4571 if (err)
4572 goto exit_device_put;
4573 }
4574 if (!found) {
4575 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004576 goto exit_unregister;
4577 }
4578
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004579 return 0;
4580
4581exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004582 platform_device_put(pdev[i]);
4583exit_device_unregister:
4584 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004585 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004586 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004587 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004588exit_unregister:
4589 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004590 return err;
4591}
4592
4593static void __exit sensors_nct6775_exit(void)
4594{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004595 int i;
4596
4597 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4598 if (pdev[i])
4599 platform_device_unregister(pdev[i]);
4600 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004601 platform_driver_unregister(&nct6775_driver);
4602}
4603
4604MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004605MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004606MODULE_LICENSE("GPL");
4607
4608module_init(sensors_nct6775_init);
4609module_exit(sensors_nct6775_exit);