blob: 4667691ca6a8dd9a891c461d2108aa12e4359db0 [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 Roeck9de2e2e2012-05-20 19:29:48 -070043 *
44 * #temp lists the number of monitored temperature sources (first value) plus
45 * the number of directly connectable temperature sensors (second value).
46 */
47
48#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
50#include <linux/module.h>
51#include <linux/init.h>
52#include <linux/slab.h>
53#include <linux/jiffies.h>
54#include <linux/platform_device.h>
55#include <linux/hwmon.h>
56#include <linux/hwmon-sysfs.h>
57#include <linux/hwmon-vid.h>
58#include <linux/err.h>
59#include <linux/mutex.h>
60#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070061#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080062#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070063#include <linux/io.h>
64#include "lm75.h"
65
Guenter Roeckaa136e52012-12-04 03:26:05 -080066#define USE_ALTERNATE
67
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070068enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070069
70/* used to set data->name = nct6775_device_names[data->sio_kind] */
71static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070072 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070073 "nct6775",
74 "nct6776",
75 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070076 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080077 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070078 "nct6793",
79};
80
81static const char * const nct6775_sio_names[] __initconst = {
82 "NCT6106D",
83 "NCT6775F",
84 "NCT6776D/F",
85 "NCT6779D",
86 "NCT6791D",
87 "NCT6792D",
88 "NCT6793D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070089};
90
91static unsigned short force_id;
92module_param(force_id, ushort, 0);
93MODULE_PARM_DESC(force_id, "Override the detected device ID");
94
Guenter Roeck47ece962012-12-04 07:59:32 -080095static unsigned short fan_debounce;
96module_param(fan_debounce, ushort, 0);
97MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
98
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070099#define DRVNAME "nct6775"
100
101/*
102 * Super-I/O constants and functions
103 */
104
Guenter Roecka6bd5872012-12-04 03:13:34 -0800105#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700106#define NCT6775_LD_HWM 0x0b
107#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700108#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700109
110#define SIO_REG_LDSEL 0x07 /* Logical device select */
111#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
112#define SIO_REG_ENABLE 0x30 /* Logical device enable */
113#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
114
Guenter Roeck6c009502012-07-01 08:23:15 -0700115#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700116#define SIO_NCT6775_ID 0xb470
117#define SIO_NCT6776_ID 0xc330
118#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700119#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800120#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700121#define SIO_NCT6793_ID 0xd120
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700122#define SIO_ID_MASK 0xFFF0
123
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800124enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
125
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700126static inline void
127superio_outb(int ioreg, int reg, int val)
128{
129 outb(reg, ioreg);
130 outb(val, ioreg + 1);
131}
132
133static inline int
134superio_inb(int ioreg, int reg)
135{
136 outb(reg, ioreg);
137 return inb(ioreg + 1);
138}
139
140static inline void
141superio_select(int ioreg, int ld)
142{
143 outb(SIO_REG_LDSEL, ioreg);
144 outb(ld, ioreg + 1);
145}
146
147static inline int
148superio_enter(int ioreg)
149{
150 /*
151 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
152 */
153 if (!request_muxed_region(ioreg, 2, DRVNAME))
154 return -EBUSY;
155
156 outb(0x87, ioreg);
157 outb(0x87, ioreg);
158
159 return 0;
160}
161
162static inline void
163superio_exit(int ioreg)
164{
165 outb(0xaa, ioreg);
166 outb(0x02, ioreg);
167 outb(0x02, ioreg + 1);
168 release_region(ioreg, 2);
169}
170
171/*
172 * ISA constants
173 */
174
175#define IOREGION_ALIGNMENT (~7)
176#define IOREGION_OFFSET 5
177#define IOREGION_LENGTH 2
178#define ADDR_REG_OFFSET 0
179#define DATA_REG_OFFSET 1
180
181#define NCT6775_REG_BANK 0x4E
182#define NCT6775_REG_CONFIG 0x40
183
184/*
185 * Not currently used:
186 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
187 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
188 * REG_MAN_ID is at port 0x4f
189 * REG_CHIP_ID is at port 0x58
190 */
191
Guenter Roeckaa136e52012-12-04 03:26:05 -0800192#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
193#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
194
Guenter Roeck6c009502012-07-01 08:23:15 -0700195#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700196#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700197
David Bartley578ab5f2013-06-24 22:28:28 -0700198#define NUM_FAN 6
199
Guenter Roeck7ce41902016-09-11 12:42:52 -0700200#define TEMP_SOURCE_VIRTUAL 0x1f
201
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700202/* Common and NCT6775 specific data */
203
204/* Voltage min/max registers for nr=7..14 are in bank 5 */
205
206static const u16 NCT6775_REG_IN_MAX[] = {
207 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
208 0x55c, 0x55e, 0x560, 0x562 };
209static const u16 NCT6775_REG_IN_MIN[] = {
210 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
211 0x55d, 0x55f, 0x561, 0x563 };
212static const u16 NCT6775_REG_IN[] = {
213 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
214};
215
216#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800217#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700218#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700219
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800220#define NCT6775_REG_FANDIV1 0x506
221#define NCT6775_REG_FANDIV2 0x507
222
Guenter Roeck47ece962012-12-04 07:59:32 -0800223#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
224
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700225static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
226
Guenter Roeck30846992013-06-24 22:21:59 -0700227/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700228
229static const s8 NCT6775_ALARM_BITS[] = {
230 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
231 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
232 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700233 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700234 -1, -1, -1, /* unused */
235 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
236 12, -1 }; /* intrusion0, intrusion1 */
237
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800238#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800239#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800240#define INTRUSION_ALARM_BASE 30
241
Guenter Roeck30846992013-06-24 22:21:59 -0700242static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
243
244/*
245 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
246 * 30..31 intrusion
247 */
248static const s8 NCT6775_BEEP_BITS[] = {
249 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
250 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
251 21, /* global beep enable */
252 6, 7, 11, 28, -1, /* fan1..fan5 */
253 -1, -1, -1, /* unused */
254 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
255 12, -1 }; /* intrusion0, intrusion1 */
256
257#define BEEP_ENABLE_BASE 15
258
Guenter Roecka6bd5872012-12-04 03:13:34 -0800259static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
260static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
261
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800262/* DC or PWM output fan configuration */
263static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
264static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
265
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800266/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800267
David Bartley578ab5f2013-06-24 22:28:28 -0700268static const u16 NCT6775_REG_TARGET[] = {
269 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
270static const u16 NCT6775_REG_FAN_MODE[] = {
271 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800272static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700273 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800274static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700275 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800276static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700277 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
278static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
279 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800280static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
281static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
282
283static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700284 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
285static const u16 NCT6775_REG_PWM[] = {
286 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
287static const u16 NCT6775_REG_PWM_READ[] = {
288 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800289
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800290static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
291static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800292static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700293static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800294
Guenter Roeckaa136e52012-12-04 03:26:05 -0800295static const u16 NCT6775_REG_TEMP[] = {
296 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
297
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800298static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
299
Guenter Roeckaa136e52012-12-04 03:26:05 -0800300static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
301 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
302static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
303 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
304static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
305 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
306
307static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
308 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
309
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800310static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700311 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800312
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800313static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700314 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800315static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700316 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800317static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700318 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800319static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700320 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800321static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700322 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800323
Guenter Roeckaa136e52012-12-04 03:26:05 -0800324static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
325
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800326static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700327 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800328static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700329 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800330
331#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
332#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
333
334static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
335
336static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700337 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800338static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700339 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800340
Guenter Roeckaa136e52012-12-04 03:26:05 -0800341static const char *const nct6775_temp_label[] = {
342 "",
343 "SYSTIN",
344 "CPUTIN",
345 "AUXTIN",
346 "AMD SB-TSI",
347 "PECI Agent 0",
348 "PECI Agent 1",
349 "PECI Agent 2",
350 "PECI Agent 3",
351 "PECI Agent 4",
352 "PECI Agent 5",
353 "PECI Agent 6",
354 "PECI Agent 7",
355 "PCH_CHIP_CPU_MAX_TEMP",
356 "PCH_CHIP_TEMP",
357 "PCH_CPU_TEMP",
358 "PCH_MCH_TEMP",
359 "PCH_DIM0_TEMP",
360 "PCH_DIM1_TEMP",
361 "PCH_DIM2_TEMP",
362 "PCH_DIM3_TEMP"
363};
364
Guenter Roeckcc66b302017-05-17 18:05:06 -0700365#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800366
Guenter Roeckcc66b302017-05-17 18:05:06 -0700367static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
368 [13] = 0x661,
369 [14] = 0x662,
370 [15] = 0x664,
371};
372
373static const u16 NCT6775_REG_TEMP_CRIT[32] = {
374 [4] = 0xa00,
375 [5] = 0xa01,
376 [6] = 0xa02,
377 [7] = 0xa03,
378 [8] = 0xa04,
379 [9] = 0xa05,
380 [10] = 0xa06,
381 [11] = 0xa07
382};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800383
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700384/* NCT6776 specific data */
385
Guenter Roeck728d2942015-08-31 16:13:47 -0700386/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
387#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
388#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
389
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700390static const s8 NCT6776_ALARM_BITS[] = {
391 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
392 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
393 -1, /* unused */
394 6, 7, 11, 10, 23, /* fan1..fan5 */
395 -1, -1, -1, /* unused */
396 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
397 12, 9 }; /* intrusion0, intrusion1 */
398
Guenter Roeck30846992013-06-24 22:21:59 -0700399static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
400
401static const s8 NCT6776_BEEP_BITS[] = {
402 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
403 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
404 24, /* global beep enable */
405 25, 26, 27, 28, 29, /* fan1..fan5 */
406 -1, -1, -1, /* unused */
407 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
408 30, 31 }; /* intrusion0, intrusion1 */
409
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800410static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700411 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800412
David Bartley578ab5f2013-06-24 22:28:28 -0700413static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
414static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800415
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800416static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800417static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800418
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800419static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700420 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800421
Guenter Roeckaa136e52012-12-04 03:26:05 -0800422static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
423 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
424
425static const char *const nct6776_temp_label[] = {
426 "",
427 "SYSTIN",
428 "CPUTIN",
429 "AUXTIN",
430 "SMBUSMASTER 0",
431 "SMBUSMASTER 1",
432 "SMBUSMASTER 2",
433 "SMBUSMASTER 3",
434 "SMBUSMASTER 4",
435 "SMBUSMASTER 5",
436 "SMBUSMASTER 6",
437 "SMBUSMASTER 7",
438 "PECI Agent 0",
439 "PECI Agent 1",
440 "PCH_CHIP_CPU_MAX_TEMP",
441 "PCH_CHIP_TEMP",
442 "PCH_CPU_TEMP",
443 "PCH_MCH_TEMP",
444 "PCH_DIM0_TEMP",
445 "PCH_DIM1_TEMP",
446 "PCH_DIM2_TEMP",
447 "PCH_DIM3_TEMP",
448 "BYTE_TEMP"
449};
450
Guenter Roeckcc66b302017-05-17 18:05:06 -0700451#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800452
Guenter Roeckcc66b302017-05-17 18:05:06 -0700453static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
454 [14] = 0x401,
455 [15] = 0x402,
456 [16] = 0x404,
457};
458
459static const u16 NCT6776_REG_TEMP_CRIT[32] = {
460 [11] = 0x709,
461 [12] = 0x70a,
462};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800463
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700464/* NCT6779 specific data */
465
466static const u16 NCT6779_REG_IN[] = {
467 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
468 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
469
470static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
471 0x459, 0x45A, 0x45B, 0x568 };
472
473static const s8 NCT6779_ALARM_BITS[] = {
474 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
475 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
476 -1, /* unused */
477 6, 7, 11, 10, 23, /* fan1..fan5 */
478 -1, -1, -1, /* unused */
479 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
480 12, 9 }; /* intrusion0, intrusion1 */
481
Guenter Roeck30846992013-06-24 22:21:59 -0700482static const s8 NCT6779_BEEP_BITS[] = {
483 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
484 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
485 24, /* global beep enable */
486 25, 26, 27, 28, 29, /* fan1..fan5 */
487 -1, -1, -1, /* unused */
488 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
489 30, 31 }; /* intrusion0, intrusion1 */
490
David Bartley578ab5f2013-06-24 22:28:28 -0700491static const u16 NCT6779_REG_FAN[] = {
492 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800493static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700494 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800495
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800496static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700497 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700498#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800499static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700500 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800501
Guenter Roeckaa136e52012-12-04 03:26:05 -0800502static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800503static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800504static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
505 0x18, 0x152 };
506static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
507 0x3a, 0x153 };
508static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
509 0x39, 0x155 };
510
511static const u16 NCT6779_REG_TEMP_OFFSET[] = {
512 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
513
514static const char *const nct6779_temp_label[] = {
515 "",
516 "SYSTIN",
517 "CPUTIN",
518 "AUXTIN0",
519 "AUXTIN1",
520 "AUXTIN2",
521 "AUXTIN3",
522 "",
523 "SMBUSMASTER 0",
524 "SMBUSMASTER 1",
525 "SMBUSMASTER 2",
526 "SMBUSMASTER 3",
527 "SMBUSMASTER 4",
528 "SMBUSMASTER 5",
529 "SMBUSMASTER 6",
530 "SMBUSMASTER 7",
531 "PECI Agent 0",
532 "PECI Agent 1",
533 "PCH_CHIP_CPU_MAX_TEMP",
534 "PCH_CHIP_TEMP",
535 "PCH_CPU_TEMP",
536 "PCH_MCH_TEMP",
537 "PCH_DIM0_TEMP",
538 "PCH_DIM1_TEMP",
539 "PCH_DIM2_TEMP",
540 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700541 "BYTE_TEMP",
542 "",
543 "",
544 "",
545 "",
546 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800547};
548
Guenter Roeckcc66b302017-05-17 18:05:06 -0700549#define NCT6779_TEMP_MASK 0x07ffff7e
550#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck9a383712015-08-29 15:29:25 -0700551
Guenter Roeckcc66b302017-05-17 18:05:06 -0700552static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800553 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
554 0, 0, 0, 0, 0, 0, 0, 0,
555 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
556 0x408, 0 };
557
Guenter Roeckcc66b302017-05-17 18:05:06 -0700558static const u16 NCT6779_REG_TEMP_CRIT[32] = {
559 [15] = 0x709,
560 [16] = 0x70a,
561};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800562
David Bartley578ab5f2013-06-24 22:28:28 -0700563/* NCT6791 specific data */
564
565#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
566
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800567static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
568static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
569static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
570static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
571static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
572static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
573
David Bartley578ab5f2013-06-24 22:28:28 -0700574static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
575 0x459, 0x45A, 0x45B, 0x568, 0x45D };
576
577static const s8 NCT6791_ALARM_BITS[] = {
578 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
579 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
580 -1, /* unused */
581 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
582 -1, -1, /* unused */
583 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
584 12, 9 }; /* intrusion0, intrusion1 */
585
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700586/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800587
588static const u16 NCT6792_REG_TEMP_MON[] = {
589 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
590static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
591 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700592
Guenter Roeck50224f42015-10-30 07:52:39 -0700593static const char *const nct6792_temp_label[] = {
594 "",
595 "SYSTIN",
596 "CPUTIN",
597 "AUXTIN0",
598 "AUXTIN1",
599 "AUXTIN2",
600 "AUXTIN3",
601 "",
602 "SMBUSMASTER 0",
603 "SMBUSMASTER 1",
604 "SMBUSMASTER 2",
605 "SMBUSMASTER 3",
606 "SMBUSMASTER 4",
607 "SMBUSMASTER 5",
608 "SMBUSMASTER 6",
609 "SMBUSMASTER 7",
610 "PECI Agent 0",
611 "PECI Agent 1",
612 "PCH_CHIP_CPU_MAX_TEMP",
613 "PCH_CHIP_TEMP",
614 "PCH_CPU_TEMP",
615 "PCH_MCH_TEMP",
616 "PCH_DIM0_TEMP",
617 "PCH_DIM1_TEMP",
618 "PCH_DIM2_TEMP",
619 "PCH_DIM3_TEMP",
620 "BYTE_TEMP",
621 "PECI Agent 0 Calibration",
622 "PECI Agent 1 Calibration",
623 "",
624 "",
625 "Virtual_TEMP"
626};
627
Guenter Roeckcc66b302017-05-17 18:05:06 -0700628#define NCT6792_TEMP_MASK 0x9fffff7e
629
Guenter Roeck50224f42015-10-30 07:52:39 -0700630static const char *const nct6793_temp_label[] = {
631 "",
632 "SYSTIN",
633 "CPUTIN",
634 "AUXTIN0",
635 "AUXTIN1",
636 "AUXTIN2",
637 "AUXTIN3",
638 "",
639 "SMBUSMASTER 0",
640 "SMBUSMASTER 1",
641 "",
642 "",
643 "",
644 "",
645 "",
646 "",
647 "PECI Agent 0",
648 "PECI Agent 1",
649 "PCH_CHIP_CPU_MAX_TEMP",
650 "PCH_CHIP_TEMP",
651 "PCH_CPU_TEMP",
652 "PCH_MCH_TEMP",
653 "Agent0 Dimm0 ",
654 "Agent0 Dimm1",
655 "Agent1 Dimm0",
656 "Agent1 Dimm1",
657 "BYTE_TEMP0",
658 "BYTE_TEMP1",
659 "PECI Agent 0 Calibration",
660 "PECI Agent 1 Calibration",
661 "",
662 "Virtual_TEMP"
663};
664
Guenter Roeckcc66b302017-05-17 18:05:06 -0700665#define NCT6793_TEMP_MASK 0xbfff037e
666
Guenter Roeck6c009502012-07-01 08:23:15 -0700667/* NCT6102D/NCT6106D specific data */
668
669#define NCT6106_REG_VBAT 0x318
670#define NCT6106_REG_DIODE 0x319
671#define NCT6106_DIODE_MASK 0x01
672
673static const u16 NCT6106_REG_IN_MAX[] = {
674 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
675static const u16 NCT6106_REG_IN_MIN[] = {
676 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
677static const u16 NCT6106_REG_IN[] = {
678 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
679
680static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800681static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700682static const u16 NCT6106_REG_TEMP_HYST[] = {
683 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
684static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700685 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
686static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
687 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
688static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
689 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700690static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
691static const u16 NCT6106_REG_TEMP_CONFIG[] = {
692 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
693
694static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
695static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
696static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
697static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
698
699static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
700static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
701static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
702static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
703static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
704static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
705static const u16 NCT6106_REG_TEMP_SOURCE[] = {
706 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
707
708static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
709static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
710 0x11b, 0x12b, 0x13b };
711
712static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
713#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
714static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
715
716static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
717static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
718static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
719static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
720static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
721static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
722
723static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
724
725static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
726static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
727static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
728static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
729static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
730static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
731
732static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
733static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
734
735static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
736 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
737
738static const s8 NCT6106_ALARM_BITS[] = {
739 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
740 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
741 -1, /* unused */
742 32, 33, 34, -1, -1, /* fan1..fan5 */
743 -1, -1, -1, /* unused */
744 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
745 48, -1 /* intrusion0, intrusion1 */
746};
747
Guenter Roeck30846992013-06-24 22:21:59 -0700748static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
749 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
750
751static const s8 NCT6106_BEEP_BITS[] = {
752 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
753 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
754 32, /* global beep enable */
755 24, 25, 26, 27, 28, /* fan1..fan5 */
756 -1, -1, -1, /* unused */
757 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
758 34, -1 /* intrusion0, intrusion1 */
759};
760
Guenter Roeckcc66b302017-05-17 18:05:06 -0700761static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
762 [14] = 0x51,
763 [15] = 0x52,
764 [16] = 0x54,
765};
Guenter Roeck6c009502012-07-01 08:23:15 -0700766
Guenter Roeckcc66b302017-05-17 18:05:06 -0700767static const u16 NCT6106_REG_TEMP_CRIT[32] = {
768 [11] = 0x204,
769 [12] = 0x205,
770};
Guenter Roeck6c009502012-07-01 08:23:15 -0700771
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800772static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
773{
774 if (mode == 0 && pwm == 255)
775 return off;
776 return mode + 1;
777}
778
779static int pwm_enable_to_reg(enum pwm_enable mode)
780{
781 if (mode == off)
782 return 0;
783 return mode - 1;
784}
785
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700786/*
787 * Conversions
788 */
789
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800790/* 1 is DC mode, output in ms */
791static unsigned int step_time_from_reg(u8 reg, u8 mode)
792{
793 return mode ? 400 * reg : 100 * reg;
794}
795
796static u8 step_time_to_reg(unsigned int msec, u8 mode)
797{
798 return clamp_val((mode ? (msec + 200) / 400 :
799 (msec + 50) / 100), 1, 255);
800}
801
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800802static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
803{
804 if (reg == 0 || reg == 255)
805 return 0;
806 return 1350000U / (reg << divreg);
807}
808
809static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
810{
811 if ((reg & 0xff1f) == 0xff1f)
812 return 0;
813
814 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
815
816 if (reg == 0)
817 return 0;
818
819 return 1350000U / reg;
820}
821
822static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
823{
824 if (reg == 0 || reg == 0xffff)
825 return 0;
826
827 /*
828 * Even though the registers are 16 bit wide, the fan divisor
829 * still applies.
830 */
831 return 1350000U / (reg << divreg);
832}
833
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800834static u16 fan_to_reg(u32 fan, unsigned int divreg)
835{
836 if (!fan)
837 return 0;
838
839 return (1350000U / fan) >> divreg;
840}
841
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800842static inline unsigned int
843div_from_reg(u8 reg)
844{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700845 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800846}
847
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700848/*
849 * Some of the voltage inputs have internal scaling, the tables below
850 * contain 8 (the ADC LSB in mV) * scaling factor * 100
851 */
852static const u16 scale_in[15] = {
853 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
854 800, 800
855};
856
857static inline long in_from_reg(u8 reg, u8 nr)
858{
859 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
860}
861
862static inline u8 in_to_reg(u32 val, u8 nr)
863{
864 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
865}
866
867/*
868 * Data structures and manipulation thereof
869 */
870
871struct nct6775_data {
872 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700873 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700874 enum kinds kind;
875 const char *name;
876
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700877 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700878
Guenter Roeckb7a61352013-04-02 22:14:06 -0700879 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
880 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800881 */
882 u8 temp_src[NUM_TEMP];
883 u16 reg_temp_config[NUM_TEMP];
884 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700885 u32 temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800886
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700887 u16 REG_CONFIG;
888 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800889 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700890 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700891
892 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700893 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700894
895 const u16 *REG_VIN;
896 const u16 *REG_IN_MINMAX[2];
897
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800898 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800899 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800900 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800901 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800902 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700903 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800904 const u16 *REG_FAN_TIME[3];
905
906 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800907
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800908 const u8 *REG_PWM_MODE;
909 const u8 *PWM_MODE_MASK;
910
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800911 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
912 * [3]=pwm_max, [4]=pwm_step,
913 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800914 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800915 const u16 *REG_PWM_READ;
916
Guenter Roeck6c009502012-07-01 08:23:15 -0700917 const u16 *REG_CRITICAL_PWM_ENABLE;
918 u8 CRITICAL_PWM_ENABLE_MASK;
919 const u16 *REG_CRITICAL_PWM;
920
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800921 const u16 *REG_AUTO_TEMP;
922 const u16 *REG_AUTO_PWM;
923
924 const u16 *REG_CRITICAL_TEMP;
925 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
926
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800927 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800928 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800929 const u16 *REG_WEIGHT_TEMP_SEL;
930 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
931
Guenter Roeckaa136e52012-12-04 03:26:05 -0800932 const u16 *REG_TEMP_OFFSET;
933
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700934 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700935 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700936
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800937 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
938 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
939
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700940 struct mutex update_lock;
941 bool valid; /* true if following fields are valid */
942 unsigned long last_updated; /* In jiffies */
943
944 /* Register values */
945 u8 bank; /* current register bank */
946 u8 in_num; /* number of in inputs we have */
947 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700948 unsigned int rpm[NUM_FAN];
949 u16 fan_min[NUM_FAN];
950 u8 fan_pulses[NUM_FAN];
951 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800952 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800953 u8 has_fan; /* some fan inputs can be disabled */
954 u8 has_fan_min; /* some fans don't have min register */
955 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700956
Guenter Roeck6c009502012-07-01 08:23:15 -0700957 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700958 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800959 u8 temp_fixed_num; /* 3 or 6 */
960 u8 temp_type[NUM_TEMP_FIXED];
961 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300962 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
963 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700964 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700965 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700966
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800967 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700968 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
969 * 0->PWM variable duty cycle
970 */
971 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800972 /* 0->off
973 * 1->manual
974 * 2->thermal cruise mode (also called SmartFan I)
975 * 3->fan speed cruise mode
976 * 4->SmartFan III
977 * 5->enhanced variable thermal cruise (SmartFan IV)
978 */
David Bartley578ab5f2013-06-24 22:28:28 -0700979 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
980 * [3]=pwm_max, [4]=pwm_step,
981 * [5]=weight_duty_step, [6]=weight_duty_base
982 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800983
David Bartley578ab5f2013-06-24 22:28:28 -0700984 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800985 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700986 u32 target_speed[NUM_FAN];
987 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800988 u8 speed_tolerance_limit;
989
David Bartley578ab5f2013-06-24 22:28:28 -0700990 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800991 u8 tolerance_mask;
992
David Bartley578ab5f2013-06-24 22:28:28 -0700993 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800994
995 /* Automatic fan speed control registers */
996 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700997 u8 auto_pwm[NUM_FAN][7];
998 u8 auto_temp[NUM_FAN][7];
999 u8 pwm_temp_sel[NUM_FAN];
1000 u8 pwm_weight_temp_sel[NUM_FAN];
1001 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1002 * 2->temp_base
1003 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001004
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001005 u8 vid;
1006 u8 vrm;
1007
Guenter Roeckf73cf632013-03-18 09:22:50 -07001008 bool have_vid;
1009
Guenter Roeckaa136e52012-12-04 03:26:05 -08001010 u16 have_temp;
1011 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001012 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001013
Guenter Roeck84d19d92012-12-04 08:01:39 -08001014 /* Remember extra register values over suspend/resume */
1015 u8 vbat;
1016 u8 fandiv1;
1017 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001018 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001019};
1020
1021struct nct6775_sio_data {
1022 int sioreg;
1023 enum kinds kind;
1024};
1025
Guenter Roeckf73cf632013-03-18 09:22:50 -07001026struct sensor_device_template {
1027 struct device_attribute dev_attr;
1028 union {
1029 struct {
1030 u8 nr;
1031 u8 index;
1032 } s;
1033 int index;
1034 } u;
1035 bool s2; /* true if both index and nr are used */
1036};
1037
1038struct sensor_device_attr_u {
1039 union {
1040 struct sensor_device_attribute a1;
1041 struct sensor_device_attribute_2 a2;
1042 } u;
1043 char name[32];
1044};
1045
1046#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1047 .attr = {.name = _template, .mode = _mode }, \
1048 .show = _show, \
1049 .store = _store, \
1050}
1051
1052#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1053 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1054 .u.index = _index, \
1055 .s2 = false }
1056
1057#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1058 _nr, _index) \
1059 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1060 .u.s.index = _index, \
1061 .u.s.nr = _nr, \
1062 .s2 = true }
1063
1064#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1065static struct sensor_device_template sensor_dev_template_##_name \
1066 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1067 _index)
1068
1069#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1070 _nr, _index) \
1071static struct sensor_device_template sensor_dev_template_##_name \
1072 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1073 _nr, _index)
1074
1075struct sensor_template_group {
1076 struct sensor_device_template **templates;
1077 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1078 int base;
1079};
1080
1081static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001082nct6775_create_attr_group(struct device *dev,
1083 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001084 int repeat)
1085{
1086 struct attribute_group *group;
1087 struct sensor_device_attr_u *su;
1088 struct sensor_device_attribute *a;
1089 struct sensor_device_attribute_2 *a2;
1090 struct attribute **attrs;
1091 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001092 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001093
1094 if (repeat <= 0)
1095 return ERR_PTR(-EINVAL);
1096
1097 t = tg->templates;
1098 for (count = 0; *t; t++, count++)
1099 ;
1100
1101 if (count == 0)
1102 return ERR_PTR(-EINVAL);
1103
1104 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1105 if (group == NULL)
1106 return ERR_PTR(-ENOMEM);
1107
1108 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1109 GFP_KERNEL);
1110 if (attrs == NULL)
1111 return ERR_PTR(-ENOMEM);
1112
1113 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1114 GFP_KERNEL);
1115 if (su == NULL)
1116 return ERR_PTR(-ENOMEM);
1117
1118 group->attrs = attrs;
1119 group->is_visible = tg->is_visible;
1120
1121 for (i = 0; i < repeat; i++) {
1122 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001123 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001124 snprintf(su->name, sizeof(su->name),
1125 (*t)->dev_attr.attr.name, tg->base + i);
1126 if ((*t)->s2) {
1127 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001128 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001129 a2->dev_attr.attr.name = su->name;
1130 a2->nr = (*t)->u.s.nr + i;
1131 a2->index = (*t)->u.s.index;
1132 a2->dev_attr.attr.mode =
1133 (*t)->dev_attr.attr.mode;
1134 a2->dev_attr.show = (*t)->dev_attr.show;
1135 a2->dev_attr.store = (*t)->dev_attr.store;
1136 *attrs = &a2->dev_attr.attr;
1137 } else {
1138 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001139 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001140 a->dev_attr.attr.name = su->name;
1141 a->index = (*t)->u.index + i;
1142 a->dev_attr.attr.mode =
1143 (*t)->dev_attr.attr.mode;
1144 a->dev_attr.show = (*t)->dev_attr.show;
1145 a->dev_attr.store = (*t)->dev_attr.store;
1146 *attrs = &a->dev_attr.attr;
1147 }
1148 attrs++;
1149 su++;
1150 t++;
1151 }
1152 }
1153
Guenter Roeckf73cf632013-03-18 09:22:50 -07001154 return group;
1155}
1156
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001157static bool is_word_sized(struct nct6775_data *data, u16 reg)
1158{
1159 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001160 case nct6106:
1161 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1162 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1163 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001164 case nct6775:
1165 return (((reg & 0xff00) == 0x100 ||
1166 (reg & 0xff00) == 0x200) &&
1167 ((reg & 0x00ff) == 0x50 ||
1168 (reg & 0x00ff) == 0x53 ||
1169 (reg & 0x00ff) == 0x55)) ||
1170 (reg & 0xfff0) == 0x630 ||
1171 reg == 0x640 || reg == 0x642 ||
1172 reg == 0x662 ||
1173 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1174 reg == 0x73 || reg == 0x75 || reg == 0x77;
1175 case nct6776:
1176 return (((reg & 0xff00) == 0x100 ||
1177 (reg & 0xff00) == 0x200) &&
1178 ((reg & 0x00ff) == 0x50 ||
1179 (reg & 0x00ff) == 0x53 ||
1180 (reg & 0x00ff) == 0x55)) ||
1181 (reg & 0xfff0) == 0x630 ||
1182 reg == 0x402 ||
1183 reg == 0x640 || reg == 0x642 ||
1184 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1185 reg == 0x73 || reg == 0x75 || reg == 0x77;
1186 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001187 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001188 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001189 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001190 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001191 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001192 reg == 0x402 ||
1193 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1194 reg == 0x640 || reg == 0x642 ||
1195 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001196 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001197 }
1198 return false;
1199}
1200
1201/*
1202 * On older chips, only registers 0x50-0x5f are banked.
1203 * On more recent chips, all registers are banked.
1204 * Assume that is the case and set the bank number for each access.
1205 * Cache the bank number so it only needs to be set if it changes.
1206 */
1207static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1208{
1209 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001210
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001211 if (data->bank != bank) {
1212 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1213 outb_p(bank, data->addr + DATA_REG_OFFSET);
1214 data->bank = bank;
1215 }
1216}
1217
1218static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1219{
1220 int res, word_sized = is_word_sized(data, reg);
1221
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001222 nct6775_set_bank(data, reg);
1223 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1224 res = inb_p(data->addr + DATA_REG_OFFSET);
1225 if (word_sized) {
1226 outb_p((reg & 0xff) + 1,
1227 data->addr + ADDR_REG_OFFSET);
1228 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1229 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001230 return res;
1231}
1232
1233static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1234{
1235 int word_sized = is_word_sized(data, reg);
1236
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001237 nct6775_set_bank(data, reg);
1238 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1239 if (word_sized) {
1240 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1241 outb_p((reg & 0xff) + 1,
1242 data->addr + ADDR_REG_OFFSET);
1243 }
1244 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001245 return 0;
1246}
1247
Guenter Roeckaa136e52012-12-04 03:26:05 -08001248/* We left-align 8-bit temperature values to make the code simpler */
1249static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1250{
1251 u16 res;
1252
1253 res = nct6775_read_value(data, reg);
1254 if (!is_word_sized(data, reg))
1255 res <<= 8;
1256
1257 return res;
1258}
1259
1260static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1261{
1262 if (!is_word_sized(data, reg))
1263 value >>= 8;
1264 return nct6775_write_value(data, reg, value);
1265}
1266
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001267/* This function assumes that the caller holds data->update_lock */
1268static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1269{
1270 u8 reg;
1271
1272 switch (nr) {
1273 case 0:
1274 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1275 | (data->fan_div[0] & 0x7);
1276 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1277 break;
1278 case 1:
1279 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1280 | ((data->fan_div[1] << 4) & 0x70);
1281 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1282 break;
1283 case 2:
1284 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1285 | (data->fan_div[2] & 0x7);
1286 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1287 break;
1288 case 3:
1289 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1290 | ((data->fan_div[3] << 4) & 0x70);
1291 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1292 break;
1293 }
1294}
1295
1296static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1297{
1298 if (data->kind == nct6775)
1299 nct6775_write_fan_div(data, nr);
1300}
1301
1302static void nct6775_update_fan_div(struct nct6775_data *data)
1303{
1304 u8 i;
1305
1306 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1307 data->fan_div[0] = i & 0x7;
1308 data->fan_div[1] = (i & 0x70) >> 4;
1309 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1310 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001311 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001312 data->fan_div[3] = (i & 0x70) >> 4;
1313}
1314
1315static void nct6775_update_fan_div_common(struct nct6775_data *data)
1316{
1317 if (data->kind == nct6775)
1318 nct6775_update_fan_div(data);
1319}
1320
1321static void nct6775_init_fan_div(struct nct6775_data *data)
1322{
1323 int i;
1324
1325 nct6775_update_fan_div_common(data);
1326 /*
1327 * For all fans, start with highest divider value if the divider
1328 * register is not initialized. This ensures that we get a
1329 * reading from the fan count register, even if it is not optimal.
1330 * We'll compute a better divider later on.
1331 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001332 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001333 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001334 continue;
1335 if (data->fan_div[i] == 0) {
1336 data->fan_div[i] = 7;
1337 nct6775_write_fan_div_common(data, i);
1338 }
1339 }
1340}
1341
1342static void nct6775_init_fan_common(struct device *dev,
1343 struct nct6775_data *data)
1344{
1345 int i;
1346 u8 reg;
1347
1348 if (data->has_fan_div)
1349 nct6775_init_fan_div(data);
1350
1351 /*
1352 * If fan_min is not set (0), set it to 0xff to disable it. This
1353 * prevents the unnecessary warning when fanX_min is reported as 0.
1354 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001355 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001356 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001357 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1358 if (!reg)
1359 nct6775_write_value(data, data->REG_FAN_MIN[i],
1360 data->has_fan_div ? 0xff
1361 : 0xff1f);
1362 }
1363 }
1364}
1365
1366static void nct6775_select_fan_div(struct device *dev,
1367 struct nct6775_data *data, int nr, u16 reg)
1368{
1369 u8 fan_div = data->fan_div[nr];
1370 u16 fan_min;
1371
1372 if (!data->has_fan_div)
1373 return;
1374
1375 /*
1376 * If we failed to measure the fan speed, or the reported value is not
1377 * in the optimal range, and the clock divider can be modified,
1378 * let's try that for next time.
1379 */
1380 if (reg == 0x00 && fan_div < 0x07)
1381 fan_div++;
1382 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1383 fan_div--;
1384
1385 if (fan_div != data->fan_div[nr]) {
1386 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1387 nr + 1, div_from_reg(data->fan_div[nr]),
1388 div_from_reg(fan_div));
1389
1390 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001391 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001392 fan_min = data->fan_min[nr];
1393 if (fan_div > data->fan_div[nr]) {
1394 if (fan_min != 255 && fan_min > 1)
1395 fan_min >>= 1;
1396 } else {
1397 if (fan_min != 255) {
1398 fan_min <<= 1;
1399 if (fan_min > 254)
1400 fan_min = 254;
1401 }
1402 }
1403 if (fan_min != data->fan_min[nr]) {
1404 data->fan_min[nr] = fan_min;
1405 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1406 fan_min);
1407 }
1408 }
1409 data->fan_div[nr] = fan_div;
1410 nct6775_write_fan_div_common(data, nr);
1411 }
1412}
1413
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001414static void nct6775_update_pwm(struct device *dev)
1415{
1416 struct nct6775_data *data = dev_get_drvdata(dev);
1417 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001418 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001419 bool duty_is_dc;
1420
1421 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001422 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001423 continue;
1424
1425 duty_is_dc = data->REG_PWM_MODE[i] &&
1426 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1427 & data->PWM_MODE_MASK[i]);
1428 data->pwm_mode[i] = duty_is_dc;
1429
1430 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1431 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1432 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1433 data->pwm[j][i]
1434 = nct6775_read_value(data,
1435 data->REG_PWM[j][i]);
1436 }
1437 }
1438
1439 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1440 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001441
1442 if (!data->temp_tolerance[0][i] ||
1443 data->pwm_enable[i] != speed_cruise)
1444 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1445 if (!data->target_speed_tolerance[i] ||
1446 data->pwm_enable[i] == speed_cruise) {
1447 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001448
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001449 if (data->REG_TOLERANCE_H) {
1450 t |= (nct6775_read_value(data,
1451 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1452 }
1453 data->target_speed_tolerance[i] = t;
1454 }
1455
1456 data->temp_tolerance[1][i] =
1457 nct6775_read_value(data,
1458 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1459
1460 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1461 data->pwm_temp_sel[i] = reg & 0x1f;
1462 /* If fan can stop, report floor as 0 */
1463 if (reg & 0x80)
1464 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001465
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001466 if (!data->REG_WEIGHT_TEMP_SEL[i])
1467 continue;
1468
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001469 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1470 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1471 /* If weight is disabled, report weight source as 0 */
1472 if (j == 1 && !(reg & 0x80))
1473 data->pwm_weight_temp_sel[i] = 0;
1474
1475 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001476 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001477 data->weight_temp[j][i]
1478 = nct6775_read_value(data,
1479 data->REG_WEIGHT_TEMP[j][i]);
1480 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001481 }
1482}
1483
1484static void nct6775_update_pwm_limits(struct device *dev)
1485{
1486 struct nct6775_data *data = dev_get_drvdata(dev);
1487 int i, j;
1488 u8 reg;
1489 u16 reg_t;
1490
1491 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001492 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001493 continue;
1494
Guenter Roeckc409fd42013-04-09 05:04:00 -07001495 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001496 data->fan_time[j][i] =
1497 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1498 }
1499
1500 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1501 /* Update only in matching mode or if never updated */
1502 if (!data->target_temp[i] ||
1503 data->pwm_enable[i] == thermal_cruise)
1504 data->target_temp[i] = reg_t & data->target_temp_mask;
1505 if (!data->target_speed[i] ||
1506 data->pwm_enable[i] == speed_cruise) {
1507 if (data->REG_TOLERANCE_H) {
1508 reg_t |= (nct6775_read_value(data,
1509 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1510 }
1511 data->target_speed[i] = reg_t;
1512 }
1513
1514 for (j = 0; j < data->auto_pwm_num; j++) {
1515 data->auto_pwm[i][j] =
1516 nct6775_read_value(data,
1517 NCT6775_AUTO_PWM(data, i, j));
1518 data->auto_temp[i][j] =
1519 nct6775_read_value(data,
1520 NCT6775_AUTO_TEMP(data, i, j));
1521 }
1522
1523 /* critical auto_pwm temperature data */
1524 data->auto_temp[i][data->auto_pwm_num] =
1525 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1526
1527 switch (data->kind) {
1528 case nct6775:
1529 reg = nct6775_read_value(data,
1530 NCT6775_REG_CRITICAL_ENAB[i]);
1531 data->auto_pwm[i][data->auto_pwm_num] =
1532 (reg & 0x02) ? 0xff : 0x00;
1533 break;
1534 case nct6776:
1535 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1536 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001537 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001538 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001539 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001540 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001541 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001542 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001543 data->REG_CRITICAL_PWM_ENABLE[i]);
1544 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1545 reg = nct6775_read_value(data,
1546 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001547 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001548 reg = 0xff;
1549 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001550 break;
1551 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001552 }
1553}
1554
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001555static struct nct6775_data *nct6775_update_device(struct device *dev)
1556{
1557 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001558 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001559
1560 mutex_lock(&data->update_lock);
1561
Guenter Roeck6445e662013-04-21 09:13:28 -07001562 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001563 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001564 /* Fan clock dividers */
1565 nct6775_update_fan_div_common(data);
1566
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001567 /* Measured voltages and limits */
1568 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001569 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001570 continue;
1571
1572 data->in[i][0] = nct6775_read_value(data,
1573 data->REG_VIN[i]);
1574 data->in[i][1] = nct6775_read_value(data,
1575 data->REG_IN_MINMAX[0][i]);
1576 data->in[i][2] = nct6775_read_value(data,
1577 data->REG_IN_MINMAX[1][i]);
1578 }
1579
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001580 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001581 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001582 u16 reg;
1583
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001584 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001585 continue;
1586
1587 reg = nct6775_read_value(data, data->REG_FAN[i]);
1588 data->rpm[i] = data->fan_from_reg(reg,
1589 data->fan_div[i]);
1590
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001591 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001592 data->fan_min[i] = nct6775_read_value(data,
1593 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001594 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001595 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1596 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001597
1598 nct6775_select_fan_div(dev, data, i, reg);
1599 }
1600
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001601 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001602 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001603
Guenter Roeckaa136e52012-12-04 03:26:05 -08001604 /* Measured temperatures and limits */
1605 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001606 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001607 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001608 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001609 if (data->reg_temp[j][i])
1610 data->temp[j][i]
1611 = nct6775_read_temp(data,
1612 data->reg_temp[j][i]);
1613 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001614 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001615 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001616 continue;
1617 data->temp_offset[i]
1618 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1619 }
1620
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001621 data->alarms = 0;
1622 for (i = 0; i < NUM_REG_ALARM; i++) {
1623 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001624
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001625 if (!data->REG_ALARM[i])
1626 continue;
1627 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1628 data->alarms |= ((u64)alarm) << (i << 3);
1629 }
1630
Guenter Roeck30846992013-06-24 22:21:59 -07001631 data->beeps = 0;
1632 for (i = 0; i < NUM_REG_BEEP; i++) {
1633 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001634
Guenter Roeck30846992013-06-24 22:21:59 -07001635 if (!data->REG_BEEP[i])
1636 continue;
1637 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1638 data->beeps |= ((u64)beep) << (i << 3);
1639 }
1640
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001641 data->last_updated = jiffies;
1642 data->valid = true;
1643 }
1644
1645 mutex_unlock(&data->update_lock);
1646 return data;
1647}
1648
1649/*
1650 * Sysfs callback functions
1651 */
1652static ssize_t
1653show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1654{
1655 struct nct6775_data *data = nct6775_update_device(dev);
1656 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001657 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001658 int nr = sattr->nr;
1659
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001660 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1661}
1662
1663static ssize_t
1664store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1665 size_t count)
1666{
1667 struct nct6775_data *data = dev_get_drvdata(dev);
1668 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001669 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001670 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001671 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001672 int err;
1673
1674 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001675 if (err < 0)
1676 return err;
1677 mutex_lock(&data->update_lock);
1678 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001679 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001680 data->in[nr][index]);
1681 mutex_unlock(&data->update_lock);
1682 return count;
1683}
1684
1685static ssize_t
1686show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1687{
1688 struct nct6775_data *data = nct6775_update_device(dev);
1689 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1690 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001691
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001692 return sprintf(buf, "%u\n",
1693 (unsigned int)((data->alarms >> nr) & 0x01));
1694}
1695
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001696static int find_temp_source(struct nct6775_data *data, int index, int count)
1697{
1698 int source = data->temp_src[index];
1699 int nr;
1700
1701 for (nr = 0; nr < count; nr++) {
1702 int src;
1703
1704 src = nct6775_read_value(data,
1705 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1706 if (src == source)
1707 return nr;
1708 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001709 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001710}
1711
1712static ssize_t
1713show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1714{
1715 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1716 struct nct6775_data *data = nct6775_update_device(dev);
1717 unsigned int alarm = 0;
1718 int nr;
1719
1720 /*
1721 * For temperatures, there is no fixed mapping from registers to alarm
1722 * bits. Alarm bits are determined by the temperature source mapping.
1723 */
1724 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1725 if (nr >= 0) {
1726 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001727
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001728 alarm = (data->alarms >> bit) & 0x01;
1729 }
1730 return sprintf(buf, "%u\n", alarm);
1731}
1732
Guenter Roeck30846992013-06-24 22:21:59 -07001733static ssize_t
1734show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1735{
1736 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1737 struct nct6775_data *data = nct6775_update_device(dev);
1738 int nr = data->BEEP_BITS[sattr->index];
1739
1740 return sprintf(buf, "%u\n",
1741 (unsigned int)((data->beeps >> nr) & 0x01));
1742}
1743
1744static ssize_t
1745store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1746 size_t count)
1747{
1748 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1749 struct nct6775_data *data = dev_get_drvdata(dev);
1750 int nr = data->BEEP_BITS[sattr->index];
1751 int regindex = nr >> 3;
1752 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001753 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001754
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001755 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001756 if (err < 0)
1757 return err;
1758 if (val > 1)
1759 return -EINVAL;
1760
1761 mutex_lock(&data->update_lock);
1762 if (val)
1763 data->beeps |= (1ULL << nr);
1764 else
1765 data->beeps &= ~(1ULL << nr);
1766 nct6775_write_value(data, data->REG_BEEP[regindex],
1767 (data->beeps >> (regindex << 3)) & 0xff);
1768 mutex_unlock(&data->update_lock);
1769 return count;
1770}
1771
1772static ssize_t
1773show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1774{
1775 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1776 struct nct6775_data *data = nct6775_update_device(dev);
1777 unsigned int beep = 0;
1778 int nr;
1779
1780 /*
1781 * For temperatures, there is no fixed mapping from registers to beep
1782 * enable bits. Beep enable bits are determined by the temperature
1783 * source mapping.
1784 */
1785 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1786 if (nr >= 0) {
1787 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001788
Guenter Roeck30846992013-06-24 22:21:59 -07001789 beep = (data->beeps >> bit) & 0x01;
1790 }
1791 return sprintf(buf, "%u\n", beep);
1792}
1793
1794static ssize_t
1795store_temp_beep(struct device *dev, struct device_attribute *attr,
1796 const char *buf, size_t count)
1797{
1798 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1799 struct nct6775_data *data = dev_get_drvdata(dev);
1800 int nr, bit, regindex;
1801 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001802 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001803
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001804 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001805 if (err < 0)
1806 return err;
1807 if (val > 1)
1808 return -EINVAL;
1809
1810 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1811 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001812 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001813
1814 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1815 regindex = bit >> 3;
1816
1817 mutex_lock(&data->update_lock);
1818 if (val)
1819 data->beeps |= (1ULL << bit);
1820 else
1821 data->beeps &= ~(1ULL << bit);
1822 nct6775_write_value(data, data->REG_BEEP[regindex],
1823 (data->beeps >> (regindex << 3)) & 0xff);
1824 mutex_unlock(&data->update_lock);
1825
1826 return count;
1827}
1828
Guenter Roeckf73cf632013-03-18 09:22:50 -07001829static umode_t nct6775_in_is_visible(struct kobject *kobj,
1830 struct attribute *attr, int index)
1831{
1832 struct device *dev = container_of(kobj, struct device, kobj);
1833 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001834 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001835
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001836 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001837 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001838
Guenter Roeckf73cf632013-03-18 09:22:50 -07001839 return attr->mode;
1840}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001841
Guenter Roeckf73cf632013-03-18 09:22:50 -07001842SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1843SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001844SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1845 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001846SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1847 store_in_reg, 0, 1);
1848SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1849 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001850
Guenter Roeckf73cf632013-03-18 09:22:50 -07001851/*
1852 * nct6775_in_is_visible uses the index into the following array
1853 * to determine if attributes should be created or not.
1854 * Any change in order or content must be matched.
1855 */
1856static struct sensor_device_template *nct6775_attributes_in_template[] = {
1857 &sensor_dev_template_in_input,
1858 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001859 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001860 &sensor_dev_template_in_min,
1861 &sensor_dev_template_in_max,
1862 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001863};
1864
Julia Lawallc60fdf82015-12-12 17:36:39 +01001865static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001866 .templates = nct6775_attributes_in_template,
1867 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001868};
1869
1870static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001871show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1872{
1873 struct nct6775_data *data = nct6775_update_device(dev);
1874 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1875 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001876
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001877 return sprintf(buf, "%d\n", data->rpm[nr]);
1878}
1879
1880static ssize_t
1881show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1882{
1883 struct nct6775_data *data = nct6775_update_device(dev);
1884 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1885 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001886
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001887 return sprintf(buf, "%d\n",
1888 data->fan_from_reg_min(data->fan_min[nr],
1889 data->fan_div[nr]));
1890}
1891
1892static ssize_t
1893show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1894{
1895 struct nct6775_data *data = nct6775_update_device(dev);
1896 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1897 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001898
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001899 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1900}
1901
1902static ssize_t
1903store_fan_min(struct device *dev, struct device_attribute *attr,
1904 const char *buf, size_t count)
1905{
1906 struct nct6775_data *data = dev_get_drvdata(dev);
1907 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1908 int nr = sattr->index;
1909 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001910 unsigned int reg;
1911 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001912 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001913
1914 err = kstrtoul(buf, 10, &val);
1915 if (err < 0)
1916 return err;
1917
1918 mutex_lock(&data->update_lock);
1919 if (!data->has_fan_div) {
1920 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1921 if (!val) {
1922 val = 0xff1f;
1923 } else {
1924 if (val > 1350000U)
1925 val = 135000U;
1926 val = 1350000U / val;
1927 val = (val & 0x1f) | ((val << 3) & 0xff00);
1928 }
1929 data->fan_min[nr] = val;
1930 goto write_min; /* Leave fan divider alone */
1931 }
1932 if (!val) {
1933 /* No min limit, alarm disabled */
1934 data->fan_min[nr] = 255;
1935 new_div = data->fan_div[nr]; /* No change */
1936 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1937 goto write_div;
1938 }
1939 reg = 1350000U / val;
1940 if (reg >= 128 * 255) {
1941 /*
1942 * Speed below this value cannot possibly be represented,
1943 * even with the highest divider (128)
1944 */
1945 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001946 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001947 dev_warn(dev,
1948 "fan%u low limit %lu below minimum %u, set to minimum\n",
1949 nr + 1, val, data->fan_from_reg_min(254, 7));
1950 } else if (!reg) {
1951 /*
1952 * Speed above this value cannot possibly be represented,
1953 * even with the lowest divider (1)
1954 */
1955 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001956 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001957 dev_warn(dev,
1958 "fan%u low limit %lu above maximum %u, set to maximum\n",
1959 nr + 1, val, data->fan_from_reg_min(1, 0));
1960 } else {
1961 /*
1962 * Automatically pick the best divider, i.e. the one such
1963 * that the min limit will correspond to a register value
1964 * in the 96..192 range
1965 */
1966 new_div = 0;
1967 while (reg > 192 && new_div < 7) {
1968 reg >>= 1;
1969 new_div++;
1970 }
1971 data->fan_min[nr] = reg;
1972 }
1973
1974write_div:
1975 /*
1976 * Write both the fan clock divider (if it changed) and the new
1977 * fan min (unconditionally)
1978 */
1979 if (new_div != data->fan_div[nr]) {
1980 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1981 nr + 1, div_from_reg(data->fan_div[nr]),
1982 div_from_reg(new_div));
1983 data->fan_div[nr] = new_div;
1984 nct6775_write_fan_div_common(data, nr);
1985 /* Give the chip time to sample a new speed value */
1986 data->last_updated = jiffies;
1987 }
1988
1989write_min:
1990 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1991 mutex_unlock(&data->update_lock);
1992
1993 return count;
1994}
1995
Guenter Roeck5c25d952012-12-11 07:29:06 -08001996static ssize_t
1997show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1998{
1999 struct nct6775_data *data = nct6775_update_device(dev);
2000 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2001 int p = data->fan_pulses[sattr->index];
2002
2003 return sprintf(buf, "%d\n", p ? : 4);
2004}
2005
2006static ssize_t
2007store_fan_pulses(struct device *dev, struct device_attribute *attr,
2008 const char *buf, size_t count)
2009{
2010 struct nct6775_data *data = dev_get_drvdata(dev);
2011 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2012 int nr = sattr->index;
2013 unsigned long val;
2014 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002015 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002016
2017 err = kstrtoul(buf, 10, &val);
2018 if (err < 0)
2019 return err;
2020
2021 if (val > 4)
2022 return -EINVAL;
2023
2024 mutex_lock(&data->update_lock);
2025 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002026 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2027 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2028 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2029 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002030 mutex_unlock(&data->update_lock);
2031
2032 return count;
2033}
2034
Guenter Roeckf73cf632013-03-18 09:22:50 -07002035static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2036 struct attribute *attr, int index)
2037{
2038 struct device *dev = container_of(kobj, struct device, kobj);
2039 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002040 int fan = index / 6; /* fan index */
2041 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002042
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002043 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002044 return 0;
2045
2046 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2047 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002048 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002049 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002050 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002051 return 0;
2052 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002053 return 0;
2054
2055 return attr->mode;
2056}
2057
2058SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2059SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2060 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002061SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2062 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002063SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2064 store_fan_pulses, 0);
2065SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2066 store_fan_min, 0);
2067SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2068
2069/*
2070 * nct6775_fan_is_visible uses the index into the following array
2071 * to determine if attributes should be created or not.
2072 * Any change in order or content must be matched.
2073 */
2074static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2075 &sensor_dev_template_fan_input,
2076 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002077 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002078 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002079 &sensor_dev_template_fan_min, /* 4 */
2080 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002081 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002082};
2083
Julia Lawallc60fdf82015-12-12 17:36:39 +01002084static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002085 .templates = nct6775_attributes_fan_template,
2086 .is_visible = nct6775_fan_is_visible,
2087 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002088};
2089
2090static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002091show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2092{
2093 struct nct6775_data *data = nct6775_update_device(dev);
2094 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2095 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002096
Guenter Roeckaa136e52012-12-04 03:26:05 -08002097 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2098}
2099
2100static ssize_t
2101show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2102{
2103 struct nct6775_data *data = nct6775_update_device(dev);
2104 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2105 int nr = sattr->nr;
2106 int index = sattr->index;
2107
2108 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2109}
2110
2111static ssize_t
2112store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2113 size_t count)
2114{
2115 struct nct6775_data *data = dev_get_drvdata(dev);
2116 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2117 int nr = sattr->nr;
2118 int index = sattr->index;
2119 int err;
2120 long val;
2121
2122 err = kstrtol(buf, 10, &val);
2123 if (err < 0)
2124 return err;
2125
2126 mutex_lock(&data->update_lock);
2127 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2128 nct6775_write_temp(data, data->reg_temp[index][nr],
2129 data->temp[index][nr]);
2130 mutex_unlock(&data->update_lock);
2131 return count;
2132}
2133
2134static ssize_t
2135show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2136{
2137 struct nct6775_data *data = nct6775_update_device(dev);
2138 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2139
2140 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2141}
2142
2143static ssize_t
2144store_temp_offset(struct device *dev, struct device_attribute *attr,
2145 const char *buf, size_t count)
2146{
2147 struct nct6775_data *data = dev_get_drvdata(dev);
2148 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2149 int nr = sattr->index;
2150 long val;
2151 int err;
2152
2153 err = kstrtol(buf, 10, &val);
2154 if (err < 0)
2155 return err;
2156
2157 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2158
2159 mutex_lock(&data->update_lock);
2160 data->temp_offset[nr] = val;
2161 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2162 mutex_unlock(&data->update_lock);
2163
2164 return count;
2165}
2166
2167static ssize_t
2168show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2169{
2170 struct nct6775_data *data = nct6775_update_device(dev);
2171 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2172 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002173
Guenter Roeckaa136e52012-12-04 03:26:05 -08002174 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2175}
2176
2177static ssize_t
2178store_temp_type(struct device *dev, struct device_attribute *attr,
2179 const char *buf, size_t count)
2180{
2181 struct nct6775_data *data = nct6775_update_device(dev);
2182 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2183 int nr = sattr->index;
2184 unsigned long val;
2185 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002186 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002187
2188 err = kstrtoul(buf, 10, &val);
2189 if (err < 0)
2190 return err;
2191
2192 if (val != 1 && val != 3 && val != 4)
2193 return -EINVAL;
2194
2195 mutex_lock(&data->update_lock);
2196
2197 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002198 vbit = 0x02 << nr;
2199 dbit = data->DIODE_MASK << nr;
2200 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2201 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002202 switch (val) {
2203 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002204 vbat |= vbit;
2205 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002206 break;
2207 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002208 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002209 break;
2210 case 4: /* thermistor */
2211 break;
2212 }
2213 nct6775_write_value(data, data->REG_VBAT, vbat);
2214 nct6775_write_value(data, data->REG_DIODE, diode);
2215
2216 mutex_unlock(&data->update_lock);
2217 return count;
2218}
2219
Guenter Roeckf73cf632013-03-18 09:22:50 -07002220static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2221 struct attribute *attr, int index)
2222{
2223 struct device *dev = container_of(kobj, struct device, kobj);
2224 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002225 int temp = index / 10; /* temp index */
2226 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002227
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002228 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002229 return 0;
2230
Guenter Roeckcc66b302017-05-17 18:05:06 -07002231 if (nr == 1 && !data->temp_label)
2232 return 0;
2233
Guenter Roeckf73cf632013-03-18 09:22:50 -07002234 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2235 return 0; /* alarm */
2236
Guenter Roeck30846992013-06-24 22:21:59 -07002237 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2238 return 0; /* beep */
2239
2240 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002241 return 0;
2242
Guenter Roeck30846992013-06-24 22:21:59 -07002243 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002244 return 0;
2245
Guenter Roeck30846992013-06-24 22:21:59 -07002246 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002247 return 0;
2248
Guenter Roeck30846992013-06-24 22:21:59 -07002249 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002250 return 0;
2251
2252 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002253 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002254 return 0;
2255
2256 return attr->mode;
2257}
2258
2259SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2260SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2261SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2262 store_temp, 0, 1);
2263SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2264 show_temp, store_temp, 0, 2);
2265SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2266 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002267SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2268 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002269SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2270 show_temp_offset, store_temp_offset, 0);
2271SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2272 store_temp_type, 0);
2273SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002274SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2275 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002276
2277/*
2278 * nct6775_temp_is_visible uses the index into the following array
2279 * to determine if attributes should be created or not.
2280 * Any change in order or content must be matched.
2281 */
2282static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2283 &sensor_dev_template_temp_input,
2284 &sensor_dev_template_temp_label,
2285 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002286 &sensor_dev_template_temp_beep, /* 3 */
2287 &sensor_dev_template_temp_max, /* 4 */
2288 &sensor_dev_template_temp_max_hyst, /* 5 */
2289 &sensor_dev_template_temp_crit, /* 6 */
2290 &sensor_dev_template_temp_lcrit, /* 7 */
2291 &sensor_dev_template_temp_offset, /* 8 */
2292 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002293 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002294};
2295
Julia Lawallc60fdf82015-12-12 17:36:39 +01002296static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002297 .templates = nct6775_attributes_temp_template,
2298 .is_visible = nct6775_temp_is_visible,
2299 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002300};
2301
Guenter Roeckaa136e52012-12-04 03:26:05 -08002302static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002303show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2304{
2305 struct nct6775_data *data = nct6775_update_device(dev);
2306 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2307
2308 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2309}
2310
2311static ssize_t
2312store_pwm_mode(struct device *dev, struct device_attribute *attr,
2313 const char *buf, size_t count)
2314{
2315 struct nct6775_data *data = dev_get_drvdata(dev);
2316 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2317 int nr = sattr->index;
2318 unsigned long val;
2319 int err;
2320 u8 reg;
2321
2322 err = kstrtoul(buf, 10, &val);
2323 if (err < 0)
2324 return err;
2325
2326 if (val > 1)
2327 return -EINVAL;
2328
2329 /* Setting DC mode is not supported for all chips/channels */
2330 if (data->REG_PWM_MODE[nr] == 0) {
2331 if (val)
2332 return -EINVAL;
2333 return count;
2334 }
2335
2336 mutex_lock(&data->update_lock);
2337 data->pwm_mode[nr] = val;
2338 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2339 reg &= ~data->PWM_MODE_MASK[nr];
2340 if (val)
2341 reg |= data->PWM_MODE_MASK[nr];
2342 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2343 mutex_unlock(&data->update_lock);
2344 return count;
2345}
2346
2347static ssize_t
2348show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2349{
2350 struct nct6775_data *data = nct6775_update_device(dev);
2351 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2352 int nr = sattr->nr;
2353 int index = sattr->index;
2354 int pwm;
2355
2356 /*
2357 * For automatic fan control modes, show current pwm readings.
2358 * Otherwise, show the configured value.
2359 */
2360 if (index == 0 && data->pwm_enable[nr] > manual)
2361 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2362 else
2363 pwm = data->pwm[index][nr];
2364
2365 return sprintf(buf, "%d\n", pwm);
2366}
2367
2368static ssize_t
2369store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2370 size_t count)
2371{
2372 struct nct6775_data *data = dev_get_drvdata(dev);
2373 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2374 int nr = sattr->nr;
2375 int index = sattr->index;
2376 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002377 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2378 int maxval[7]
2379 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002380 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002381 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002382
2383 err = kstrtoul(buf, 10, &val);
2384 if (err < 0)
2385 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002386 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002387
2388 mutex_lock(&data->update_lock);
2389 data->pwm[index][nr] = val;
2390 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002391 if (index == 2) { /* floor: disable if val == 0 */
2392 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2393 reg &= 0x7f;
2394 if (val)
2395 reg |= 0x80;
2396 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2397 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002398 mutex_unlock(&data->update_lock);
2399 return count;
2400}
2401
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002402/* Returns 0 if OK, -EINVAL otherwise */
2403static int check_trip_points(struct nct6775_data *data, int nr)
2404{
2405 int i;
2406
2407 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2408 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2409 return -EINVAL;
2410 }
2411 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2412 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2413 return -EINVAL;
2414 }
2415 /* validate critical temperature and pwm if enabled (pwm > 0) */
2416 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2417 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2418 data->auto_temp[nr][data->auto_pwm_num] ||
2419 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2420 data->auto_pwm[nr][data->auto_pwm_num])
2421 return -EINVAL;
2422 }
2423 return 0;
2424}
2425
2426static void pwm_update_registers(struct nct6775_data *data, int nr)
2427{
2428 u8 reg;
2429
2430 switch (data->pwm_enable[nr]) {
2431 case off:
2432 case manual:
2433 break;
2434 case speed_cruise:
2435 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2436 reg = (reg & ~data->tolerance_mask) |
2437 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2438 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2439 nct6775_write_value(data, data->REG_TARGET[nr],
2440 data->target_speed[nr] & 0xff);
2441 if (data->REG_TOLERANCE_H) {
2442 reg = (data->target_speed[nr] >> 8) & 0x0f;
2443 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2444 nct6775_write_value(data,
2445 data->REG_TOLERANCE_H[nr],
2446 reg);
2447 }
2448 break;
2449 case thermal_cruise:
2450 nct6775_write_value(data, data->REG_TARGET[nr],
2451 data->target_temp[nr]);
2452 /* intentional */
2453 default:
2454 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2455 reg = (reg & ~data->tolerance_mask) |
2456 data->temp_tolerance[0][nr];
2457 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2458 break;
2459 }
2460}
2461
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002462static ssize_t
2463show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2464{
2465 struct nct6775_data *data = nct6775_update_device(dev);
2466 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2467
2468 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2469}
2470
2471static ssize_t
2472store_pwm_enable(struct device *dev, struct device_attribute *attr,
2473 const char *buf, size_t count)
2474{
2475 struct nct6775_data *data = dev_get_drvdata(dev);
2476 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2477 int nr = sattr->index;
2478 unsigned long val;
2479 int err;
2480 u16 reg;
2481
2482 err = kstrtoul(buf, 10, &val);
2483 if (err < 0)
2484 return err;
2485
2486 if (val > sf4)
2487 return -EINVAL;
2488
2489 if (val == sf3 && data->kind != nct6775)
2490 return -EINVAL;
2491
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002492 if (val == sf4 && check_trip_points(data, nr)) {
2493 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2494 dev_err(dev, "Adjust trip points and try again\n");
2495 return -EINVAL;
2496 }
2497
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002498 mutex_lock(&data->update_lock);
2499 data->pwm_enable[nr] = val;
2500 if (val == off) {
2501 /*
2502 * turn off pwm control: select manual mode, set pwm to maximum
2503 */
2504 data->pwm[0][nr] = 255;
2505 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2506 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002507 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002508 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2509 reg &= 0x0f;
2510 reg |= pwm_enable_to_reg(val) << 4;
2511 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2512 mutex_unlock(&data->update_lock);
2513 return count;
2514}
2515
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002516static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002517show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002518{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002519 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002520
2521 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002522 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002523 continue;
2524 if (src == data->temp_src[i]) {
2525 sel = i + 1;
2526 break;
2527 }
2528 }
2529
2530 return sprintf(buf, "%d\n", sel);
2531}
2532
2533static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002534show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2535{
2536 struct nct6775_data *data = nct6775_update_device(dev);
2537 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2538 int index = sattr->index;
2539
2540 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2541}
2542
2543static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002544store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2545 const char *buf, size_t count)
2546{
2547 struct nct6775_data *data = nct6775_update_device(dev);
2548 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2549 int nr = sattr->index;
2550 unsigned long val;
2551 int err, reg, src;
2552
2553 err = kstrtoul(buf, 10, &val);
2554 if (err < 0)
2555 return err;
2556 if (val == 0 || val > NUM_TEMP)
2557 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002558 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002559 return -EINVAL;
2560
2561 mutex_lock(&data->update_lock);
2562 src = data->temp_src[val - 1];
2563 data->pwm_temp_sel[nr] = src;
2564 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2565 reg &= 0xe0;
2566 reg |= src;
2567 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2568 mutex_unlock(&data->update_lock);
2569
2570 return count;
2571}
2572
2573static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002574show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2575 char *buf)
2576{
2577 struct nct6775_data *data = nct6775_update_device(dev);
2578 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2579 int index = sattr->index;
2580
2581 return show_pwm_temp_sel_common(data, buf,
2582 data->pwm_weight_temp_sel[index]);
2583}
2584
2585static ssize_t
2586store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2587 const char *buf, size_t count)
2588{
2589 struct nct6775_data *data = nct6775_update_device(dev);
2590 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2591 int nr = sattr->index;
2592 unsigned long val;
2593 int err, reg, src;
2594
2595 err = kstrtoul(buf, 10, &val);
2596 if (err < 0)
2597 return err;
2598 if (val > NUM_TEMP)
2599 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002600 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002601 !data->temp_src[val - 1]))
2602 return -EINVAL;
2603
2604 mutex_lock(&data->update_lock);
2605 if (val) {
2606 src = data->temp_src[val - 1];
2607 data->pwm_weight_temp_sel[nr] = src;
2608 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2609 reg &= 0xe0;
2610 reg |= (src | 0x80);
2611 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2612 } else {
2613 data->pwm_weight_temp_sel[nr] = 0;
2614 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2615 reg &= 0x7f;
2616 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2617 }
2618 mutex_unlock(&data->update_lock);
2619
2620 return count;
2621}
2622
2623static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002624show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2625{
2626 struct nct6775_data *data = nct6775_update_device(dev);
2627 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2628
2629 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2630}
2631
2632static ssize_t
2633store_target_temp(struct device *dev, struct device_attribute *attr,
2634 const char *buf, size_t count)
2635{
2636 struct nct6775_data *data = dev_get_drvdata(dev);
2637 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2638 int nr = sattr->index;
2639 unsigned long val;
2640 int err;
2641
2642 err = kstrtoul(buf, 10, &val);
2643 if (err < 0)
2644 return err;
2645
2646 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2647 data->target_temp_mask);
2648
2649 mutex_lock(&data->update_lock);
2650 data->target_temp[nr] = val;
2651 pwm_update_registers(data, nr);
2652 mutex_unlock(&data->update_lock);
2653 return count;
2654}
2655
2656static ssize_t
2657show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2658{
2659 struct nct6775_data *data = nct6775_update_device(dev);
2660 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2661 int nr = sattr->index;
2662
2663 return sprintf(buf, "%d\n",
2664 fan_from_reg16(data->target_speed[nr],
2665 data->fan_div[nr]));
2666}
2667
2668static ssize_t
2669store_target_speed(struct device *dev, struct device_attribute *attr,
2670 const char *buf, size_t count)
2671{
2672 struct nct6775_data *data = dev_get_drvdata(dev);
2673 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2674 int nr = sattr->index;
2675 unsigned long val;
2676 int err;
2677 u16 speed;
2678
2679 err = kstrtoul(buf, 10, &val);
2680 if (err < 0)
2681 return err;
2682
2683 val = clamp_val(val, 0, 1350000U);
2684 speed = fan_to_reg(val, data->fan_div[nr]);
2685
2686 mutex_lock(&data->update_lock);
2687 data->target_speed[nr] = speed;
2688 pwm_update_registers(data, nr);
2689 mutex_unlock(&data->update_lock);
2690 return count;
2691}
2692
2693static ssize_t
2694show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2695 char *buf)
2696{
2697 struct nct6775_data *data = nct6775_update_device(dev);
2698 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2699 int nr = sattr->nr;
2700 int index = sattr->index;
2701
2702 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2703}
2704
2705static ssize_t
2706store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2707 const char *buf, size_t count)
2708{
2709 struct nct6775_data *data = dev_get_drvdata(dev);
2710 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2711 int nr = sattr->nr;
2712 int index = sattr->index;
2713 unsigned long val;
2714 int err;
2715
2716 err = kstrtoul(buf, 10, &val);
2717 if (err < 0)
2718 return err;
2719
2720 /* Limit tolerance as needed */
2721 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2722
2723 mutex_lock(&data->update_lock);
2724 data->temp_tolerance[index][nr] = val;
2725 if (index)
2726 pwm_update_registers(data, nr);
2727 else
2728 nct6775_write_value(data,
2729 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2730 val);
2731 mutex_unlock(&data->update_lock);
2732 return count;
2733}
2734
2735/*
2736 * Fan speed tolerance is a tricky beast, since the associated register is
2737 * a tick counter, but the value is reported and configured as rpm.
2738 * Compute resulting low and high rpm values and report the difference.
2739 */
2740static ssize_t
2741show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2742 char *buf)
2743{
2744 struct nct6775_data *data = nct6775_update_device(dev);
2745 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2746 int nr = sattr->index;
2747 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2748 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2749 int tolerance;
2750
2751 if (low <= 0)
2752 low = 1;
2753 if (high > 0xffff)
2754 high = 0xffff;
2755 if (high < low)
2756 high = low;
2757
2758 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2759 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2760
2761 return sprintf(buf, "%d\n", tolerance);
2762}
2763
2764static ssize_t
2765store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2766 const char *buf, size_t count)
2767{
2768 struct nct6775_data *data = dev_get_drvdata(dev);
2769 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2770 int nr = sattr->index;
2771 unsigned long val;
2772 int err;
2773 int low, high;
2774
2775 err = kstrtoul(buf, 10, &val);
2776 if (err < 0)
2777 return err;
2778
2779 high = fan_from_reg16(data->target_speed[nr],
2780 data->fan_div[nr]) + val;
2781 low = fan_from_reg16(data->target_speed[nr],
2782 data->fan_div[nr]) - val;
2783 if (low <= 0)
2784 low = 1;
2785 if (high < low)
2786 high = low;
2787
2788 val = (fan_to_reg(low, data->fan_div[nr]) -
2789 fan_to_reg(high, data->fan_div[nr])) / 2;
2790
2791 /* Limit tolerance as needed */
2792 val = clamp_val(val, 0, data->speed_tolerance_limit);
2793
2794 mutex_lock(&data->update_lock);
2795 data->target_speed_tolerance[nr] = val;
2796 pwm_update_registers(data, nr);
2797 mutex_unlock(&data->update_lock);
2798 return count;
2799}
2800
Guenter Roeckf73cf632013-03-18 09:22:50 -07002801SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2802SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2803 store_pwm_mode, 0);
2804SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2805 store_pwm_enable, 0);
2806SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2807 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2808SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2809 show_target_temp, store_target_temp, 0);
2810SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2811 show_target_speed, store_target_speed, 0);
2812SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2813 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002814
2815/* Smart Fan registers */
2816
2817static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002818show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2819{
2820 struct nct6775_data *data = nct6775_update_device(dev);
2821 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2822 int nr = sattr->nr;
2823 int index = sattr->index;
2824
2825 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2826}
2827
2828static ssize_t
2829store_weight_temp(struct device *dev, struct device_attribute *attr,
2830 const char *buf, size_t count)
2831{
2832 struct nct6775_data *data = dev_get_drvdata(dev);
2833 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2834 int nr = sattr->nr;
2835 int index = sattr->index;
2836 unsigned long val;
2837 int err;
2838
2839 err = kstrtoul(buf, 10, &val);
2840 if (err < 0)
2841 return err;
2842
2843 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2844
2845 mutex_lock(&data->update_lock);
2846 data->weight_temp[index][nr] = val;
2847 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2848 mutex_unlock(&data->update_lock);
2849 return count;
2850}
2851
Guenter Roeckf73cf632013-03-18 09:22:50 -07002852SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2853 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2854SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2855 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2856SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2857 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2858SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2859 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2860SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2861 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2862SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2863 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002864
2865static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002866show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2867{
2868 struct nct6775_data *data = nct6775_update_device(dev);
2869 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2870 int nr = sattr->nr;
2871 int index = sattr->index;
2872
2873 return sprintf(buf, "%d\n",
2874 step_time_from_reg(data->fan_time[index][nr],
2875 data->pwm_mode[nr]));
2876}
2877
2878static ssize_t
2879store_fan_time(struct device *dev, struct device_attribute *attr,
2880 const char *buf, size_t count)
2881{
2882 struct nct6775_data *data = dev_get_drvdata(dev);
2883 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2884 int nr = sattr->nr;
2885 int index = sattr->index;
2886 unsigned long val;
2887 int err;
2888
2889 err = kstrtoul(buf, 10, &val);
2890 if (err < 0)
2891 return err;
2892
2893 val = step_time_to_reg(val, data->pwm_mode[nr]);
2894 mutex_lock(&data->update_lock);
2895 data->fan_time[index][nr] = val;
2896 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2897 mutex_unlock(&data->update_lock);
2898 return count;
2899}
2900
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002901static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002902show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2903{
2904 struct nct6775_data *data = nct6775_update_device(dev);
2905 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2906
2907 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2908}
2909
2910static ssize_t
2911store_auto_pwm(struct device *dev, struct device_attribute *attr,
2912 const char *buf, size_t count)
2913{
2914 struct nct6775_data *data = dev_get_drvdata(dev);
2915 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2916 int nr = sattr->nr;
2917 int point = sattr->index;
2918 unsigned long val;
2919 int err;
2920 u8 reg;
2921
2922 err = kstrtoul(buf, 10, &val);
2923 if (err < 0)
2924 return err;
2925 if (val > 255)
2926 return -EINVAL;
2927
2928 if (point == data->auto_pwm_num) {
2929 if (data->kind != nct6775 && !val)
2930 return -EINVAL;
2931 if (data->kind != nct6779 && val)
2932 val = 0xff;
2933 }
2934
2935 mutex_lock(&data->update_lock);
2936 data->auto_pwm[nr][point] = val;
2937 if (point < data->auto_pwm_num) {
2938 nct6775_write_value(data,
2939 NCT6775_AUTO_PWM(data, nr, point),
2940 data->auto_pwm[nr][point]);
2941 } else {
2942 switch (data->kind) {
2943 case nct6775:
2944 /* disable if needed (pwm == 0) */
2945 reg = nct6775_read_value(data,
2946 NCT6775_REG_CRITICAL_ENAB[nr]);
2947 if (val)
2948 reg |= 0x02;
2949 else
2950 reg &= ~0x02;
2951 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2952 reg);
2953 break;
2954 case nct6776:
2955 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002956 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002957 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002958 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002959 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002960 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002961 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002962 val);
2963 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002964 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002965 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002966 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002967 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002968 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002969 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002970 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002971 reg);
2972 break;
2973 }
2974 }
2975 mutex_unlock(&data->update_lock);
2976 return count;
2977}
2978
2979static ssize_t
2980show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2981{
2982 struct nct6775_data *data = nct6775_update_device(dev);
2983 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2984 int nr = sattr->nr;
2985 int point = sattr->index;
2986
2987 /*
2988 * We don't know for sure if the temperature is signed or unsigned.
2989 * Assume it is unsigned.
2990 */
2991 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2992}
2993
2994static ssize_t
2995store_auto_temp(struct device *dev, struct device_attribute *attr,
2996 const char *buf, size_t count)
2997{
2998 struct nct6775_data *data = dev_get_drvdata(dev);
2999 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3000 int nr = sattr->nr;
3001 int point = sattr->index;
3002 unsigned long val;
3003 int err;
3004
3005 err = kstrtoul(buf, 10, &val);
3006 if (err)
3007 return err;
3008 if (val > 255000)
3009 return -EINVAL;
3010
3011 mutex_lock(&data->update_lock);
3012 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3013 if (point < data->auto_pwm_num) {
3014 nct6775_write_value(data,
3015 NCT6775_AUTO_TEMP(data, nr, point),
3016 data->auto_temp[nr][point]);
3017 } else {
3018 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3019 data->auto_temp[nr][point]);
3020 }
3021 mutex_unlock(&data->update_lock);
3022 return count;
3023}
3024
Guenter Roeckf73cf632013-03-18 09:22:50 -07003025static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3026 struct attribute *attr, int index)
3027{
3028 struct device *dev = container_of(kobj, struct device, kobj);
3029 struct nct6775_data *data = dev_get_drvdata(dev);
3030 int pwm = index / 36; /* pwm index */
3031 int nr = index % 36; /* attribute index */
3032
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003033 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003034 return 0;
3035
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003036 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3037 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3038 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003039 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3040 return 0;
3041 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3042 return 0;
3043 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3044 return 0;
3045
3046 if (nr >= 22 && nr <= 35) { /* auto point */
3047 int api = (nr - 22) / 2; /* auto point index */
3048
3049 if (api > data->auto_pwm_num)
3050 return 0;
3051 }
3052 return attr->mode;
3053}
3054
3055SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3056 show_fan_time, store_fan_time, 0, 0);
3057SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3058 show_fan_time, store_fan_time, 0, 1);
3059SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3060 show_fan_time, store_fan_time, 0, 2);
3061SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3062 store_pwm, 0, 1);
3063SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3064 store_pwm, 0, 2);
3065SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3066 show_temp_tolerance, store_temp_tolerance, 0, 0);
3067SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3068 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3069 0, 1);
3070
3071SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3072 0, 3);
3073
3074SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3075 store_pwm, 0, 4);
3076
3077SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3078 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3079SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3080 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3081
3082SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3083 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3084SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3085 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3086
3087SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3088 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3089SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3090 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3091
3092SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3093 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3094SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3095 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3096
3097SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3098 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3099SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3100 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3101
3102SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3103 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3104SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3105 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3106
3107SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3108 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3109SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3110 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3111
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003112/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003113 * nct6775_pwm_is_visible uses the index into the following array
3114 * to determine if attributes should be created or not.
3115 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003116 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003117static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3118 &sensor_dev_template_pwm,
3119 &sensor_dev_template_pwm_mode,
3120 &sensor_dev_template_pwm_enable,
3121 &sensor_dev_template_pwm_temp_sel,
3122 &sensor_dev_template_pwm_temp_tolerance,
3123 &sensor_dev_template_pwm_crit_temp_tolerance,
3124 &sensor_dev_template_pwm_target_temp,
3125 &sensor_dev_template_fan_target,
3126 &sensor_dev_template_fan_tolerance,
3127 &sensor_dev_template_pwm_stop_time,
3128 &sensor_dev_template_pwm_step_up_time,
3129 &sensor_dev_template_pwm_step_down_time,
3130 &sensor_dev_template_pwm_start,
3131 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003132 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003133 &sensor_dev_template_pwm_weight_temp_step,
3134 &sensor_dev_template_pwm_weight_temp_step_tol,
3135 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003136 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003137 &sensor_dev_template_pwm_max, /* 19 */
3138 &sensor_dev_template_pwm_step, /* 20 */
3139 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3140 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3141 &sensor_dev_template_pwm_auto_point1_temp,
3142 &sensor_dev_template_pwm_auto_point2_pwm,
3143 &sensor_dev_template_pwm_auto_point2_temp,
3144 &sensor_dev_template_pwm_auto_point3_pwm,
3145 &sensor_dev_template_pwm_auto_point3_temp,
3146 &sensor_dev_template_pwm_auto_point4_pwm,
3147 &sensor_dev_template_pwm_auto_point4_temp,
3148 &sensor_dev_template_pwm_auto_point5_pwm,
3149 &sensor_dev_template_pwm_auto_point5_temp,
3150 &sensor_dev_template_pwm_auto_point6_pwm,
3151 &sensor_dev_template_pwm_auto_point6_temp,
3152 &sensor_dev_template_pwm_auto_point7_pwm,
3153 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003154
Guenter Roeckf73cf632013-03-18 09:22:50 -07003155 NULL
3156};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003157
Julia Lawallc60fdf82015-12-12 17:36:39 +01003158static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003159 .templates = nct6775_attributes_pwm_template,
3160 .is_visible = nct6775_pwm_is_visible,
3161 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003162};
3163
3164static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003165cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003166{
3167 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003168
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003169 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3170}
3171
Julia Lawall93d72ac2016-12-22 13:05:23 +01003172static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003173
Guenter Roecka6bd5872012-12-04 03:13:34 -08003174/* Case open detection */
3175
3176static ssize_t
3177clear_caseopen(struct device *dev, struct device_attribute *attr,
3178 const char *buf, size_t count)
3179{
3180 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003181 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3182 unsigned long val;
3183 u8 reg;
3184 int ret;
3185
3186 if (kstrtoul(buf, 10, &val) || val != 0)
3187 return -EINVAL;
3188
3189 mutex_lock(&data->update_lock);
3190
3191 /*
3192 * Use CR registers to clear caseopen status.
3193 * The CR registers are the same for all chips, and not all chips
3194 * support clearing the caseopen status through "regular" registers.
3195 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003196 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003197 if (ret) {
3198 count = ret;
3199 goto error;
3200 }
3201
Guenter Roeckdf612d52013-07-08 13:15:04 -07003202 superio_select(data->sioreg, NCT6775_LD_ACPI);
3203 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003204 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003205 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003206 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003207 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3208 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003209
3210 data->valid = false; /* Force cache refresh */
3211error:
3212 mutex_unlock(&data->update_lock);
3213 return count;
3214}
3215
Guenter Roeckf73cf632013-03-18 09:22:50 -07003216static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3217 clear_caseopen, INTRUSION_ALARM_BASE);
3218static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3219 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003220static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3221 store_beep, INTRUSION_ALARM_BASE);
3222static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3223 store_beep, INTRUSION_ALARM_BASE + 1);
3224static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3225 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003226
3227static umode_t nct6775_other_is_visible(struct kobject *kobj,
3228 struct attribute *attr, int index)
3229{
3230 struct device *dev = container_of(kobj, struct device, kobj);
3231 struct nct6775_data *data = dev_get_drvdata(dev);
3232
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003233 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003234 return 0;
3235
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003236 if (index == 1 || index == 2) {
3237 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003238 return 0;
3239 }
3240
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003241 if (index == 3 || index == 4) {
3242 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003243 return 0;
3244 }
3245
Guenter Roeckf73cf632013-03-18 09:22:50 -07003246 return attr->mode;
3247}
3248
3249/*
3250 * nct6775_other_is_visible uses the index into the following array
3251 * to determine if attributes should be created or not.
3252 * Any change in order or content must be matched.
3253 */
3254static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003255 &dev_attr_cpu0_vid.attr, /* 0 */
3256 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3257 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3258 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3259 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3260 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003261
3262 NULL
3263};
3264
3265static const struct attribute_group nct6775_group_other = {
3266 .attrs = nct6775_attributes_other,
3267 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003268};
3269
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003270static inline void nct6775_init_device(struct nct6775_data *data)
3271{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003272 int i;
3273 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003274
3275 /* Start monitoring if needed */
3276 if (data->REG_CONFIG) {
3277 tmp = nct6775_read_value(data, data->REG_CONFIG);
3278 if (!(tmp & 0x01))
3279 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3280 }
3281
Guenter Roeckaa136e52012-12-04 03:26:05 -08003282 /* Enable temperature sensors if needed */
3283 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003284 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003285 continue;
3286 if (!data->reg_temp_config[i])
3287 continue;
3288 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3289 if (tmp & 0x01)
3290 nct6775_write_value(data, data->reg_temp_config[i],
3291 tmp & 0xfe);
3292 }
3293
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003294 /* Enable VBAT monitoring if needed */
3295 tmp = nct6775_read_value(data, data->REG_VBAT);
3296 if (!(tmp & 0x01))
3297 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003298
3299 diode = nct6775_read_value(data, data->REG_DIODE);
3300
3301 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003302 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003303 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003304 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3305 data->temp_type[i]
3306 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003307 else /* thermistor */
3308 data->temp_type[i] = 4;
3309 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003310}
3311
Guenter Roeckf73cf632013-03-18 09:22:50 -07003312static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003313nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003314{
David Bartley578ab5f2013-06-24 22:28:28 -07003315 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3316 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003317 int sioreg = data->sioreg;
3318 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003319
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003320 /* Store SIO_REG_ENABLE for use during resume */
3321 superio_select(sioreg, NCT6775_LD_HWM);
3322 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3323
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003324 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3325 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003326 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003327
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003328 fan3pin = regval & BIT(6);
3329 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003330
3331 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003332 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003333 fan4min = false;
3334 fan5pin = false;
3335 fan6pin = false;
3336 pwm4pin = false;
3337 pwm5pin = false;
3338 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003339 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003340 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003341 const char *board_vendor, *board_name;
3342
3343 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3344 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3345
3346 if (board_name && board_vendor &&
3347 !strcmp(board_vendor, "ASRock")) {
3348 /*
3349 * Auxiliary fan monitoring is not enabled on ASRock
3350 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3351 * Observed with BIOS version 2.00.
3352 */
3353 if (!strcmp(board_name, "Z77 Pro4-M")) {
3354 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3355 data->sio_reg_enable |= 0xe0;
3356 superio_outb(sioreg, SIO_REG_ENABLE,
3357 data->sio_reg_enable);
3358 }
3359 }
3360 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003361
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003362 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003363 fan3pin = gpok;
3364 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003365 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003366
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003367 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003368 fan4pin = gpok;
3369 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003370 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003371
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003372 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003373 fan5pin = gpok;
3374 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003375 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003376
3377 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003378 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003379 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003380 pwm4pin = false;
3381 pwm5pin = false;
3382 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003383 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003384 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003385 fan3pin = !(regval & 0x80);
3386 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003387
3388 fan4pin = false;
3389 fan4min = false;
3390 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003391 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003392 pwm4pin = false;
3393 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003394 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003395 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003396 int regval_1b, regval_2a, regval_eb;
3397
Guenter Roeckdf612d52013-07-08 13:15:04 -07003398 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003399
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003400 fan3pin = !(regval & BIT(5));
3401 fan4pin = !(regval & BIT(6));
3402 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003403
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003404 pwm3pin = !(regval & BIT(0));
3405 pwm4pin = !(regval & BIT(1));
3406 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003407
Guenter Roecke5c85222017-05-17 18:09:41 -07003408 regval = superio_inb(sioreg, 0x2d);
3409 switch (data->kind) {
3410 case nct6791:
3411 case nct6792:
3412 fan6pin = regval & BIT(1);
3413 pwm6pin = regval & BIT(0);
3414 break;
3415 case nct6793:
3416 regval_1b = superio_inb(sioreg, 0x1b);
3417 regval_2a = superio_inb(sioreg, 0x2a);
David Bartley578ab5f2013-06-24 22:28:28 -07003418
Guenter Roecke5c85222017-05-17 18:09:41 -07003419 if (!pwm5pin)
3420 pwm5pin = regval & BIT(7);
3421 fan6pin = regval & BIT(1);
3422 pwm6pin = regval & BIT(0);
3423 if (!fan5pin)
3424 fan5pin = regval_1b & BIT(5);
3425
3426 superio_select(sioreg, NCT6775_LD_12);
3427 regval_eb = superio_inb(sioreg, 0xeb);
3428 if (!fan5pin)
3429 fan5pin = regval_eb & BIT(5);
3430 if (!pwm5pin)
3431 pwm5pin = (regval_eb & BIT(4)) &&
3432 !(regval_2a & BIT(0));
3433 if (!fan6pin)
3434 fan6pin = regval_eb & BIT(3);
3435 if (!pwm6pin)
3436 pwm6pin = regval_eb & BIT(2);
3437 break;
3438 default: /* NCT6779D */
David Bartley578ab5f2013-06-24 22:28:28 -07003439 fan6pin = false;
3440 pwm6pin = false;
Guenter Roecke5c85222017-05-17 18:09:41 -07003441 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003442 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003443
3444 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003445 }
3446
David Bartley578ab5f2013-06-24 22:28:28 -07003447 /* fan 1 and 2 (0x03) are always present */
3448 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3449 (fan5pin << 4) | (fan6pin << 5);
3450 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3451 (fan5pin << 4);
3452 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3453 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003454}
3455
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003456static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3457 int *available, int *mask)
3458{
3459 int i;
3460 u8 src;
3461
3462 for (i = 0; i < data->pwm_num && *available; i++) {
3463 int index;
3464
3465 if (!regp[i])
3466 continue;
3467 src = nct6775_read_value(data, regp[i]);
3468 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003469 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003470 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003471 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003472 continue;
3473
3474 index = __ffs(*available);
3475 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003476 *available &= ~BIT(index);
3477 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003478 }
3479}
3480
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003481static int nct6775_probe(struct platform_device *pdev)
3482{
3483 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003484 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003485 struct nct6775_data *data;
3486 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003487 int i, s, err = 0;
3488 int src, mask, available;
3489 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003490 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003491 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003492 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003493 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003494 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003495 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003496 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003497
3498 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3499 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3500 DRVNAME))
3501 return -EBUSY;
3502
3503 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3504 GFP_KERNEL);
3505 if (!data)
3506 return -ENOMEM;
3507
3508 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003509 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003510 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003511 mutex_init(&data->update_lock);
3512 data->name = nct6775_device_names[data->kind];
3513 data->bank = 0xff; /* Force initial bank selection */
3514 platform_set_drvdata(pdev, data);
3515
3516 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003517 case nct6106:
3518 data->in_num = 9;
3519 data->pwm_num = 3;
3520 data->auto_pwm_num = 4;
3521 data->temp_fixed_num = 3;
3522 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003523 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003524
3525 data->fan_from_reg = fan_from_reg13;
3526 data->fan_from_reg_min = fan_from_reg13;
3527
3528 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003529 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003530
3531 data->REG_VBAT = NCT6106_REG_VBAT;
3532 data->REG_DIODE = NCT6106_REG_DIODE;
3533 data->DIODE_MASK = NCT6106_DIODE_MASK;
3534 data->REG_VIN = NCT6106_REG_IN;
3535 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3536 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3537 data->REG_TARGET = NCT6106_REG_TARGET;
3538 data->REG_FAN = NCT6106_REG_FAN;
3539 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3540 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3541 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3542 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3543 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3544 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3545 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3546 data->REG_PWM[0] = NCT6106_REG_PWM;
3547 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3548 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3549 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3550 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3551 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3552 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3553 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3554 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3555 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3556 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3557 data->REG_CRITICAL_TEMP_TOLERANCE
3558 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3559 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3560 data->CRITICAL_PWM_ENABLE_MASK
3561 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3562 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3563 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3564 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3565 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3566 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3567 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3568 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3569 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3570 data->REG_ALARM = NCT6106_REG_ALARM;
3571 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003572 data->REG_BEEP = NCT6106_REG_BEEP;
3573 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003574
3575 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003576 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003577 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003578 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003579 reg_temp_over = NCT6106_REG_TEMP_OVER;
3580 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3581 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3582 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3583 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003584 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3585 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003586
3587 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003588 case nct6775:
3589 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003590 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003591 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003592 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003593 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003594 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003595 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003596
3597 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003598 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003599
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003600 data->fan_from_reg = fan_from_reg16;
3601 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003602 data->target_temp_mask = 0x7f;
3603 data->tolerance_mask = 0x0f;
3604 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003605
Guenter Roeckaa136e52012-12-04 03:26:05 -08003606 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003607 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003608
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003609 data->REG_CONFIG = NCT6775_REG_CONFIG;
3610 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003611 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003612 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003613 data->REG_VIN = NCT6775_REG_IN;
3614 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3615 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003616 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003617 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003618 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003619 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003620 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003621 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003622 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3623 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3624 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003625 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003626 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3627 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3628 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3629 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003630 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003631 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3632 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3633 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003634 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3635 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3636 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3637 data->REG_CRITICAL_TEMP_TOLERANCE
3638 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003639 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3640 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003641 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003642 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3643 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3644 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3645 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003646 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003647 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003648
3649 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003650 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003651 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003652 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003653 reg_temp_over = NCT6775_REG_TEMP_OVER;
3654 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3655 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3656 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3657 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3658
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003659 break;
3660 case nct6776:
3661 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003662 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003663 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003664 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003665 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003666 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003667 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003668
3669 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003670 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003671
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003672 data->fan_from_reg = fan_from_reg13;
3673 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003674 data->target_temp_mask = 0xff;
3675 data->tolerance_mask = 0x07;
3676 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003677
Guenter Roeckaa136e52012-12-04 03:26:05 -08003678 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003679 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003680
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003681 data->REG_CONFIG = NCT6775_REG_CONFIG;
3682 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003683 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003684 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003685 data->REG_VIN = NCT6775_REG_IN;
3686 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3687 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003688 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003689 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003690 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003691 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003692 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003693 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003694 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003695 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3696 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003697 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003698 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003699 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3700 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003701 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3702 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003703 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3704 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3705 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003706 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3707 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3708 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3709 data->REG_CRITICAL_TEMP_TOLERANCE
3710 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003711 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3712 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003713 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003714 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3715 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3716 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3717 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003718 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003719 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003720
3721 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003722 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003723 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003724 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003725 reg_temp_over = NCT6775_REG_TEMP_OVER;
3726 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3727 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3728 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3729 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3730
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003731 break;
3732 case nct6779:
3733 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003734 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003735 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003736 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003737 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003738 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003739 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003740
3741 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003742 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003743
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003744 data->fan_from_reg = fan_from_reg13;
3745 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003746 data->target_temp_mask = 0xff;
3747 data->tolerance_mask = 0x07;
3748 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003749
Guenter Roeckaa136e52012-12-04 03:26:05 -08003750 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003751 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003752
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003753 data->REG_CONFIG = NCT6775_REG_CONFIG;
3754 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003755 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003756 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003757 data->REG_VIN = NCT6779_REG_IN;
3758 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3759 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003760 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003761 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003762 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003763 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003764 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003765 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003766 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003767 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3768 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003769 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003770 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003771 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3772 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003773 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3774 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003775 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3776 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3777 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003778 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3779 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3780 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3781 data->REG_CRITICAL_TEMP_TOLERANCE
3782 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003783 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3784 data->CRITICAL_PWM_ENABLE_MASK
3785 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3786 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003787 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3788 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003789 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003790 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3791 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3792 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3793 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003794 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003795 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003796
3797 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003798 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003799 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003800 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003801 reg_temp_over = NCT6779_REG_TEMP_OVER;
3802 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3803 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3804 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3805 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3806
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003807 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003808 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003809 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003810 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003811 data->in_num = 15;
3812 data->pwm_num = 6;
3813 data->auto_pwm_num = 4;
3814 data->has_fan_div = false;
3815 data->temp_fixed_num = 6;
3816 data->num_temp_alarms = 2;
3817 data->num_temp_beeps = 2;
3818
3819 data->ALARM_BITS = NCT6791_ALARM_BITS;
3820 data->BEEP_BITS = NCT6779_BEEP_BITS;
3821
3822 data->fan_from_reg = fan_from_reg13;
3823 data->fan_from_reg_min = fan_from_reg13;
3824 data->target_temp_mask = 0xff;
3825 data->tolerance_mask = 0x07;
3826 data->speed_tolerance_limit = 63;
3827
Guenter Roeck50224f42015-10-30 07:52:39 -07003828 switch (data->kind) {
3829 default:
3830 case nct6791:
3831 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003832 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003833 break;
3834 case nct6792:
3835 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003836 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003837 break;
3838 case nct6793:
3839 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003840 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003841 break;
3842 }
David Bartley578ab5f2013-06-24 22:28:28 -07003843
3844 data->REG_CONFIG = NCT6775_REG_CONFIG;
3845 data->REG_VBAT = NCT6775_REG_VBAT;
3846 data->REG_DIODE = NCT6775_REG_DIODE;
3847 data->DIODE_MASK = NCT6775_DIODE_MASK;
3848 data->REG_VIN = NCT6779_REG_IN;
3849 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3850 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3851 data->REG_TARGET = NCT6775_REG_TARGET;
3852 data->REG_FAN = NCT6779_REG_FAN;
3853 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3854 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3855 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3856 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3857 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003858 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3859 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003860 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3861 data->REG_PWM[0] = NCT6775_REG_PWM;
3862 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3863 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003864 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3865 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003866 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3867 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3868 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3869 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3870 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3871 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3872 data->REG_CRITICAL_TEMP_TOLERANCE
3873 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3874 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3875 data->CRITICAL_PWM_ENABLE_MASK
3876 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3877 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3878 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3879 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3880 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003881 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3882 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3883 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3884 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003885 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003886 if (data->kind == nct6791)
3887 data->REG_BEEP = NCT6776_REG_BEEP;
3888 else
3889 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003890
3891 reg_temp = NCT6779_REG_TEMP;
3892 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003893 if (data->kind == nct6791) {
3894 reg_temp_mon = NCT6779_REG_TEMP_MON;
3895 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3896 } else {
3897 reg_temp_mon = NCT6792_REG_TEMP_MON;
3898 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3899 }
David Bartley578ab5f2013-06-24 22:28:28 -07003900 reg_temp_over = NCT6779_REG_TEMP_OVER;
3901 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3902 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3903 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3904 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3905
3906 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003907 default:
3908 return -ENODEV;
3909 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003910 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003911 data->have_temp = 0;
3912
3913 /*
3914 * On some boards, not all available temperature sources are monitored,
3915 * even though some of the monitoring registers are unused.
3916 * Get list of unused monitoring registers, then detect if any fan
3917 * controls are configured to use unmonitored temperature sources.
3918 * If so, assign the unmonitored temperature sources to available
3919 * monitoring registers.
3920 */
3921 mask = 0;
3922 available = 0;
3923 for (i = 0; i < num_reg_temp; i++) {
3924 if (reg_temp[i] == 0)
3925 continue;
3926
3927 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003928 if (!src || (mask & BIT(src)))
3929 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003930
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003931 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003932 }
3933
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003934 /*
3935 * Now find unmonitored temperature registers and enable monitoring
3936 * if additional monitoring registers are available.
3937 */
3938 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3939 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3940
Guenter Roeckaa136e52012-12-04 03:26:05 -08003941 mask = 0;
3942 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3943 for (i = 0; i < num_reg_temp; i++) {
3944 if (reg_temp[i] == 0)
3945 continue;
3946
3947 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003948 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003949 continue;
3950
Guenter Roeckcc66b302017-05-17 18:05:06 -07003951 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08003952 dev_info(dev,
3953 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3954 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3955 continue;
3956 }
3957
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003958 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003959
3960 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3961 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003962 data->have_temp |= BIT(src - 1);
3963 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003964 data->reg_temp[0][src - 1] = reg_temp[i];
3965 data->reg_temp[1][src - 1] = reg_temp_over[i];
3966 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003967 if (reg_temp_crit_h && reg_temp_crit_h[i])
3968 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3969 else if (reg_temp_crit[src - 1])
3970 data->reg_temp[3][src - 1]
3971 = reg_temp_crit[src - 1];
3972 if (reg_temp_crit_l && reg_temp_crit_l[i])
3973 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003974 data->reg_temp_config[src - 1] = reg_temp_config[i];
3975 data->temp_src[src - 1] = src;
3976 continue;
3977 }
3978
3979 if (s >= NUM_TEMP)
3980 continue;
3981
3982 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003983 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003984 data->reg_temp[0][s] = reg_temp[i];
3985 data->reg_temp[1][s] = reg_temp_over[i];
3986 data->reg_temp[2][s] = reg_temp_hyst[i];
3987 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003988 if (reg_temp_crit_h && reg_temp_crit_h[i])
3989 data->reg_temp[3][s] = reg_temp_crit_h[i];
3990 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003991 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003992 if (reg_temp_crit_l && reg_temp_crit_l[i])
3993 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003994
3995 data->temp_src[s] = src;
3996 s++;
3997 }
3998
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003999 /*
4000 * Repeat with temperatures used for fan control.
4001 * This set of registers does not support limits.
4002 */
4003 for (i = 0; i < num_reg_temp_mon; i++) {
4004 if (reg_temp_mon[i] == 0)
4005 continue;
4006
4007 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004008 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004009 continue;
4010
Guenter Roeckcc66b302017-05-17 18:05:06 -07004011 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004012 dev_info(dev,
4013 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4014 src, i, data->REG_TEMP_SEL[i],
4015 reg_temp_mon[i]);
4016 continue;
4017 }
4018
Guenter Roeck7ce41902016-09-11 12:42:52 -07004019 /*
4020 * For virtual temperature sources, the 'virtual' temperature
4021 * for each fan reflects a different temperature, and there
4022 * are no duplicates.
4023 */
4024 if (src != TEMP_SOURCE_VIRTUAL) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004025 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004026 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004027 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004028 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004029
4030 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4031 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004032 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004033 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004034 data->have_temp |= BIT(src - 1);
4035 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004036 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4037 data->temp_src[src - 1] = src;
4038 continue;
4039 }
4040
4041 if (s >= NUM_TEMP)
4042 continue;
4043
4044 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004045 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004046 data->reg_temp[0][s] = reg_temp_mon[i];
4047 data->temp_src[s] = src;
4048 s++;
4049 }
4050
Guenter Roeckaa136e52012-12-04 03:26:05 -08004051#ifdef USE_ALTERNATE
4052 /*
4053 * Go through the list of alternate temp registers and enable
4054 * if possible.
4055 * The temperature is already monitored if the respective bit in <mask>
4056 * is set.
4057 */
Guenter Roeckcc66b302017-05-17 18:05:06 -07004058 for (i = 0; i < 32; i++) {
4059 if (!(data->temp_mask & BIT(i + 1)))
4060 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004061 if (!reg_temp_alternate[i])
4062 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004063 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004064 continue;
4065 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004066 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004067 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004068 data->have_temp |= BIT(i);
4069 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004070 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004071 if (i < num_reg_temp) {
4072 data->reg_temp[1][i] = reg_temp_over[i];
4073 data->reg_temp[2][i] = reg_temp_hyst[i];
4074 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004075 data->temp_src[i] = i + 1;
4076 continue;
4077 }
4078
4079 if (s >= NUM_TEMP) /* Abort if no more space */
4080 break;
4081
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004082 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004083 data->reg_temp[0][s] = reg_temp_alternate[i];
4084 data->temp_src[s] = i + 1;
4085 s++;
4086 }
4087#endif /* USE_ALTERNATE */
4088
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004089 /* Initialize the chip */
4090 nct6775_init_device(data);
4091
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004092 err = superio_enter(sio_data->sioreg);
4093 if (err)
4094 return err;
4095
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004096 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4097 switch (data->kind) {
4098 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004099 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004100 break;
4101 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004102 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004103 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004104 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004105 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004106 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004107 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004108 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004109 break;
4110 }
4111
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004112 /*
4113 * Read VID value
4114 * We can get the VID input values directly at logical device D 0xe3.
4115 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004116 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004117 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4118 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4119 data->vrm = vid_which_vrm();
4120 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004121
4122 if (fan_debounce) {
4123 u8 tmp;
4124
4125 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4126 tmp = superio_inb(sio_data->sioreg,
4127 NCT6775_REG_CR_FAN_DEBOUNCE);
4128 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004129 case nct6106:
4130 tmp |= 0xe0;
4131 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004132 case nct6775:
4133 tmp |= 0x1e;
4134 break;
4135 case nct6776:
4136 case nct6779:
4137 tmp |= 0x3e;
4138 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004139 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004140 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004141 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07004142 tmp |= 0x7e;
4143 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004144 }
4145 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4146 tmp);
4147 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4148 data->name);
4149 }
4150
Guenter Roeckdf612d52013-07-08 13:15:04 -07004151 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004152
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004153 superio_exit(sio_data->sioreg);
4154
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004155 /* Read fan clock dividers immediately */
4156 nct6775_init_fan_common(dev, data);
4157
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004158 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004159 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4160 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004161 if (IS_ERR(group))
4162 return PTR_ERR(group);
4163
Axel Lin55bdee62014-07-24 08:59:34 +08004164 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004165
Guenter Roeckf73cf632013-03-18 09:22:50 -07004166 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4167 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004168 if (IS_ERR(group))
4169 return PTR_ERR(group);
4170
Axel Lin55bdee62014-07-24 08:59:34 +08004171 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004172
Guenter Roeckf73cf632013-03-18 09:22:50 -07004173 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4174 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004175 if (IS_ERR(group))
4176 return PTR_ERR(group);
4177
Axel Lin55bdee62014-07-24 08:59:34 +08004178 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004179
Guenter Roeckf73cf632013-03-18 09:22:50 -07004180 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4181 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004182 if (IS_ERR(group))
4183 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004184
Axel Lin55bdee62014-07-24 08:59:34 +08004185 data->groups[num_attr_groups++] = group;
4186 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004187
Guenter Roecka150d952013-07-11 22:55:22 -07004188 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4189 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004190 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004191}
4192
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004193static void nct6791_enable_io_mapping(int sioaddr)
4194{
4195 int val;
4196
4197 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4198 if (val & 0x10) {
4199 pr_info("Enabling hardware monitor logical device mappings.\n");
4200 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4201 val & ~0x10);
4202 }
4203}
4204
Guenter Roeck48e93182015-02-07 08:48:49 -08004205static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004206{
4207 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004208
4209 mutex_lock(&data->update_lock);
4210 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004211 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004212 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4213 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4214 }
4215 mutex_unlock(&data->update_lock);
4216
4217 return 0;
4218}
4219
Guenter Roeck48e93182015-02-07 08:48:49 -08004220static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004221{
4222 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004223 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004224 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004225 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004226
4227 mutex_lock(&data->update_lock);
4228 data->bank = 0xff; /* Force initial bank selection */
4229
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004230 err = superio_enter(sioreg);
4231 if (err)
4232 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004233
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004234 superio_select(sioreg, NCT6775_LD_HWM);
4235 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4236 if (reg != data->sio_reg_enable)
4237 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4238
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004239 if (data->kind == nct6791 || data->kind == nct6792 ||
4240 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004241 nct6791_enable_io_mapping(sioreg);
4242
4243 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004244
Guenter Roeck84d19d92012-12-04 08:01:39 -08004245 /* Restore limits */
4246 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004247 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004248 continue;
4249
4250 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4251 data->in[i][1]);
4252 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4253 data->in[i][2]);
4254 }
4255
Guenter Roeckc409fd42013-04-09 05:04:00 -07004256 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004257 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004258 continue;
4259
4260 nct6775_write_value(data, data->REG_FAN_MIN[i],
4261 data->fan_min[i]);
4262 }
4263
4264 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004265 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004266 continue;
4267
Guenter Roeckc409fd42013-04-09 05:04:00 -07004268 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004269 if (data->reg_temp[j][i])
4270 nct6775_write_temp(data, data->reg_temp[j][i],
4271 data->temp[j][i]);
4272 }
4273
4274 /* Restore other settings */
4275 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004276 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004277 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4278 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4279 }
4280
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004281abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004282 /* Force re-reading all values */
4283 data->valid = false;
4284 mutex_unlock(&data->update_lock);
4285
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004286 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004287}
4288
Guenter Roeck48e93182015-02-07 08:48:49 -08004289static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004290
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004291static struct platform_driver nct6775_driver = {
4292 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004293 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004294 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004295 },
4296 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004297};
4298
4299/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004300static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004301{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004302 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004303 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004304 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004305
4306 err = superio_enter(sioaddr);
4307 if (err)
4308 return err;
4309
Guenter Roeckfc72af32016-08-03 22:07:18 -07004310 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4311 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4312 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004313 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004314
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004315 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004316 case SIO_NCT6106_ID:
4317 sio_data->kind = nct6106;
4318 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004319 case SIO_NCT6775_ID:
4320 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004321 break;
4322 case SIO_NCT6776_ID:
4323 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004324 break;
4325 case SIO_NCT6779_ID:
4326 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004327 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004328 case SIO_NCT6791_ID:
4329 sio_data->kind = nct6791;
4330 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004331 case SIO_NCT6792_ID:
4332 sio_data->kind = nct6792;
4333 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004334 case SIO_NCT6793_ID:
4335 sio_data->kind = nct6793;
4336 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004337 default:
4338 if (val != 0xffff)
4339 pr_debug("unsupported chip ID: 0x%04x\n", val);
4340 superio_exit(sioaddr);
4341 return -ENODEV;
4342 }
4343
4344 /* We have a known chip, find the HWM I/O address */
4345 superio_select(sioaddr, NCT6775_LD_HWM);
4346 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4347 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004348 addr = val & IOREGION_ALIGNMENT;
4349 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004350 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4351 superio_exit(sioaddr);
4352 return -ENODEV;
4353 }
4354
4355 /* Activate logical device if needed */
4356 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4357 if (!(val & 0x01)) {
4358 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4359 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4360 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004361
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004362 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4363 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004364 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004365
4366 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004367 pr_info("Found %s or compatible chip at %#x:%#x\n",
4368 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004369 sio_data->sioreg = sioaddr;
4370
Guenter Roeck698a7c22013-04-05 07:35:25 -07004371 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004372}
4373
4374/*
4375 * when Super-I/O functions move to a separate file, the Super-I/O
4376 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004377 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004378 * must keep track of the device
4379 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004380static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004381
4382static int __init sensors_nct6775_init(void)
4383{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004384 int i, err;
4385 bool found = false;
4386 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004387 struct resource res;
4388 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004389 int sioaddr[2] = { 0x2e, 0x4e };
4390
4391 err = platform_driver_register(&nct6775_driver);
4392 if (err)
4393 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004394
4395 /*
4396 * initialize sio_data->kind and sio_data->sioreg.
4397 *
4398 * when Super-I/O functions move to a separate file, the Super-I/O
4399 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4400 * nct6775 hardware monitor, and call probe()
4401 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004402 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4403 address = nct6775_find(sioaddr[i], &sio_data);
4404 if (address <= 0)
4405 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004406
Guenter Roeck698a7c22013-04-05 07:35:25 -07004407 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004408
Guenter Roeck698a7c22013-04-05 07:35:25 -07004409 pdev[i] = platform_device_alloc(DRVNAME, address);
4410 if (!pdev[i]) {
4411 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004412 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004413 }
4414
4415 err = platform_device_add_data(pdev[i], &sio_data,
4416 sizeof(struct nct6775_sio_data));
4417 if (err)
4418 goto exit_device_put;
4419
4420 memset(&res, 0, sizeof(res));
4421 res.name = DRVNAME;
4422 res.start = address + IOREGION_OFFSET;
4423 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4424 res.flags = IORESOURCE_IO;
4425
4426 err = acpi_check_resource_conflict(&res);
4427 if (err) {
4428 platform_device_put(pdev[i]);
4429 pdev[i] = NULL;
4430 continue;
4431 }
4432
4433 err = platform_device_add_resources(pdev[i], &res, 1);
4434 if (err)
4435 goto exit_device_put;
4436
4437 /* platform_device_add calls probe() */
4438 err = platform_device_add(pdev[i]);
4439 if (err)
4440 goto exit_device_put;
4441 }
4442 if (!found) {
4443 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004444 goto exit_unregister;
4445 }
4446
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004447 return 0;
4448
4449exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004450 platform_device_put(pdev[i]);
4451exit_device_unregister:
4452 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004453 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004454 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004455 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004456exit_unregister:
4457 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004458 return err;
4459}
4460
4461static void __exit sensors_nct6775_exit(void)
4462{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004463 int i;
4464
4465 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4466 if (pdev[i])
4467 platform_device_unregister(pdev[i]);
4468 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004469 platform_driver_unregister(&nct6775_driver);
4470}
4471
4472MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004473MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004474MODULE_LICENSE("GPL");
4475
4476module_init(sensors_nct6775_init);
4477module_exit(sensors_nct6775_exit);