blob: c219e43b8f026faa69e4617cecc2b31e7449a064 [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 Delvare7c81c602014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070042 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck419220d2017-05-17 18:19:18 -070043 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
44 *
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070045 *
46 * #temp lists the number of monitored temperature sources (first value) plus
47 * the number of directly connectable temperature sensors (second value).
48 */
49
50#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51
52#include <linux/module.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/jiffies.h>
56#include <linux/platform_device.h>
57#include <linux/hwmon.h>
58#include <linux/hwmon-sysfs.h>
59#include <linux/hwmon-vid.h>
60#include <linux/err.h>
61#include <linux/mutex.h>
62#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070063#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080064#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070065#include <linux/io.h>
66#include "lm75.h"
67
Guenter Roeckaa136e52012-12-04 03:26:05 -080068#define USE_ALTERNATE
69
Guenter Roeck419220d2017-05-17 18:19:18 -070070enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
71 nct6795 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070072
73/* used to set data->name = nct6775_device_names[data->sio_kind] */
74static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070075 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070076 "nct6775",
77 "nct6776",
78 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070079 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080080 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070081 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070082 "nct6795",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070083};
84
85static const char * const nct6775_sio_names[] __initconst = {
86 "NCT6106D",
87 "NCT6775F",
88 "NCT6776D/F",
89 "NCT6779D",
90 "NCT6791D",
91 "NCT6792D",
92 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -070093 "NCT6795D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070094};
95
96static unsigned short force_id;
97module_param(force_id, ushort, 0);
98MODULE_PARM_DESC(force_id, "Override the detected device ID");
99
Guenter Roeck47ece962012-12-04 07:59:32 -0800100static unsigned short fan_debounce;
101module_param(fan_debounce, ushort, 0);
102MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
103
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700104#define DRVNAME "nct6775"
105
106/*
107 * Super-I/O constants and functions
108 */
109
Guenter Roecka6bd5872012-12-04 03:13:34 -0800110#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700111#define NCT6775_LD_HWM 0x0b
112#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700113#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114
115#define SIO_REG_LDSEL 0x07 /* Logical device select */
116#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
117#define SIO_REG_ENABLE 0x30 /* Logical device enable */
118#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
119
Guenter Roeck6c009502012-07-01 08:23:15 -0700120#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700121#define SIO_NCT6775_ID 0xb470
122#define SIO_NCT6776_ID 0xc330
123#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700124#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800125#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700126#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700127#define SIO_NCT6795_ID 0xd350
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700128#define SIO_ID_MASK 0xFFF0
129
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800130enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
131
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700132static inline void
133superio_outb(int ioreg, int reg, int val)
134{
135 outb(reg, ioreg);
136 outb(val, ioreg + 1);
137}
138
139static inline int
140superio_inb(int ioreg, int reg)
141{
142 outb(reg, ioreg);
143 return inb(ioreg + 1);
144}
145
146static inline void
147superio_select(int ioreg, int ld)
148{
149 outb(SIO_REG_LDSEL, ioreg);
150 outb(ld, ioreg + 1);
151}
152
153static inline int
154superio_enter(int ioreg)
155{
156 /*
157 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
158 */
159 if (!request_muxed_region(ioreg, 2, DRVNAME))
160 return -EBUSY;
161
162 outb(0x87, ioreg);
163 outb(0x87, ioreg);
164
165 return 0;
166}
167
168static inline void
169superio_exit(int ioreg)
170{
171 outb(0xaa, ioreg);
172 outb(0x02, ioreg);
173 outb(0x02, ioreg + 1);
174 release_region(ioreg, 2);
175}
176
177/*
178 * ISA constants
179 */
180
181#define IOREGION_ALIGNMENT (~7)
182#define IOREGION_OFFSET 5
183#define IOREGION_LENGTH 2
184#define ADDR_REG_OFFSET 0
185#define DATA_REG_OFFSET 1
186
187#define NCT6775_REG_BANK 0x4E
188#define NCT6775_REG_CONFIG 0x40
189
190/*
191 * Not currently used:
192 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
193 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
194 * REG_MAN_ID is at port 0x4f
195 * REG_CHIP_ID is at port 0x58
196 */
197
Guenter Roeckaa136e52012-12-04 03:26:05 -0800198#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
199#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
200
Guenter Roeck6c009502012-07-01 08:23:15 -0700201#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700202#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700203
David Bartley578ab5f2013-06-24 22:28:28 -0700204#define NUM_FAN 6
205
Guenter Roeck7ce41902016-09-11 12:42:52 -0700206#define TEMP_SOURCE_VIRTUAL 0x1f
207
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700208/* Common and NCT6775 specific data */
209
210/* Voltage min/max registers for nr=7..14 are in bank 5 */
211
212static const u16 NCT6775_REG_IN_MAX[] = {
213 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
214 0x55c, 0x55e, 0x560, 0x562 };
215static const u16 NCT6775_REG_IN_MIN[] = {
216 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
217 0x55d, 0x55f, 0x561, 0x563 };
218static const u16 NCT6775_REG_IN[] = {
219 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
220};
221
222#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800223#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700224#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700225
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800226#define NCT6775_REG_FANDIV1 0x506
227#define NCT6775_REG_FANDIV2 0x507
228
Guenter Roeck47ece962012-12-04 07:59:32 -0800229#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
230
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700231static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
232
Guenter Roeck30846992013-06-24 22:21:59 -0700233/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700234
235static const s8 NCT6775_ALARM_BITS[] = {
236 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
237 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
238 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700239 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700240 -1, -1, -1, /* unused */
241 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
242 12, -1 }; /* intrusion0, intrusion1 */
243
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800244#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800245#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800246#define INTRUSION_ALARM_BASE 30
247
Guenter Roeck30846992013-06-24 22:21:59 -0700248static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
249
250/*
251 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
252 * 30..31 intrusion
253 */
254static const s8 NCT6775_BEEP_BITS[] = {
255 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
256 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
257 21, /* global beep enable */
258 6, 7, 11, 28, -1, /* fan1..fan5 */
259 -1, -1, -1, /* unused */
260 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
261 12, -1 }; /* intrusion0, intrusion1 */
262
263#define BEEP_ENABLE_BASE 15
264
Guenter Roecka6bd5872012-12-04 03:13:34 -0800265static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
266static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
267
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800268/* DC or PWM output fan configuration */
269static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
270static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
271
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800272/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800273
David Bartley578ab5f2013-06-24 22:28:28 -0700274static const u16 NCT6775_REG_TARGET[] = {
275 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
276static const u16 NCT6775_REG_FAN_MODE[] = {
277 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800278static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700279 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800280static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700281 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800282static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700283 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
284static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
285 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800286static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
287static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
288
289static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700290 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
291static const u16 NCT6775_REG_PWM[] = {
292 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
293static const u16 NCT6775_REG_PWM_READ[] = {
294 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800295
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800296static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
297static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800298static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700299static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800300
Guenter Roeckaa136e52012-12-04 03:26:05 -0800301static const u16 NCT6775_REG_TEMP[] = {
302 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
303
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800304static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
305
Guenter Roeckaa136e52012-12-04 03:26:05 -0800306static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
307 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
308static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
309 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
310static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
311 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
312
313static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
314 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
315
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800316static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700317 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800318
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800319static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700320 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800321static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700322 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800323static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700324 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800325static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700326 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800327static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700328 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800329
Guenter Roeckaa136e52012-12-04 03:26:05 -0800330static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
331
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800332static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700333 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800334static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700335 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800336
337#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
338#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
339
340static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
341
342static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700343 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800344static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700345 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800346
Guenter Roeckaa136e52012-12-04 03:26:05 -0800347static const char *const nct6775_temp_label[] = {
348 "",
349 "SYSTIN",
350 "CPUTIN",
351 "AUXTIN",
352 "AMD SB-TSI",
353 "PECI Agent 0",
354 "PECI Agent 1",
355 "PECI Agent 2",
356 "PECI Agent 3",
357 "PECI Agent 4",
358 "PECI Agent 5",
359 "PECI Agent 6",
360 "PECI Agent 7",
361 "PCH_CHIP_CPU_MAX_TEMP",
362 "PCH_CHIP_TEMP",
363 "PCH_CPU_TEMP",
364 "PCH_MCH_TEMP",
365 "PCH_DIM0_TEMP",
366 "PCH_DIM1_TEMP",
367 "PCH_DIM2_TEMP",
368 "PCH_DIM3_TEMP"
369};
370
Guenter Roeckcc66b302017-05-17 18:05:06 -0700371#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800372
Guenter Roeckcc66b302017-05-17 18:05:06 -0700373static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
374 [13] = 0x661,
375 [14] = 0x662,
376 [15] = 0x664,
377};
378
379static const u16 NCT6775_REG_TEMP_CRIT[32] = {
380 [4] = 0xa00,
381 [5] = 0xa01,
382 [6] = 0xa02,
383 [7] = 0xa03,
384 [8] = 0xa04,
385 [9] = 0xa05,
386 [10] = 0xa06,
387 [11] = 0xa07
388};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800389
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700390/* NCT6776 specific data */
391
Guenter Roeck728d2942015-08-31 16:13:47 -0700392/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
393#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
394#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
395
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700396static const s8 NCT6776_ALARM_BITS[] = {
397 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
398 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
399 -1, /* unused */
400 6, 7, 11, 10, 23, /* fan1..fan5 */
401 -1, -1, -1, /* unused */
402 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
403 12, 9 }; /* intrusion0, intrusion1 */
404
Guenter Roeck30846992013-06-24 22:21:59 -0700405static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
406
407static const s8 NCT6776_BEEP_BITS[] = {
408 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
409 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
410 24, /* global beep enable */
411 25, 26, 27, 28, 29, /* fan1..fan5 */
412 -1, -1, -1, /* unused */
413 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
414 30, 31 }; /* intrusion0, intrusion1 */
415
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800416static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700417 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800418
David Bartley578ab5f2013-06-24 22:28:28 -0700419static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
420static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800421
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800422static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800423static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800424
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800425static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700426 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800427
Guenter Roeckaa136e52012-12-04 03:26:05 -0800428static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
429 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
430
431static const char *const nct6776_temp_label[] = {
432 "",
433 "SYSTIN",
434 "CPUTIN",
435 "AUXTIN",
436 "SMBUSMASTER 0",
437 "SMBUSMASTER 1",
438 "SMBUSMASTER 2",
439 "SMBUSMASTER 3",
440 "SMBUSMASTER 4",
441 "SMBUSMASTER 5",
442 "SMBUSMASTER 6",
443 "SMBUSMASTER 7",
444 "PECI Agent 0",
445 "PECI Agent 1",
446 "PCH_CHIP_CPU_MAX_TEMP",
447 "PCH_CHIP_TEMP",
448 "PCH_CPU_TEMP",
449 "PCH_MCH_TEMP",
450 "PCH_DIM0_TEMP",
451 "PCH_DIM1_TEMP",
452 "PCH_DIM2_TEMP",
453 "PCH_DIM3_TEMP",
454 "BYTE_TEMP"
455};
456
Guenter Roeckcc66b302017-05-17 18:05:06 -0700457#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800458
Guenter Roeckcc66b302017-05-17 18:05:06 -0700459static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
460 [14] = 0x401,
461 [15] = 0x402,
462 [16] = 0x404,
463};
464
465static const u16 NCT6776_REG_TEMP_CRIT[32] = {
466 [11] = 0x709,
467 [12] = 0x70a,
468};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800469
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700470/* NCT6779 specific data */
471
472static const u16 NCT6779_REG_IN[] = {
473 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
474 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
475
476static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
477 0x459, 0x45A, 0x45B, 0x568 };
478
479static const s8 NCT6779_ALARM_BITS[] = {
480 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
481 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
482 -1, /* unused */
483 6, 7, 11, 10, 23, /* fan1..fan5 */
484 -1, -1, -1, /* unused */
485 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
486 12, 9 }; /* intrusion0, intrusion1 */
487
Guenter Roeck30846992013-06-24 22:21:59 -0700488static const s8 NCT6779_BEEP_BITS[] = {
489 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
490 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
491 24, /* global beep enable */
492 25, 26, 27, 28, 29, /* fan1..fan5 */
493 -1, -1, -1, /* unused */
494 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
495 30, 31 }; /* intrusion0, intrusion1 */
496
David Bartley578ab5f2013-06-24 22:28:28 -0700497static const u16 NCT6779_REG_FAN[] = {
498 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800499static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700500 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800501
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800502static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700503 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700504#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800505static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700506 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800507
Guenter Roeckaa136e52012-12-04 03:26:05 -0800508static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800509static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800510static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
511 0x18, 0x152 };
512static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
513 0x3a, 0x153 };
514static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
515 0x39, 0x155 };
516
517static const u16 NCT6779_REG_TEMP_OFFSET[] = {
518 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
519
520static const char *const nct6779_temp_label[] = {
521 "",
522 "SYSTIN",
523 "CPUTIN",
524 "AUXTIN0",
525 "AUXTIN1",
526 "AUXTIN2",
527 "AUXTIN3",
528 "",
529 "SMBUSMASTER 0",
530 "SMBUSMASTER 1",
531 "SMBUSMASTER 2",
532 "SMBUSMASTER 3",
533 "SMBUSMASTER 4",
534 "SMBUSMASTER 5",
535 "SMBUSMASTER 6",
536 "SMBUSMASTER 7",
537 "PECI Agent 0",
538 "PECI Agent 1",
539 "PCH_CHIP_CPU_MAX_TEMP",
540 "PCH_CHIP_TEMP",
541 "PCH_CPU_TEMP",
542 "PCH_MCH_TEMP",
543 "PCH_DIM0_TEMP",
544 "PCH_DIM1_TEMP",
545 "PCH_DIM2_TEMP",
546 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700547 "BYTE_TEMP",
548 "",
549 "",
550 "",
551 "",
552 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800553};
554
Guenter Roeckcc66b302017-05-17 18:05:06 -0700555#define NCT6779_TEMP_MASK 0x07ffff7e
556#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck9a383712015-08-29 15:29:25 -0700557
Guenter Roeckcc66b302017-05-17 18:05:06 -0700558static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800559 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
560 0, 0, 0, 0, 0, 0, 0, 0,
561 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
562 0x408, 0 };
563
Guenter Roeckcc66b302017-05-17 18:05:06 -0700564static const u16 NCT6779_REG_TEMP_CRIT[32] = {
565 [15] = 0x709,
566 [16] = 0x70a,
567};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800568
David Bartley578ab5f2013-06-24 22:28:28 -0700569/* NCT6791 specific data */
570
571#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
572
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800573static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
574static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
575static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
576static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
577static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
578static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
579
David Bartley578ab5f2013-06-24 22:28:28 -0700580static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
581 0x459, 0x45A, 0x45B, 0x568, 0x45D };
582
583static const s8 NCT6791_ALARM_BITS[] = {
584 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
585 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
586 -1, /* unused */
587 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
588 -1, -1, /* unused */
589 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
590 12, 9 }; /* intrusion0, intrusion1 */
591
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700592/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800593
594static const u16 NCT6792_REG_TEMP_MON[] = {
595 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
596static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
597 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700598
Guenter Roeck50224f42015-10-30 07:52:39 -0700599static const char *const nct6792_temp_label[] = {
600 "",
601 "SYSTIN",
602 "CPUTIN",
603 "AUXTIN0",
604 "AUXTIN1",
605 "AUXTIN2",
606 "AUXTIN3",
607 "",
608 "SMBUSMASTER 0",
609 "SMBUSMASTER 1",
610 "SMBUSMASTER 2",
611 "SMBUSMASTER 3",
612 "SMBUSMASTER 4",
613 "SMBUSMASTER 5",
614 "SMBUSMASTER 6",
615 "SMBUSMASTER 7",
616 "PECI Agent 0",
617 "PECI Agent 1",
618 "PCH_CHIP_CPU_MAX_TEMP",
619 "PCH_CHIP_TEMP",
620 "PCH_CPU_TEMP",
621 "PCH_MCH_TEMP",
622 "PCH_DIM0_TEMP",
623 "PCH_DIM1_TEMP",
624 "PCH_DIM2_TEMP",
625 "PCH_DIM3_TEMP",
626 "BYTE_TEMP",
627 "PECI Agent 0 Calibration",
628 "PECI Agent 1 Calibration",
629 "",
630 "",
631 "Virtual_TEMP"
632};
633
Guenter Roeckcc66b302017-05-17 18:05:06 -0700634#define NCT6792_TEMP_MASK 0x9fffff7e
635
Guenter Roeck50224f42015-10-30 07:52:39 -0700636static const char *const nct6793_temp_label[] = {
637 "",
638 "SYSTIN",
639 "CPUTIN",
640 "AUXTIN0",
641 "AUXTIN1",
642 "AUXTIN2",
643 "AUXTIN3",
644 "",
645 "SMBUSMASTER 0",
646 "SMBUSMASTER 1",
647 "",
648 "",
649 "",
650 "",
651 "",
652 "",
653 "PECI Agent 0",
654 "PECI Agent 1",
655 "PCH_CHIP_CPU_MAX_TEMP",
656 "PCH_CHIP_TEMP",
657 "PCH_CPU_TEMP",
658 "PCH_MCH_TEMP",
659 "Agent0 Dimm0 ",
660 "Agent0 Dimm1",
661 "Agent1 Dimm0",
662 "Agent1 Dimm1",
663 "BYTE_TEMP0",
664 "BYTE_TEMP1",
665 "PECI Agent 0 Calibration",
666 "PECI Agent 1 Calibration",
667 "",
668 "Virtual_TEMP"
669};
670
Guenter Roeckcc66b302017-05-17 18:05:06 -0700671#define NCT6793_TEMP_MASK 0xbfff037e
672
Guenter Roeck419220d2017-05-17 18:19:18 -0700673static const char *const nct6795_temp_label[] = {
674 "",
675 "SYSTIN",
676 "CPUTIN",
677 "AUXTIN0",
678 "AUXTIN1",
679 "AUXTIN2",
680 "AUXTIN3",
681 "",
682 "SMBUSMASTER 0",
683 "SMBUSMASTER 1",
684 "SMBUSMASTER 2",
685 "SMBUSMASTER 3",
686 "SMBUSMASTER 4",
687 "SMBUSMASTER 5",
688 "SMBUSMASTER 6",
689 "SMBUSMASTER 7",
690 "PECI Agent 0",
691 "PECI Agent 1",
692 "PCH_CHIP_CPU_MAX_TEMP",
693 "PCH_CHIP_TEMP",
694 "PCH_CPU_TEMP",
695 "PCH_MCH_TEMP",
696 "PCH_DIM0_TEMP",
697 "PCH_DIM1_TEMP",
698 "PCH_DIM2_TEMP",
699 "PCH_DIM3_TEMP",
700 "BYTE_TEMP0",
701 "BYTE_TEMP1",
702 "PECI Agent 0 Calibration",
703 "PECI Agent 1 Calibration",
704 "",
705 "Virtual_TEMP"
706};
707
708#define NCT6795_TEMP_MASK 0xbfffff7e
709
Guenter Roeck6c009502012-07-01 08:23:15 -0700710/* NCT6102D/NCT6106D specific data */
711
712#define NCT6106_REG_VBAT 0x318
713#define NCT6106_REG_DIODE 0x319
714#define NCT6106_DIODE_MASK 0x01
715
716static const u16 NCT6106_REG_IN_MAX[] = {
717 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
718static const u16 NCT6106_REG_IN_MIN[] = {
719 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
720static const u16 NCT6106_REG_IN[] = {
721 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
722
723static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800724static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700725static const u16 NCT6106_REG_TEMP_HYST[] = {
726 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
727static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700728 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
729static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
730 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
731static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
732 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700733static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
734static const u16 NCT6106_REG_TEMP_CONFIG[] = {
735 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
736
737static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
738static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
739static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
740static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
741
742static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
743static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
744static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
745static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
746static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
747static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
748static const u16 NCT6106_REG_TEMP_SOURCE[] = {
749 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
750
751static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
752static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
753 0x11b, 0x12b, 0x13b };
754
755static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
756#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
757static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
758
759static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
760static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
761static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
762static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
763static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
764static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
765
766static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
767
768static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
769static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
770static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
771static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
772static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
773static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
774
775static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
776static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
777
778static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
779 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
780
781static const s8 NCT6106_ALARM_BITS[] = {
782 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
783 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
784 -1, /* unused */
785 32, 33, 34, -1, -1, /* fan1..fan5 */
786 -1, -1, -1, /* unused */
787 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
788 48, -1 /* intrusion0, intrusion1 */
789};
790
Guenter Roeck30846992013-06-24 22:21:59 -0700791static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
792 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
793
794static const s8 NCT6106_BEEP_BITS[] = {
795 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
796 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
797 32, /* global beep enable */
798 24, 25, 26, 27, 28, /* fan1..fan5 */
799 -1, -1, -1, /* unused */
800 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
801 34, -1 /* intrusion0, intrusion1 */
802};
803
Guenter Roeckcc66b302017-05-17 18:05:06 -0700804static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
805 [14] = 0x51,
806 [15] = 0x52,
807 [16] = 0x54,
808};
Guenter Roeck6c009502012-07-01 08:23:15 -0700809
Guenter Roeckcc66b302017-05-17 18:05:06 -0700810static const u16 NCT6106_REG_TEMP_CRIT[32] = {
811 [11] = 0x204,
812 [12] = 0x205,
813};
Guenter Roeck6c009502012-07-01 08:23:15 -0700814
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800815static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
816{
817 if (mode == 0 && pwm == 255)
818 return off;
819 return mode + 1;
820}
821
822static int pwm_enable_to_reg(enum pwm_enable mode)
823{
824 if (mode == off)
825 return 0;
826 return mode - 1;
827}
828
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700829/*
830 * Conversions
831 */
832
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800833/* 1 is DC mode, output in ms */
834static unsigned int step_time_from_reg(u8 reg, u8 mode)
835{
836 return mode ? 400 * reg : 100 * reg;
837}
838
839static u8 step_time_to_reg(unsigned int msec, u8 mode)
840{
841 return clamp_val((mode ? (msec + 200) / 400 :
842 (msec + 50) / 100), 1, 255);
843}
844
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800845static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
846{
847 if (reg == 0 || reg == 255)
848 return 0;
849 return 1350000U / (reg << divreg);
850}
851
852static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
853{
854 if ((reg & 0xff1f) == 0xff1f)
855 return 0;
856
857 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
858
859 if (reg == 0)
860 return 0;
861
862 return 1350000U / reg;
863}
864
865static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
866{
867 if (reg == 0 || reg == 0xffff)
868 return 0;
869
870 /*
871 * Even though the registers are 16 bit wide, the fan divisor
872 * still applies.
873 */
874 return 1350000U / (reg << divreg);
875}
876
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800877static u16 fan_to_reg(u32 fan, unsigned int divreg)
878{
879 if (!fan)
880 return 0;
881
882 return (1350000U / fan) >> divreg;
883}
884
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800885static inline unsigned int
886div_from_reg(u8 reg)
887{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700888 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800889}
890
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700891/*
892 * Some of the voltage inputs have internal scaling, the tables below
893 * contain 8 (the ADC LSB in mV) * scaling factor * 100
894 */
895static const u16 scale_in[15] = {
896 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
897 800, 800
898};
899
900static inline long in_from_reg(u8 reg, u8 nr)
901{
902 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
903}
904
905static inline u8 in_to_reg(u32 val, u8 nr)
906{
907 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
908}
909
910/*
911 * Data structures and manipulation thereof
912 */
913
914struct nct6775_data {
915 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700916 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700917 enum kinds kind;
918 const char *name;
919
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700920 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700921
Guenter Roeckb7a61352013-04-02 22:14:06 -0700922 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
923 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800924 */
925 u8 temp_src[NUM_TEMP];
926 u16 reg_temp_config[NUM_TEMP];
927 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700928 u32 temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800929
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700930 u16 REG_CONFIG;
931 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800932 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700933 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700934
935 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700936 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700937
938 const u16 *REG_VIN;
939 const u16 *REG_IN_MINMAX[2];
940
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800941 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800942 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800943 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800944 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800945 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700946 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800947 const u16 *REG_FAN_TIME[3];
948
949 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800950
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800951 const u8 *REG_PWM_MODE;
952 const u8 *PWM_MODE_MASK;
953
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800954 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
955 * [3]=pwm_max, [4]=pwm_step,
956 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800957 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800958 const u16 *REG_PWM_READ;
959
Guenter Roeck6c009502012-07-01 08:23:15 -0700960 const u16 *REG_CRITICAL_PWM_ENABLE;
961 u8 CRITICAL_PWM_ENABLE_MASK;
962 const u16 *REG_CRITICAL_PWM;
963
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800964 const u16 *REG_AUTO_TEMP;
965 const u16 *REG_AUTO_PWM;
966
967 const u16 *REG_CRITICAL_TEMP;
968 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
969
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800970 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800971 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800972 const u16 *REG_WEIGHT_TEMP_SEL;
973 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
974
Guenter Roeckaa136e52012-12-04 03:26:05 -0800975 const u16 *REG_TEMP_OFFSET;
976
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700977 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700978 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700979
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800980 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
981 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
982
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700983 struct mutex update_lock;
984 bool valid; /* true if following fields are valid */
985 unsigned long last_updated; /* In jiffies */
986
987 /* Register values */
988 u8 bank; /* current register bank */
989 u8 in_num; /* number of in inputs we have */
990 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700991 unsigned int rpm[NUM_FAN];
992 u16 fan_min[NUM_FAN];
993 u8 fan_pulses[NUM_FAN];
994 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800995 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800996 u8 has_fan; /* some fan inputs can be disabled */
997 u8 has_fan_min; /* some fans don't have min register */
998 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700999
Guenter Roeck6c009502012-07-01 08:23:15 -07001000 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001001 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001002 u8 temp_fixed_num; /* 3 or 6 */
1003 u8 temp_type[NUM_TEMP_FIXED];
1004 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001005 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1006 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001007 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001008 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001009
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001010 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -07001011 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
1012 * 0->PWM variable duty cycle
1013 */
1014 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001015 /* 0->off
1016 * 1->manual
1017 * 2->thermal cruise mode (also called SmartFan I)
1018 * 3->fan speed cruise mode
1019 * 4->SmartFan III
1020 * 5->enhanced variable thermal cruise (SmartFan IV)
1021 */
David Bartley578ab5f2013-06-24 22:28:28 -07001022 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1023 * [3]=pwm_max, [4]=pwm_step,
1024 * [5]=weight_duty_step, [6]=weight_duty_base
1025 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001026
David Bartley578ab5f2013-06-24 22:28:28 -07001027 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001028 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001029 u32 target_speed[NUM_FAN];
1030 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001031 u8 speed_tolerance_limit;
1032
David Bartley578ab5f2013-06-24 22:28:28 -07001033 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001034 u8 tolerance_mask;
1035
David Bartley578ab5f2013-06-24 22:28:28 -07001036 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001037
1038 /* Automatic fan speed control registers */
1039 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001040 u8 auto_pwm[NUM_FAN][7];
1041 u8 auto_temp[NUM_FAN][7];
1042 u8 pwm_temp_sel[NUM_FAN];
1043 u8 pwm_weight_temp_sel[NUM_FAN];
1044 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1045 * 2->temp_base
1046 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001047
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001048 u8 vid;
1049 u8 vrm;
1050
Guenter Roeckf73cf632013-03-18 09:22:50 -07001051 bool have_vid;
1052
Guenter Roeckaa136e52012-12-04 03:26:05 -08001053 u16 have_temp;
1054 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001055 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001056
Guenter Roeck84d19d92012-12-04 08:01:39 -08001057 /* Remember extra register values over suspend/resume */
1058 u8 vbat;
1059 u8 fandiv1;
1060 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001061 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001062};
1063
1064struct nct6775_sio_data {
1065 int sioreg;
1066 enum kinds kind;
1067};
1068
Guenter Roeckf73cf632013-03-18 09:22:50 -07001069struct sensor_device_template {
1070 struct device_attribute dev_attr;
1071 union {
1072 struct {
1073 u8 nr;
1074 u8 index;
1075 } s;
1076 int index;
1077 } u;
1078 bool s2; /* true if both index and nr are used */
1079};
1080
1081struct sensor_device_attr_u {
1082 union {
1083 struct sensor_device_attribute a1;
1084 struct sensor_device_attribute_2 a2;
1085 } u;
1086 char name[32];
1087};
1088
1089#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1090 .attr = {.name = _template, .mode = _mode }, \
1091 .show = _show, \
1092 .store = _store, \
1093}
1094
1095#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1096 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1097 .u.index = _index, \
1098 .s2 = false }
1099
1100#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1101 _nr, _index) \
1102 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1103 .u.s.index = _index, \
1104 .u.s.nr = _nr, \
1105 .s2 = true }
1106
1107#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1108static struct sensor_device_template sensor_dev_template_##_name \
1109 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1110 _index)
1111
1112#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1113 _nr, _index) \
1114static struct sensor_device_template sensor_dev_template_##_name \
1115 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1116 _nr, _index)
1117
1118struct sensor_template_group {
1119 struct sensor_device_template **templates;
1120 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1121 int base;
1122};
1123
1124static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001125nct6775_create_attr_group(struct device *dev,
1126 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001127 int repeat)
1128{
1129 struct attribute_group *group;
1130 struct sensor_device_attr_u *su;
1131 struct sensor_device_attribute *a;
1132 struct sensor_device_attribute_2 *a2;
1133 struct attribute **attrs;
1134 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001135 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001136
1137 if (repeat <= 0)
1138 return ERR_PTR(-EINVAL);
1139
1140 t = tg->templates;
1141 for (count = 0; *t; t++, count++)
1142 ;
1143
1144 if (count == 0)
1145 return ERR_PTR(-EINVAL);
1146
1147 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1148 if (group == NULL)
1149 return ERR_PTR(-ENOMEM);
1150
1151 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1152 GFP_KERNEL);
1153 if (attrs == NULL)
1154 return ERR_PTR(-ENOMEM);
1155
1156 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1157 GFP_KERNEL);
1158 if (su == NULL)
1159 return ERR_PTR(-ENOMEM);
1160
1161 group->attrs = attrs;
1162 group->is_visible = tg->is_visible;
1163
1164 for (i = 0; i < repeat; i++) {
1165 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001166 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001167 snprintf(su->name, sizeof(su->name),
1168 (*t)->dev_attr.attr.name, tg->base + i);
1169 if ((*t)->s2) {
1170 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001171 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001172 a2->dev_attr.attr.name = su->name;
1173 a2->nr = (*t)->u.s.nr + i;
1174 a2->index = (*t)->u.s.index;
1175 a2->dev_attr.attr.mode =
1176 (*t)->dev_attr.attr.mode;
1177 a2->dev_attr.show = (*t)->dev_attr.show;
1178 a2->dev_attr.store = (*t)->dev_attr.store;
1179 *attrs = &a2->dev_attr.attr;
1180 } else {
1181 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001182 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001183 a->dev_attr.attr.name = su->name;
1184 a->index = (*t)->u.index + i;
1185 a->dev_attr.attr.mode =
1186 (*t)->dev_attr.attr.mode;
1187 a->dev_attr.show = (*t)->dev_attr.show;
1188 a->dev_attr.store = (*t)->dev_attr.store;
1189 *attrs = &a->dev_attr.attr;
1190 }
1191 attrs++;
1192 su++;
1193 t++;
1194 }
1195 }
1196
Guenter Roeckf73cf632013-03-18 09:22:50 -07001197 return group;
1198}
1199
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001200static bool is_word_sized(struct nct6775_data *data, u16 reg)
1201{
1202 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001203 case nct6106:
1204 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1205 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1206 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001207 case nct6775:
1208 return (((reg & 0xff00) == 0x100 ||
1209 (reg & 0xff00) == 0x200) &&
1210 ((reg & 0x00ff) == 0x50 ||
1211 (reg & 0x00ff) == 0x53 ||
1212 (reg & 0x00ff) == 0x55)) ||
1213 (reg & 0xfff0) == 0x630 ||
1214 reg == 0x640 || reg == 0x642 ||
1215 reg == 0x662 ||
1216 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1217 reg == 0x73 || reg == 0x75 || reg == 0x77;
1218 case nct6776:
1219 return (((reg & 0xff00) == 0x100 ||
1220 (reg & 0xff00) == 0x200) &&
1221 ((reg & 0x00ff) == 0x50 ||
1222 (reg & 0x00ff) == 0x53 ||
1223 (reg & 0x00ff) == 0x55)) ||
1224 (reg & 0xfff0) == 0x630 ||
1225 reg == 0x402 ||
1226 reg == 0x640 || reg == 0x642 ||
1227 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1228 reg == 0x73 || reg == 0x75 || reg == 0x77;
1229 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001230 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001231 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001232 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001233 case nct6795:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001234 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001235 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001236 reg == 0x402 ||
1237 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1238 reg == 0x640 || reg == 0x642 ||
1239 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001240 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001241 }
1242 return false;
1243}
1244
1245/*
1246 * On older chips, only registers 0x50-0x5f are banked.
1247 * On more recent chips, all registers are banked.
1248 * Assume that is the case and set the bank number for each access.
1249 * Cache the bank number so it only needs to be set if it changes.
1250 */
1251static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1252{
1253 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001254
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001255 if (data->bank != bank) {
1256 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1257 outb_p(bank, data->addr + DATA_REG_OFFSET);
1258 data->bank = bank;
1259 }
1260}
1261
1262static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1263{
1264 int res, word_sized = is_word_sized(data, reg);
1265
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001266 nct6775_set_bank(data, reg);
1267 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1268 res = inb_p(data->addr + DATA_REG_OFFSET);
1269 if (word_sized) {
1270 outb_p((reg & 0xff) + 1,
1271 data->addr + ADDR_REG_OFFSET);
1272 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1273 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001274 return res;
1275}
1276
1277static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1278{
1279 int word_sized = is_word_sized(data, reg);
1280
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001281 nct6775_set_bank(data, reg);
1282 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1283 if (word_sized) {
1284 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1285 outb_p((reg & 0xff) + 1,
1286 data->addr + ADDR_REG_OFFSET);
1287 }
1288 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001289 return 0;
1290}
1291
Guenter Roeckaa136e52012-12-04 03:26:05 -08001292/* We left-align 8-bit temperature values to make the code simpler */
1293static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1294{
1295 u16 res;
1296
1297 res = nct6775_read_value(data, reg);
1298 if (!is_word_sized(data, reg))
1299 res <<= 8;
1300
1301 return res;
1302}
1303
1304static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1305{
1306 if (!is_word_sized(data, reg))
1307 value >>= 8;
1308 return nct6775_write_value(data, reg, value);
1309}
1310
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001311/* This function assumes that the caller holds data->update_lock */
1312static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1313{
1314 u8 reg;
1315
1316 switch (nr) {
1317 case 0:
1318 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1319 | (data->fan_div[0] & 0x7);
1320 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1321 break;
1322 case 1:
1323 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1324 | ((data->fan_div[1] << 4) & 0x70);
1325 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1326 break;
1327 case 2:
1328 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1329 | (data->fan_div[2] & 0x7);
1330 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1331 break;
1332 case 3:
1333 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1334 | ((data->fan_div[3] << 4) & 0x70);
1335 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1336 break;
1337 }
1338}
1339
1340static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1341{
1342 if (data->kind == nct6775)
1343 nct6775_write_fan_div(data, nr);
1344}
1345
1346static void nct6775_update_fan_div(struct nct6775_data *data)
1347{
1348 u8 i;
1349
1350 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1351 data->fan_div[0] = i & 0x7;
1352 data->fan_div[1] = (i & 0x70) >> 4;
1353 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1354 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001355 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001356 data->fan_div[3] = (i & 0x70) >> 4;
1357}
1358
1359static void nct6775_update_fan_div_common(struct nct6775_data *data)
1360{
1361 if (data->kind == nct6775)
1362 nct6775_update_fan_div(data);
1363}
1364
1365static void nct6775_init_fan_div(struct nct6775_data *data)
1366{
1367 int i;
1368
1369 nct6775_update_fan_div_common(data);
1370 /*
1371 * For all fans, start with highest divider value if the divider
1372 * register is not initialized. This ensures that we get a
1373 * reading from the fan count register, even if it is not optimal.
1374 * We'll compute a better divider later on.
1375 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001376 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001377 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001378 continue;
1379 if (data->fan_div[i] == 0) {
1380 data->fan_div[i] = 7;
1381 nct6775_write_fan_div_common(data, i);
1382 }
1383 }
1384}
1385
1386static void nct6775_init_fan_common(struct device *dev,
1387 struct nct6775_data *data)
1388{
1389 int i;
1390 u8 reg;
1391
1392 if (data->has_fan_div)
1393 nct6775_init_fan_div(data);
1394
1395 /*
1396 * If fan_min is not set (0), set it to 0xff to disable it. This
1397 * prevents the unnecessary warning when fanX_min is reported as 0.
1398 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001399 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001400 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001401 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1402 if (!reg)
1403 nct6775_write_value(data, data->REG_FAN_MIN[i],
1404 data->has_fan_div ? 0xff
1405 : 0xff1f);
1406 }
1407 }
1408}
1409
1410static void nct6775_select_fan_div(struct device *dev,
1411 struct nct6775_data *data, int nr, u16 reg)
1412{
1413 u8 fan_div = data->fan_div[nr];
1414 u16 fan_min;
1415
1416 if (!data->has_fan_div)
1417 return;
1418
1419 /*
1420 * If we failed to measure the fan speed, or the reported value is not
1421 * in the optimal range, and the clock divider can be modified,
1422 * let's try that for next time.
1423 */
1424 if (reg == 0x00 && fan_div < 0x07)
1425 fan_div++;
1426 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1427 fan_div--;
1428
1429 if (fan_div != data->fan_div[nr]) {
1430 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1431 nr + 1, div_from_reg(data->fan_div[nr]),
1432 div_from_reg(fan_div));
1433
1434 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001435 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001436 fan_min = data->fan_min[nr];
1437 if (fan_div > data->fan_div[nr]) {
1438 if (fan_min != 255 && fan_min > 1)
1439 fan_min >>= 1;
1440 } else {
1441 if (fan_min != 255) {
1442 fan_min <<= 1;
1443 if (fan_min > 254)
1444 fan_min = 254;
1445 }
1446 }
1447 if (fan_min != data->fan_min[nr]) {
1448 data->fan_min[nr] = fan_min;
1449 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1450 fan_min);
1451 }
1452 }
1453 data->fan_div[nr] = fan_div;
1454 nct6775_write_fan_div_common(data, nr);
1455 }
1456}
1457
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001458static void nct6775_update_pwm(struct device *dev)
1459{
1460 struct nct6775_data *data = dev_get_drvdata(dev);
1461 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001462 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001463 bool duty_is_dc;
1464
1465 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001466 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001467 continue;
1468
1469 duty_is_dc = data->REG_PWM_MODE[i] &&
1470 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1471 & data->PWM_MODE_MASK[i]);
1472 data->pwm_mode[i] = duty_is_dc;
1473
1474 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1475 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1476 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1477 data->pwm[j][i]
1478 = nct6775_read_value(data,
1479 data->REG_PWM[j][i]);
1480 }
1481 }
1482
1483 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1484 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001485
1486 if (!data->temp_tolerance[0][i] ||
1487 data->pwm_enable[i] != speed_cruise)
1488 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1489 if (!data->target_speed_tolerance[i] ||
1490 data->pwm_enable[i] == speed_cruise) {
1491 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001492
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001493 if (data->REG_TOLERANCE_H) {
1494 t |= (nct6775_read_value(data,
1495 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1496 }
1497 data->target_speed_tolerance[i] = t;
1498 }
1499
1500 data->temp_tolerance[1][i] =
1501 nct6775_read_value(data,
1502 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1503
1504 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1505 data->pwm_temp_sel[i] = reg & 0x1f;
1506 /* If fan can stop, report floor as 0 */
1507 if (reg & 0x80)
1508 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001509
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001510 if (!data->REG_WEIGHT_TEMP_SEL[i])
1511 continue;
1512
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001513 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1514 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1515 /* If weight is disabled, report weight source as 0 */
1516 if (j == 1 && !(reg & 0x80))
1517 data->pwm_weight_temp_sel[i] = 0;
1518
1519 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001520 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001521 data->weight_temp[j][i]
1522 = nct6775_read_value(data,
1523 data->REG_WEIGHT_TEMP[j][i]);
1524 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001525 }
1526}
1527
1528static void nct6775_update_pwm_limits(struct device *dev)
1529{
1530 struct nct6775_data *data = dev_get_drvdata(dev);
1531 int i, j;
1532 u8 reg;
1533 u16 reg_t;
1534
1535 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001536 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001537 continue;
1538
Guenter Roeckc409fd42013-04-09 05:04:00 -07001539 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001540 data->fan_time[j][i] =
1541 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1542 }
1543
1544 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1545 /* Update only in matching mode or if never updated */
1546 if (!data->target_temp[i] ||
1547 data->pwm_enable[i] == thermal_cruise)
1548 data->target_temp[i] = reg_t & data->target_temp_mask;
1549 if (!data->target_speed[i] ||
1550 data->pwm_enable[i] == speed_cruise) {
1551 if (data->REG_TOLERANCE_H) {
1552 reg_t |= (nct6775_read_value(data,
1553 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1554 }
1555 data->target_speed[i] = reg_t;
1556 }
1557
1558 for (j = 0; j < data->auto_pwm_num; j++) {
1559 data->auto_pwm[i][j] =
1560 nct6775_read_value(data,
1561 NCT6775_AUTO_PWM(data, i, j));
1562 data->auto_temp[i][j] =
1563 nct6775_read_value(data,
1564 NCT6775_AUTO_TEMP(data, i, j));
1565 }
1566
1567 /* critical auto_pwm temperature data */
1568 data->auto_temp[i][data->auto_pwm_num] =
1569 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1570
1571 switch (data->kind) {
1572 case nct6775:
1573 reg = nct6775_read_value(data,
1574 NCT6775_REG_CRITICAL_ENAB[i]);
1575 data->auto_pwm[i][data->auto_pwm_num] =
1576 (reg & 0x02) ? 0xff : 0x00;
1577 break;
1578 case nct6776:
1579 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1580 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001581 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001582 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001583 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001584 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001585 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001586 case nct6795:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001587 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001588 data->REG_CRITICAL_PWM_ENABLE[i]);
1589 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1590 reg = nct6775_read_value(data,
1591 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001592 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001593 reg = 0xff;
1594 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001595 break;
1596 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001597 }
1598}
1599
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001600static struct nct6775_data *nct6775_update_device(struct device *dev)
1601{
1602 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001603 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001604
1605 mutex_lock(&data->update_lock);
1606
Guenter Roeck6445e662013-04-21 09:13:28 -07001607 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001608 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001609 /* Fan clock dividers */
1610 nct6775_update_fan_div_common(data);
1611
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001612 /* Measured voltages and limits */
1613 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001614 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001615 continue;
1616
1617 data->in[i][0] = nct6775_read_value(data,
1618 data->REG_VIN[i]);
1619 data->in[i][1] = nct6775_read_value(data,
1620 data->REG_IN_MINMAX[0][i]);
1621 data->in[i][2] = nct6775_read_value(data,
1622 data->REG_IN_MINMAX[1][i]);
1623 }
1624
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001625 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001626 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001627 u16 reg;
1628
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001629 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001630 continue;
1631
1632 reg = nct6775_read_value(data, data->REG_FAN[i]);
1633 data->rpm[i] = data->fan_from_reg(reg,
1634 data->fan_div[i]);
1635
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001636 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001637 data->fan_min[i] = nct6775_read_value(data,
1638 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001639 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001640 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1641 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001642
1643 nct6775_select_fan_div(dev, data, i, reg);
1644 }
1645
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001646 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001647 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001648
Guenter Roeckaa136e52012-12-04 03:26:05 -08001649 /* Measured temperatures and limits */
1650 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001651 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001652 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001653 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001654 if (data->reg_temp[j][i])
1655 data->temp[j][i]
1656 = nct6775_read_temp(data,
1657 data->reg_temp[j][i]);
1658 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001659 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001660 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001661 continue;
1662 data->temp_offset[i]
1663 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1664 }
1665
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001666 data->alarms = 0;
1667 for (i = 0; i < NUM_REG_ALARM; i++) {
1668 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001669
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001670 if (!data->REG_ALARM[i])
1671 continue;
1672 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1673 data->alarms |= ((u64)alarm) << (i << 3);
1674 }
1675
Guenter Roeck30846992013-06-24 22:21:59 -07001676 data->beeps = 0;
1677 for (i = 0; i < NUM_REG_BEEP; i++) {
1678 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001679
Guenter Roeck30846992013-06-24 22:21:59 -07001680 if (!data->REG_BEEP[i])
1681 continue;
1682 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1683 data->beeps |= ((u64)beep) << (i << 3);
1684 }
1685
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001686 data->last_updated = jiffies;
1687 data->valid = true;
1688 }
1689
1690 mutex_unlock(&data->update_lock);
1691 return data;
1692}
1693
1694/*
1695 * Sysfs callback functions
1696 */
1697static ssize_t
1698show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1699{
1700 struct nct6775_data *data = nct6775_update_device(dev);
1701 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001702 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001703 int nr = sattr->nr;
1704
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001705 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1706}
1707
1708static ssize_t
1709store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1710 size_t count)
1711{
1712 struct nct6775_data *data = dev_get_drvdata(dev);
1713 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001714 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001715 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001716 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001717 int err;
1718
1719 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001720 if (err < 0)
1721 return err;
1722 mutex_lock(&data->update_lock);
1723 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001724 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001725 data->in[nr][index]);
1726 mutex_unlock(&data->update_lock);
1727 return count;
1728}
1729
1730static ssize_t
1731show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1732{
1733 struct nct6775_data *data = nct6775_update_device(dev);
1734 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1735 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001736
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001737 return sprintf(buf, "%u\n",
1738 (unsigned int)((data->alarms >> nr) & 0x01));
1739}
1740
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001741static int find_temp_source(struct nct6775_data *data, int index, int count)
1742{
1743 int source = data->temp_src[index];
1744 int nr;
1745
1746 for (nr = 0; nr < count; nr++) {
1747 int src;
1748
1749 src = nct6775_read_value(data,
1750 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1751 if (src == source)
1752 return nr;
1753 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001754 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001755}
1756
1757static ssize_t
1758show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1759{
1760 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1761 struct nct6775_data *data = nct6775_update_device(dev);
1762 unsigned int alarm = 0;
1763 int nr;
1764
1765 /*
1766 * For temperatures, there is no fixed mapping from registers to alarm
1767 * bits. Alarm bits are determined by the temperature source mapping.
1768 */
1769 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1770 if (nr >= 0) {
1771 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001772
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001773 alarm = (data->alarms >> bit) & 0x01;
1774 }
1775 return sprintf(buf, "%u\n", alarm);
1776}
1777
Guenter Roeck30846992013-06-24 22:21:59 -07001778static ssize_t
1779show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1780{
1781 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1782 struct nct6775_data *data = nct6775_update_device(dev);
1783 int nr = data->BEEP_BITS[sattr->index];
1784
1785 return sprintf(buf, "%u\n",
1786 (unsigned int)((data->beeps >> nr) & 0x01));
1787}
1788
1789static ssize_t
1790store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1791 size_t count)
1792{
1793 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1794 struct nct6775_data *data = dev_get_drvdata(dev);
1795 int nr = data->BEEP_BITS[sattr->index];
1796 int regindex = nr >> 3;
1797 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001798 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001799
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001800 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001801 if (err < 0)
1802 return err;
1803 if (val > 1)
1804 return -EINVAL;
1805
1806 mutex_lock(&data->update_lock);
1807 if (val)
1808 data->beeps |= (1ULL << nr);
1809 else
1810 data->beeps &= ~(1ULL << nr);
1811 nct6775_write_value(data, data->REG_BEEP[regindex],
1812 (data->beeps >> (regindex << 3)) & 0xff);
1813 mutex_unlock(&data->update_lock);
1814 return count;
1815}
1816
1817static ssize_t
1818show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1819{
1820 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1821 struct nct6775_data *data = nct6775_update_device(dev);
1822 unsigned int beep = 0;
1823 int nr;
1824
1825 /*
1826 * For temperatures, there is no fixed mapping from registers to beep
1827 * enable bits. Beep enable bits are determined by the temperature
1828 * source mapping.
1829 */
1830 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1831 if (nr >= 0) {
1832 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001833
Guenter Roeck30846992013-06-24 22:21:59 -07001834 beep = (data->beeps >> bit) & 0x01;
1835 }
1836 return sprintf(buf, "%u\n", beep);
1837}
1838
1839static ssize_t
1840store_temp_beep(struct device *dev, struct device_attribute *attr,
1841 const char *buf, size_t count)
1842{
1843 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1844 struct nct6775_data *data = dev_get_drvdata(dev);
1845 int nr, bit, regindex;
1846 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001847 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001848
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001849 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001850 if (err < 0)
1851 return err;
1852 if (val > 1)
1853 return -EINVAL;
1854
1855 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1856 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001857 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001858
1859 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1860 regindex = bit >> 3;
1861
1862 mutex_lock(&data->update_lock);
1863 if (val)
1864 data->beeps |= (1ULL << bit);
1865 else
1866 data->beeps &= ~(1ULL << bit);
1867 nct6775_write_value(data, data->REG_BEEP[regindex],
1868 (data->beeps >> (regindex << 3)) & 0xff);
1869 mutex_unlock(&data->update_lock);
1870
1871 return count;
1872}
1873
Guenter Roeckf73cf632013-03-18 09:22:50 -07001874static umode_t nct6775_in_is_visible(struct kobject *kobj,
1875 struct attribute *attr, int index)
1876{
1877 struct device *dev = container_of(kobj, struct device, kobj);
1878 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001879 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001880
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001881 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001882 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001883
Guenter Roeckf73cf632013-03-18 09:22:50 -07001884 return attr->mode;
1885}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001886
Guenter Roeckf73cf632013-03-18 09:22:50 -07001887SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1888SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001889SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1890 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001891SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1892 store_in_reg, 0, 1);
1893SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1894 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001895
Guenter Roeckf73cf632013-03-18 09:22:50 -07001896/*
1897 * nct6775_in_is_visible uses the index into the following array
1898 * to determine if attributes should be created or not.
1899 * Any change in order or content must be matched.
1900 */
1901static struct sensor_device_template *nct6775_attributes_in_template[] = {
1902 &sensor_dev_template_in_input,
1903 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001904 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001905 &sensor_dev_template_in_min,
1906 &sensor_dev_template_in_max,
1907 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001908};
1909
Julia Lawallc60fdf82015-12-12 17:36:39 +01001910static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001911 .templates = nct6775_attributes_in_template,
1912 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001913};
1914
1915static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001916show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1917{
1918 struct nct6775_data *data = nct6775_update_device(dev);
1919 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1920 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001921
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001922 return sprintf(buf, "%d\n", data->rpm[nr]);
1923}
1924
1925static ssize_t
1926show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1927{
1928 struct nct6775_data *data = nct6775_update_device(dev);
1929 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1930 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001931
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001932 return sprintf(buf, "%d\n",
1933 data->fan_from_reg_min(data->fan_min[nr],
1934 data->fan_div[nr]));
1935}
1936
1937static ssize_t
1938show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1939{
1940 struct nct6775_data *data = nct6775_update_device(dev);
1941 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1942 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001943
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001944 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1945}
1946
1947static ssize_t
1948store_fan_min(struct device *dev, struct device_attribute *attr,
1949 const char *buf, size_t count)
1950{
1951 struct nct6775_data *data = dev_get_drvdata(dev);
1952 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1953 int nr = sattr->index;
1954 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001955 unsigned int reg;
1956 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001957 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001958
1959 err = kstrtoul(buf, 10, &val);
1960 if (err < 0)
1961 return err;
1962
1963 mutex_lock(&data->update_lock);
1964 if (!data->has_fan_div) {
1965 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1966 if (!val) {
1967 val = 0xff1f;
1968 } else {
1969 if (val > 1350000U)
1970 val = 135000U;
1971 val = 1350000U / val;
1972 val = (val & 0x1f) | ((val << 3) & 0xff00);
1973 }
1974 data->fan_min[nr] = val;
1975 goto write_min; /* Leave fan divider alone */
1976 }
1977 if (!val) {
1978 /* No min limit, alarm disabled */
1979 data->fan_min[nr] = 255;
1980 new_div = data->fan_div[nr]; /* No change */
1981 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1982 goto write_div;
1983 }
1984 reg = 1350000U / val;
1985 if (reg >= 128 * 255) {
1986 /*
1987 * Speed below this value cannot possibly be represented,
1988 * even with the highest divider (128)
1989 */
1990 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001991 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001992 dev_warn(dev,
1993 "fan%u low limit %lu below minimum %u, set to minimum\n",
1994 nr + 1, val, data->fan_from_reg_min(254, 7));
1995 } else if (!reg) {
1996 /*
1997 * Speed above this value cannot possibly be represented,
1998 * even with the lowest divider (1)
1999 */
2000 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002001 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002002 dev_warn(dev,
2003 "fan%u low limit %lu above maximum %u, set to maximum\n",
2004 nr + 1, val, data->fan_from_reg_min(1, 0));
2005 } else {
2006 /*
2007 * Automatically pick the best divider, i.e. the one such
2008 * that the min limit will correspond to a register value
2009 * in the 96..192 range
2010 */
2011 new_div = 0;
2012 while (reg > 192 && new_div < 7) {
2013 reg >>= 1;
2014 new_div++;
2015 }
2016 data->fan_min[nr] = reg;
2017 }
2018
2019write_div:
2020 /*
2021 * Write both the fan clock divider (if it changed) and the new
2022 * fan min (unconditionally)
2023 */
2024 if (new_div != data->fan_div[nr]) {
2025 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2026 nr + 1, div_from_reg(data->fan_div[nr]),
2027 div_from_reg(new_div));
2028 data->fan_div[nr] = new_div;
2029 nct6775_write_fan_div_common(data, nr);
2030 /* Give the chip time to sample a new speed value */
2031 data->last_updated = jiffies;
2032 }
2033
2034write_min:
2035 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2036 mutex_unlock(&data->update_lock);
2037
2038 return count;
2039}
2040
Guenter Roeck5c25d952012-12-11 07:29:06 -08002041static ssize_t
2042show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2043{
2044 struct nct6775_data *data = nct6775_update_device(dev);
2045 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2046 int p = data->fan_pulses[sattr->index];
2047
2048 return sprintf(buf, "%d\n", p ? : 4);
2049}
2050
2051static ssize_t
2052store_fan_pulses(struct device *dev, struct device_attribute *attr,
2053 const char *buf, size_t count)
2054{
2055 struct nct6775_data *data = dev_get_drvdata(dev);
2056 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2057 int nr = sattr->index;
2058 unsigned long val;
2059 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002060 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002061
2062 err = kstrtoul(buf, 10, &val);
2063 if (err < 0)
2064 return err;
2065
2066 if (val > 4)
2067 return -EINVAL;
2068
2069 mutex_lock(&data->update_lock);
2070 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002071 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2072 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2073 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2074 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002075 mutex_unlock(&data->update_lock);
2076
2077 return count;
2078}
2079
Guenter Roeckf73cf632013-03-18 09:22:50 -07002080static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2081 struct attribute *attr, int index)
2082{
2083 struct device *dev = container_of(kobj, struct device, kobj);
2084 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002085 int fan = index / 6; /* fan index */
2086 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002087
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002088 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002089 return 0;
2090
2091 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2092 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002093 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002094 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002095 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002096 return 0;
2097 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002098 return 0;
2099
2100 return attr->mode;
2101}
2102
2103SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2104SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2105 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002106SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2107 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002108SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2109 store_fan_pulses, 0);
2110SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2111 store_fan_min, 0);
2112SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2113
2114/*
2115 * nct6775_fan_is_visible uses the index into the following array
2116 * to determine if attributes should be created or not.
2117 * Any change in order or content must be matched.
2118 */
2119static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2120 &sensor_dev_template_fan_input,
2121 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002122 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002123 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002124 &sensor_dev_template_fan_min, /* 4 */
2125 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002126 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002127};
2128
Julia Lawallc60fdf82015-12-12 17:36:39 +01002129static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002130 .templates = nct6775_attributes_fan_template,
2131 .is_visible = nct6775_fan_is_visible,
2132 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002133};
2134
2135static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002136show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2137{
2138 struct nct6775_data *data = nct6775_update_device(dev);
2139 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2140 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002141
Guenter Roeckaa136e52012-12-04 03:26:05 -08002142 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2143}
2144
2145static ssize_t
2146show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2147{
2148 struct nct6775_data *data = nct6775_update_device(dev);
2149 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2150 int nr = sattr->nr;
2151 int index = sattr->index;
2152
2153 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2154}
2155
2156static ssize_t
2157store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2158 size_t count)
2159{
2160 struct nct6775_data *data = dev_get_drvdata(dev);
2161 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2162 int nr = sattr->nr;
2163 int index = sattr->index;
2164 int err;
2165 long val;
2166
2167 err = kstrtol(buf, 10, &val);
2168 if (err < 0)
2169 return err;
2170
2171 mutex_lock(&data->update_lock);
2172 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2173 nct6775_write_temp(data, data->reg_temp[index][nr],
2174 data->temp[index][nr]);
2175 mutex_unlock(&data->update_lock);
2176 return count;
2177}
2178
2179static ssize_t
2180show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2181{
2182 struct nct6775_data *data = nct6775_update_device(dev);
2183 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2184
2185 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2186}
2187
2188static ssize_t
2189store_temp_offset(struct device *dev, struct device_attribute *attr,
2190 const char *buf, size_t count)
2191{
2192 struct nct6775_data *data = dev_get_drvdata(dev);
2193 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2194 int nr = sattr->index;
2195 long val;
2196 int err;
2197
2198 err = kstrtol(buf, 10, &val);
2199 if (err < 0)
2200 return err;
2201
2202 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2203
2204 mutex_lock(&data->update_lock);
2205 data->temp_offset[nr] = val;
2206 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2207 mutex_unlock(&data->update_lock);
2208
2209 return count;
2210}
2211
2212static ssize_t
2213show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2214{
2215 struct nct6775_data *data = nct6775_update_device(dev);
2216 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2217 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002218
Guenter Roeckaa136e52012-12-04 03:26:05 -08002219 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2220}
2221
2222static ssize_t
2223store_temp_type(struct device *dev, struct device_attribute *attr,
2224 const char *buf, size_t count)
2225{
2226 struct nct6775_data *data = nct6775_update_device(dev);
2227 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2228 int nr = sattr->index;
2229 unsigned long val;
2230 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002231 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002232
2233 err = kstrtoul(buf, 10, &val);
2234 if (err < 0)
2235 return err;
2236
2237 if (val != 1 && val != 3 && val != 4)
2238 return -EINVAL;
2239
2240 mutex_lock(&data->update_lock);
2241
2242 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002243 vbit = 0x02 << nr;
2244 dbit = data->DIODE_MASK << nr;
2245 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2246 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002247 switch (val) {
2248 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002249 vbat |= vbit;
2250 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002251 break;
2252 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002253 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002254 break;
2255 case 4: /* thermistor */
2256 break;
2257 }
2258 nct6775_write_value(data, data->REG_VBAT, vbat);
2259 nct6775_write_value(data, data->REG_DIODE, diode);
2260
2261 mutex_unlock(&data->update_lock);
2262 return count;
2263}
2264
Guenter Roeckf73cf632013-03-18 09:22:50 -07002265static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2266 struct attribute *attr, int index)
2267{
2268 struct device *dev = container_of(kobj, struct device, kobj);
2269 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002270 int temp = index / 10; /* temp index */
2271 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002272
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002273 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002274 return 0;
2275
Guenter Roeckcc66b302017-05-17 18:05:06 -07002276 if (nr == 1 && !data->temp_label)
2277 return 0;
2278
Guenter Roeckf73cf632013-03-18 09:22:50 -07002279 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2280 return 0; /* alarm */
2281
Guenter Roeck30846992013-06-24 22:21:59 -07002282 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2283 return 0; /* beep */
2284
2285 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002286 return 0;
2287
Guenter Roeck30846992013-06-24 22:21:59 -07002288 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002289 return 0;
2290
Guenter Roeck30846992013-06-24 22:21:59 -07002291 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002292 return 0;
2293
Guenter Roeck30846992013-06-24 22:21:59 -07002294 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002295 return 0;
2296
2297 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002298 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002299 return 0;
2300
2301 return attr->mode;
2302}
2303
2304SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2305SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2306SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2307 store_temp, 0, 1);
2308SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2309 show_temp, store_temp, 0, 2);
2310SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2311 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002312SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2313 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002314SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2315 show_temp_offset, store_temp_offset, 0);
2316SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2317 store_temp_type, 0);
2318SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002319SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2320 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002321
2322/*
2323 * nct6775_temp_is_visible uses the index into the following array
2324 * to determine if attributes should be created or not.
2325 * Any change in order or content must be matched.
2326 */
2327static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2328 &sensor_dev_template_temp_input,
2329 &sensor_dev_template_temp_label,
2330 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002331 &sensor_dev_template_temp_beep, /* 3 */
2332 &sensor_dev_template_temp_max, /* 4 */
2333 &sensor_dev_template_temp_max_hyst, /* 5 */
2334 &sensor_dev_template_temp_crit, /* 6 */
2335 &sensor_dev_template_temp_lcrit, /* 7 */
2336 &sensor_dev_template_temp_offset, /* 8 */
2337 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002338 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002339};
2340
Julia Lawallc60fdf82015-12-12 17:36:39 +01002341static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002342 .templates = nct6775_attributes_temp_template,
2343 .is_visible = nct6775_temp_is_visible,
2344 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002345};
2346
Guenter Roeckaa136e52012-12-04 03:26:05 -08002347static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002348show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2349{
2350 struct nct6775_data *data = nct6775_update_device(dev);
2351 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2352
2353 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2354}
2355
2356static ssize_t
2357store_pwm_mode(struct device *dev, struct device_attribute *attr,
2358 const char *buf, size_t count)
2359{
2360 struct nct6775_data *data = dev_get_drvdata(dev);
2361 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2362 int nr = sattr->index;
2363 unsigned long val;
2364 int err;
2365 u8 reg;
2366
2367 err = kstrtoul(buf, 10, &val);
2368 if (err < 0)
2369 return err;
2370
2371 if (val > 1)
2372 return -EINVAL;
2373
2374 /* Setting DC mode is not supported for all chips/channels */
2375 if (data->REG_PWM_MODE[nr] == 0) {
2376 if (val)
2377 return -EINVAL;
2378 return count;
2379 }
2380
2381 mutex_lock(&data->update_lock);
2382 data->pwm_mode[nr] = val;
2383 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2384 reg &= ~data->PWM_MODE_MASK[nr];
2385 if (val)
2386 reg |= data->PWM_MODE_MASK[nr];
2387 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2388 mutex_unlock(&data->update_lock);
2389 return count;
2390}
2391
2392static ssize_t
2393show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2394{
2395 struct nct6775_data *data = nct6775_update_device(dev);
2396 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2397 int nr = sattr->nr;
2398 int index = sattr->index;
2399 int pwm;
2400
2401 /*
2402 * For automatic fan control modes, show current pwm readings.
2403 * Otherwise, show the configured value.
2404 */
2405 if (index == 0 && data->pwm_enable[nr] > manual)
2406 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2407 else
2408 pwm = data->pwm[index][nr];
2409
2410 return sprintf(buf, "%d\n", pwm);
2411}
2412
2413static ssize_t
2414store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2415 size_t count)
2416{
2417 struct nct6775_data *data = dev_get_drvdata(dev);
2418 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2419 int nr = sattr->nr;
2420 int index = sattr->index;
2421 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002422 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2423 int maxval[7]
2424 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002425 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002426 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002427
2428 err = kstrtoul(buf, 10, &val);
2429 if (err < 0)
2430 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002431 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002432
2433 mutex_lock(&data->update_lock);
2434 data->pwm[index][nr] = val;
2435 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002436 if (index == 2) { /* floor: disable if val == 0 */
2437 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2438 reg &= 0x7f;
2439 if (val)
2440 reg |= 0x80;
2441 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2442 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002443 mutex_unlock(&data->update_lock);
2444 return count;
2445}
2446
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002447/* Returns 0 if OK, -EINVAL otherwise */
2448static int check_trip_points(struct nct6775_data *data, int nr)
2449{
2450 int i;
2451
2452 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2453 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2454 return -EINVAL;
2455 }
2456 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2457 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2458 return -EINVAL;
2459 }
2460 /* validate critical temperature and pwm if enabled (pwm > 0) */
2461 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2462 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2463 data->auto_temp[nr][data->auto_pwm_num] ||
2464 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2465 data->auto_pwm[nr][data->auto_pwm_num])
2466 return -EINVAL;
2467 }
2468 return 0;
2469}
2470
2471static void pwm_update_registers(struct nct6775_data *data, int nr)
2472{
2473 u8 reg;
2474
2475 switch (data->pwm_enable[nr]) {
2476 case off:
2477 case manual:
2478 break;
2479 case speed_cruise:
2480 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2481 reg = (reg & ~data->tolerance_mask) |
2482 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2483 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2484 nct6775_write_value(data, data->REG_TARGET[nr],
2485 data->target_speed[nr] & 0xff);
2486 if (data->REG_TOLERANCE_H) {
2487 reg = (data->target_speed[nr] >> 8) & 0x0f;
2488 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2489 nct6775_write_value(data,
2490 data->REG_TOLERANCE_H[nr],
2491 reg);
2492 }
2493 break;
2494 case thermal_cruise:
2495 nct6775_write_value(data, data->REG_TARGET[nr],
2496 data->target_temp[nr]);
2497 /* intentional */
2498 default:
2499 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2500 reg = (reg & ~data->tolerance_mask) |
2501 data->temp_tolerance[0][nr];
2502 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2503 break;
2504 }
2505}
2506
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002507static ssize_t
2508show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2509{
2510 struct nct6775_data *data = nct6775_update_device(dev);
2511 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2512
2513 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2514}
2515
2516static ssize_t
2517store_pwm_enable(struct device *dev, struct device_attribute *attr,
2518 const char *buf, size_t count)
2519{
2520 struct nct6775_data *data = dev_get_drvdata(dev);
2521 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2522 int nr = sattr->index;
2523 unsigned long val;
2524 int err;
2525 u16 reg;
2526
2527 err = kstrtoul(buf, 10, &val);
2528 if (err < 0)
2529 return err;
2530
2531 if (val > sf4)
2532 return -EINVAL;
2533
2534 if (val == sf3 && data->kind != nct6775)
2535 return -EINVAL;
2536
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002537 if (val == sf4 && check_trip_points(data, nr)) {
2538 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2539 dev_err(dev, "Adjust trip points and try again\n");
2540 return -EINVAL;
2541 }
2542
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002543 mutex_lock(&data->update_lock);
2544 data->pwm_enable[nr] = val;
2545 if (val == off) {
2546 /*
2547 * turn off pwm control: select manual mode, set pwm to maximum
2548 */
2549 data->pwm[0][nr] = 255;
2550 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2551 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002552 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002553 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2554 reg &= 0x0f;
2555 reg |= pwm_enable_to_reg(val) << 4;
2556 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2557 mutex_unlock(&data->update_lock);
2558 return count;
2559}
2560
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002561static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002562show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002563{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002564 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002565
2566 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002567 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002568 continue;
2569 if (src == data->temp_src[i]) {
2570 sel = i + 1;
2571 break;
2572 }
2573 }
2574
2575 return sprintf(buf, "%d\n", sel);
2576}
2577
2578static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002579show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2580{
2581 struct nct6775_data *data = nct6775_update_device(dev);
2582 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2583 int index = sattr->index;
2584
2585 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2586}
2587
2588static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002589store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2590 const char *buf, size_t count)
2591{
2592 struct nct6775_data *data = nct6775_update_device(dev);
2593 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2594 int nr = sattr->index;
2595 unsigned long val;
2596 int err, reg, src;
2597
2598 err = kstrtoul(buf, 10, &val);
2599 if (err < 0)
2600 return err;
2601 if (val == 0 || val > NUM_TEMP)
2602 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002603 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002604 return -EINVAL;
2605
2606 mutex_lock(&data->update_lock);
2607 src = data->temp_src[val - 1];
2608 data->pwm_temp_sel[nr] = src;
2609 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2610 reg &= 0xe0;
2611 reg |= src;
2612 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2613 mutex_unlock(&data->update_lock);
2614
2615 return count;
2616}
2617
2618static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002619show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2620 char *buf)
2621{
2622 struct nct6775_data *data = nct6775_update_device(dev);
2623 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2624 int index = sattr->index;
2625
2626 return show_pwm_temp_sel_common(data, buf,
2627 data->pwm_weight_temp_sel[index]);
2628}
2629
2630static ssize_t
2631store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2632 const char *buf, size_t count)
2633{
2634 struct nct6775_data *data = nct6775_update_device(dev);
2635 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2636 int nr = sattr->index;
2637 unsigned long val;
2638 int err, reg, src;
2639
2640 err = kstrtoul(buf, 10, &val);
2641 if (err < 0)
2642 return err;
2643 if (val > NUM_TEMP)
2644 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002645 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002646 !data->temp_src[val - 1]))
2647 return -EINVAL;
2648
2649 mutex_lock(&data->update_lock);
2650 if (val) {
2651 src = data->temp_src[val - 1];
2652 data->pwm_weight_temp_sel[nr] = src;
2653 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2654 reg &= 0xe0;
2655 reg |= (src | 0x80);
2656 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2657 } else {
2658 data->pwm_weight_temp_sel[nr] = 0;
2659 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2660 reg &= 0x7f;
2661 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2662 }
2663 mutex_unlock(&data->update_lock);
2664
2665 return count;
2666}
2667
2668static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002669show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2670{
2671 struct nct6775_data *data = nct6775_update_device(dev);
2672 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2673
2674 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2675}
2676
2677static ssize_t
2678store_target_temp(struct device *dev, struct device_attribute *attr,
2679 const char *buf, size_t count)
2680{
2681 struct nct6775_data *data = dev_get_drvdata(dev);
2682 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2683 int nr = sattr->index;
2684 unsigned long val;
2685 int err;
2686
2687 err = kstrtoul(buf, 10, &val);
2688 if (err < 0)
2689 return err;
2690
2691 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2692 data->target_temp_mask);
2693
2694 mutex_lock(&data->update_lock);
2695 data->target_temp[nr] = val;
2696 pwm_update_registers(data, nr);
2697 mutex_unlock(&data->update_lock);
2698 return count;
2699}
2700
2701static ssize_t
2702show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2703{
2704 struct nct6775_data *data = nct6775_update_device(dev);
2705 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2706 int nr = sattr->index;
2707
2708 return sprintf(buf, "%d\n",
2709 fan_from_reg16(data->target_speed[nr],
2710 data->fan_div[nr]));
2711}
2712
2713static ssize_t
2714store_target_speed(struct device *dev, struct device_attribute *attr,
2715 const char *buf, size_t count)
2716{
2717 struct nct6775_data *data = dev_get_drvdata(dev);
2718 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2719 int nr = sattr->index;
2720 unsigned long val;
2721 int err;
2722 u16 speed;
2723
2724 err = kstrtoul(buf, 10, &val);
2725 if (err < 0)
2726 return err;
2727
2728 val = clamp_val(val, 0, 1350000U);
2729 speed = fan_to_reg(val, data->fan_div[nr]);
2730
2731 mutex_lock(&data->update_lock);
2732 data->target_speed[nr] = speed;
2733 pwm_update_registers(data, nr);
2734 mutex_unlock(&data->update_lock);
2735 return count;
2736}
2737
2738static ssize_t
2739show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2740 char *buf)
2741{
2742 struct nct6775_data *data = nct6775_update_device(dev);
2743 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2744 int nr = sattr->nr;
2745 int index = sattr->index;
2746
2747 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2748}
2749
2750static ssize_t
2751store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2752 const char *buf, size_t count)
2753{
2754 struct nct6775_data *data = dev_get_drvdata(dev);
2755 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2756 int nr = sattr->nr;
2757 int index = sattr->index;
2758 unsigned long val;
2759 int err;
2760
2761 err = kstrtoul(buf, 10, &val);
2762 if (err < 0)
2763 return err;
2764
2765 /* Limit tolerance as needed */
2766 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2767
2768 mutex_lock(&data->update_lock);
2769 data->temp_tolerance[index][nr] = val;
2770 if (index)
2771 pwm_update_registers(data, nr);
2772 else
2773 nct6775_write_value(data,
2774 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2775 val);
2776 mutex_unlock(&data->update_lock);
2777 return count;
2778}
2779
2780/*
2781 * Fan speed tolerance is a tricky beast, since the associated register is
2782 * a tick counter, but the value is reported and configured as rpm.
2783 * Compute resulting low and high rpm values and report the difference.
2784 */
2785static ssize_t
2786show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2787 char *buf)
2788{
2789 struct nct6775_data *data = nct6775_update_device(dev);
2790 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2791 int nr = sattr->index;
2792 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2793 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2794 int tolerance;
2795
2796 if (low <= 0)
2797 low = 1;
2798 if (high > 0xffff)
2799 high = 0xffff;
2800 if (high < low)
2801 high = low;
2802
2803 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2804 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2805
2806 return sprintf(buf, "%d\n", tolerance);
2807}
2808
2809static ssize_t
2810store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2811 const char *buf, size_t count)
2812{
2813 struct nct6775_data *data = dev_get_drvdata(dev);
2814 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2815 int nr = sattr->index;
2816 unsigned long val;
2817 int err;
2818 int low, high;
2819
2820 err = kstrtoul(buf, 10, &val);
2821 if (err < 0)
2822 return err;
2823
2824 high = fan_from_reg16(data->target_speed[nr],
2825 data->fan_div[nr]) + val;
2826 low = fan_from_reg16(data->target_speed[nr],
2827 data->fan_div[nr]) - val;
2828 if (low <= 0)
2829 low = 1;
2830 if (high < low)
2831 high = low;
2832
2833 val = (fan_to_reg(low, data->fan_div[nr]) -
2834 fan_to_reg(high, data->fan_div[nr])) / 2;
2835
2836 /* Limit tolerance as needed */
2837 val = clamp_val(val, 0, data->speed_tolerance_limit);
2838
2839 mutex_lock(&data->update_lock);
2840 data->target_speed_tolerance[nr] = val;
2841 pwm_update_registers(data, nr);
2842 mutex_unlock(&data->update_lock);
2843 return count;
2844}
2845
Guenter Roeckf73cf632013-03-18 09:22:50 -07002846SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2847SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2848 store_pwm_mode, 0);
2849SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2850 store_pwm_enable, 0);
2851SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2852 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2853SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2854 show_target_temp, store_target_temp, 0);
2855SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2856 show_target_speed, store_target_speed, 0);
2857SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2858 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002859
2860/* Smart Fan registers */
2861
2862static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002863show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2864{
2865 struct nct6775_data *data = nct6775_update_device(dev);
2866 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2867 int nr = sattr->nr;
2868 int index = sattr->index;
2869
2870 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2871}
2872
2873static ssize_t
2874store_weight_temp(struct device *dev, struct device_attribute *attr,
2875 const char *buf, size_t count)
2876{
2877 struct nct6775_data *data = dev_get_drvdata(dev);
2878 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2879 int nr = sattr->nr;
2880 int index = sattr->index;
2881 unsigned long val;
2882 int err;
2883
2884 err = kstrtoul(buf, 10, &val);
2885 if (err < 0)
2886 return err;
2887
2888 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2889
2890 mutex_lock(&data->update_lock);
2891 data->weight_temp[index][nr] = val;
2892 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2893 mutex_unlock(&data->update_lock);
2894 return count;
2895}
2896
Guenter Roeckf73cf632013-03-18 09:22:50 -07002897SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2898 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2899SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2900 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2901SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2902 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2903SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2904 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2905SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2906 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2907SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2908 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002909
2910static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002911show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2912{
2913 struct nct6775_data *data = nct6775_update_device(dev);
2914 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2915 int nr = sattr->nr;
2916 int index = sattr->index;
2917
2918 return sprintf(buf, "%d\n",
2919 step_time_from_reg(data->fan_time[index][nr],
2920 data->pwm_mode[nr]));
2921}
2922
2923static ssize_t
2924store_fan_time(struct device *dev, struct device_attribute *attr,
2925 const char *buf, size_t count)
2926{
2927 struct nct6775_data *data = dev_get_drvdata(dev);
2928 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2929 int nr = sattr->nr;
2930 int index = sattr->index;
2931 unsigned long val;
2932 int err;
2933
2934 err = kstrtoul(buf, 10, &val);
2935 if (err < 0)
2936 return err;
2937
2938 val = step_time_to_reg(val, data->pwm_mode[nr]);
2939 mutex_lock(&data->update_lock);
2940 data->fan_time[index][nr] = val;
2941 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2942 mutex_unlock(&data->update_lock);
2943 return count;
2944}
2945
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002946static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002947show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2948{
2949 struct nct6775_data *data = nct6775_update_device(dev);
2950 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2951
2952 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2953}
2954
2955static ssize_t
2956store_auto_pwm(struct device *dev, struct device_attribute *attr,
2957 const char *buf, size_t count)
2958{
2959 struct nct6775_data *data = dev_get_drvdata(dev);
2960 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2961 int nr = sattr->nr;
2962 int point = sattr->index;
2963 unsigned long val;
2964 int err;
2965 u8 reg;
2966
2967 err = kstrtoul(buf, 10, &val);
2968 if (err < 0)
2969 return err;
2970 if (val > 255)
2971 return -EINVAL;
2972
2973 if (point == data->auto_pwm_num) {
2974 if (data->kind != nct6775 && !val)
2975 return -EINVAL;
2976 if (data->kind != nct6779 && val)
2977 val = 0xff;
2978 }
2979
2980 mutex_lock(&data->update_lock);
2981 data->auto_pwm[nr][point] = val;
2982 if (point < data->auto_pwm_num) {
2983 nct6775_write_value(data,
2984 NCT6775_AUTO_PWM(data, nr, point),
2985 data->auto_pwm[nr][point]);
2986 } else {
2987 switch (data->kind) {
2988 case nct6775:
2989 /* disable if needed (pwm == 0) */
2990 reg = nct6775_read_value(data,
2991 NCT6775_REG_CRITICAL_ENAB[nr]);
2992 if (val)
2993 reg |= 0x02;
2994 else
2995 reg &= ~0x02;
2996 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2997 reg);
2998 break;
2999 case nct6776:
3000 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003001 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003002 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003003 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003004 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003005 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003006 case nct6795:
Guenter Roeck6c009502012-07-01 08:23:15 -07003007 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003008 val);
3009 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003010 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003011 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003012 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003013 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003014 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003015 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003016 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003017 reg);
3018 break;
3019 }
3020 }
3021 mutex_unlock(&data->update_lock);
3022 return count;
3023}
3024
3025static ssize_t
3026show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3027{
3028 struct nct6775_data *data = nct6775_update_device(dev);
3029 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3030 int nr = sattr->nr;
3031 int point = sattr->index;
3032
3033 /*
3034 * We don't know for sure if the temperature is signed or unsigned.
3035 * Assume it is unsigned.
3036 */
3037 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3038}
3039
3040static ssize_t
3041store_auto_temp(struct device *dev, struct device_attribute *attr,
3042 const char *buf, size_t count)
3043{
3044 struct nct6775_data *data = dev_get_drvdata(dev);
3045 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3046 int nr = sattr->nr;
3047 int point = sattr->index;
3048 unsigned long val;
3049 int err;
3050
3051 err = kstrtoul(buf, 10, &val);
3052 if (err)
3053 return err;
3054 if (val > 255000)
3055 return -EINVAL;
3056
3057 mutex_lock(&data->update_lock);
3058 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3059 if (point < data->auto_pwm_num) {
3060 nct6775_write_value(data,
3061 NCT6775_AUTO_TEMP(data, nr, point),
3062 data->auto_temp[nr][point]);
3063 } else {
3064 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3065 data->auto_temp[nr][point]);
3066 }
3067 mutex_unlock(&data->update_lock);
3068 return count;
3069}
3070
Guenter Roeckf73cf632013-03-18 09:22:50 -07003071static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3072 struct attribute *attr, int index)
3073{
3074 struct device *dev = container_of(kobj, struct device, kobj);
3075 struct nct6775_data *data = dev_get_drvdata(dev);
3076 int pwm = index / 36; /* pwm index */
3077 int nr = index % 36; /* attribute index */
3078
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003079 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003080 return 0;
3081
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003082 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3083 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3084 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003085 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3086 return 0;
3087 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3088 return 0;
3089 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3090 return 0;
3091
3092 if (nr >= 22 && nr <= 35) { /* auto point */
3093 int api = (nr - 22) / 2; /* auto point index */
3094
3095 if (api > data->auto_pwm_num)
3096 return 0;
3097 }
3098 return attr->mode;
3099}
3100
3101SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3102 show_fan_time, store_fan_time, 0, 0);
3103SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3104 show_fan_time, store_fan_time, 0, 1);
3105SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3106 show_fan_time, store_fan_time, 0, 2);
3107SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3108 store_pwm, 0, 1);
3109SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3110 store_pwm, 0, 2);
3111SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3112 show_temp_tolerance, store_temp_tolerance, 0, 0);
3113SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3114 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3115 0, 1);
3116
3117SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3118 0, 3);
3119
3120SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3121 store_pwm, 0, 4);
3122
3123SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3124 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3125SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3126 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3127
3128SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3129 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3130SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3131 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3132
3133SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3134 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3135SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3136 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3137
3138SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3139 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3140SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3141 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3142
3143SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3144 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3145SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3146 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3147
3148SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3149 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3150SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3151 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3152
3153SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3154 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3155SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3156 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3157
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003158/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003159 * nct6775_pwm_is_visible uses the index into the following array
3160 * to determine if attributes should be created or not.
3161 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003162 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003163static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3164 &sensor_dev_template_pwm,
3165 &sensor_dev_template_pwm_mode,
3166 &sensor_dev_template_pwm_enable,
3167 &sensor_dev_template_pwm_temp_sel,
3168 &sensor_dev_template_pwm_temp_tolerance,
3169 &sensor_dev_template_pwm_crit_temp_tolerance,
3170 &sensor_dev_template_pwm_target_temp,
3171 &sensor_dev_template_fan_target,
3172 &sensor_dev_template_fan_tolerance,
3173 &sensor_dev_template_pwm_stop_time,
3174 &sensor_dev_template_pwm_step_up_time,
3175 &sensor_dev_template_pwm_step_down_time,
3176 &sensor_dev_template_pwm_start,
3177 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003178 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003179 &sensor_dev_template_pwm_weight_temp_step,
3180 &sensor_dev_template_pwm_weight_temp_step_tol,
3181 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003182 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003183 &sensor_dev_template_pwm_max, /* 19 */
3184 &sensor_dev_template_pwm_step, /* 20 */
3185 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3186 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3187 &sensor_dev_template_pwm_auto_point1_temp,
3188 &sensor_dev_template_pwm_auto_point2_pwm,
3189 &sensor_dev_template_pwm_auto_point2_temp,
3190 &sensor_dev_template_pwm_auto_point3_pwm,
3191 &sensor_dev_template_pwm_auto_point3_temp,
3192 &sensor_dev_template_pwm_auto_point4_pwm,
3193 &sensor_dev_template_pwm_auto_point4_temp,
3194 &sensor_dev_template_pwm_auto_point5_pwm,
3195 &sensor_dev_template_pwm_auto_point5_temp,
3196 &sensor_dev_template_pwm_auto_point6_pwm,
3197 &sensor_dev_template_pwm_auto_point6_temp,
3198 &sensor_dev_template_pwm_auto_point7_pwm,
3199 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003200
Guenter Roeckf73cf632013-03-18 09:22:50 -07003201 NULL
3202};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003203
Julia Lawallc60fdf82015-12-12 17:36:39 +01003204static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003205 .templates = nct6775_attributes_pwm_template,
3206 .is_visible = nct6775_pwm_is_visible,
3207 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003208};
3209
3210static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003211cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003212{
3213 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003214
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003215 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3216}
3217
Julia Lawall93d72ac2016-12-22 13:05:23 +01003218static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003219
Guenter Roecka6bd5872012-12-04 03:13:34 -08003220/* Case open detection */
3221
3222static ssize_t
3223clear_caseopen(struct device *dev, struct device_attribute *attr,
3224 const char *buf, size_t count)
3225{
3226 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003227 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3228 unsigned long val;
3229 u8 reg;
3230 int ret;
3231
3232 if (kstrtoul(buf, 10, &val) || val != 0)
3233 return -EINVAL;
3234
3235 mutex_lock(&data->update_lock);
3236
3237 /*
3238 * Use CR registers to clear caseopen status.
3239 * The CR registers are the same for all chips, and not all chips
3240 * support clearing the caseopen status through "regular" registers.
3241 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003242 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003243 if (ret) {
3244 count = ret;
3245 goto error;
3246 }
3247
Guenter Roeckdf612d52013-07-08 13:15:04 -07003248 superio_select(data->sioreg, NCT6775_LD_ACPI);
3249 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003250 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003251 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003252 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003253 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3254 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003255
3256 data->valid = false; /* Force cache refresh */
3257error:
3258 mutex_unlock(&data->update_lock);
3259 return count;
3260}
3261
Guenter Roeckf73cf632013-03-18 09:22:50 -07003262static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3263 clear_caseopen, INTRUSION_ALARM_BASE);
3264static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3265 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003266static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3267 store_beep, INTRUSION_ALARM_BASE);
3268static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3269 store_beep, INTRUSION_ALARM_BASE + 1);
3270static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3271 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003272
3273static umode_t nct6775_other_is_visible(struct kobject *kobj,
3274 struct attribute *attr, int index)
3275{
3276 struct device *dev = container_of(kobj, struct device, kobj);
3277 struct nct6775_data *data = dev_get_drvdata(dev);
3278
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003279 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003280 return 0;
3281
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003282 if (index == 1 || index == 2) {
3283 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003284 return 0;
3285 }
3286
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003287 if (index == 3 || index == 4) {
3288 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003289 return 0;
3290 }
3291
Guenter Roeckf73cf632013-03-18 09:22:50 -07003292 return attr->mode;
3293}
3294
3295/*
3296 * nct6775_other_is_visible uses the index into the following array
3297 * to determine if attributes should be created or not.
3298 * Any change in order or content must be matched.
3299 */
3300static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003301 &dev_attr_cpu0_vid.attr, /* 0 */
3302 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3303 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3304 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3305 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3306 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003307
3308 NULL
3309};
3310
3311static const struct attribute_group nct6775_group_other = {
3312 .attrs = nct6775_attributes_other,
3313 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003314};
3315
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003316static inline void nct6775_init_device(struct nct6775_data *data)
3317{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003318 int i;
3319 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003320
3321 /* Start monitoring if needed */
3322 if (data->REG_CONFIG) {
3323 tmp = nct6775_read_value(data, data->REG_CONFIG);
3324 if (!(tmp & 0x01))
3325 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3326 }
3327
Guenter Roeckaa136e52012-12-04 03:26:05 -08003328 /* Enable temperature sensors if needed */
3329 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003330 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003331 continue;
3332 if (!data->reg_temp_config[i])
3333 continue;
3334 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3335 if (tmp & 0x01)
3336 nct6775_write_value(data, data->reg_temp_config[i],
3337 tmp & 0xfe);
3338 }
3339
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003340 /* Enable VBAT monitoring if needed */
3341 tmp = nct6775_read_value(data, data->REG_VBAT);
3342 if (!(tmp & 0x01))
3343 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003344
3345 diode = nct6775_read_value(data, data->REG_DIODE);
3346
3347 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003348 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003349 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003350 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3351 data->temp_type[i]
3352 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003353 else /* thermistor */
3354 data->temp_type[i] = 4;
3355 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003356}
3357
Guenter Roeckf73cf632013-03-18 09:22:50 -07003358static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003359nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003360{
David Bartley578ab5f2013-06-24 22:28:28 -07003361 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3362 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003363 int sioreg = data->sioreg;
3364 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003365
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003366 /* Store SIO_REG_ENABLE for use during resume */
3367 superio_select(sioreg, NCT6775_LD_HWM);
3368 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3369
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003370 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3371 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003372 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003373
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003374 fan3pin = regval & BIT(6);
3375 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003376
3377 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003378 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003379 fan4min = false;
3380 fan5pin = false;
3381 fan6pin = false;
3382 pwm4pin = false;
3383 pwm5pin = false;
3384 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003385 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003386 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003387 const char *board_vendor, *board_name;
3388
3389 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3390 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3391
3392 if (board_name && board_vendor &&
3393 !strcmp(board_vendor, "ASRock")) {
3394 /*
3395 * Auxiliary fan monitoring is not enabled on ASRock
3396 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3397 * Observed with BIOS version 2.00.
3398 */
3399 if (!strcmp(board_name, "Z77 Pro4-M")) {
3400 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3401 data->sio_reg_enable |= 0xe0;
3402 superio_outb(sioreg, SIO_REG_ENABLE,
3403 data->sio_reg_enable);
3404 }
3405 }
3406 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003407
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003408 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003409 fan3pin = gpok;
3410 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003411 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003412
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003413 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003414 fan4pin = gpok;
3415 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003416 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003417
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003418 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003419 fan5pin = gpok;
3420 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003421 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003422
3423 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003424 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003425 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003426 pwm4pin = false;
3427 pwm5pin = false;
3428 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003429 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003430 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003431 fan3pin = !(regval & 0x80);
3432 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003433
3434 fan4pin = false;
3435 fan4min = false;
3436 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003437 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003438 pwm4pin = false;
3439 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003440 pwm6pin = false;
Guenter Roeck419220d2017-05-17 18:19:18 -07003441 } else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, or NCT6795D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003442 int regval_1b, regval_2a, regval_eb;
3443
Guenter Roeckdf612d52013-07-08 13:15:04 -07003444 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003445
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003446 fan3pin = !(regval & BIT(5));
3447 fan4pin = !(regval & BIT(6));
3448 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003449
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003450 pwm3pin = !(regval & BIT(0));
3451 pwm4pin = !(regval & BIT(1));
3452 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003453
Guenter Roecke5c85222017-05-17 18:09:41 -07003454 regval = superio_inb(sioreg, 0x2d);
3455 switch (data->kind) {
3456 case nct6791:
3457 case nct6792:
3458 fan6pin = regval & BIT(1);
3459 pwm6pin = regval & BIT(0);
3460 break;
3461 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003462 case nct6795:
Guenter Roecke5c85222017-05-17 18:09:41 -07003463 regval_1b = superio_inb(sioreg, 0x1b);
3464 regval_2a = superio_inb(sioreg, 0x2a);
David Bartley578ab5f2013-06-24 22:28:28 -07003465
Guenter Roecke5c85222017-05-17 18:09:41 -07003466 if (!pwm5pin)
3467 pwm5pin = regval & BIT(7);
3468 fan6pin = regval & BIT(1);
3469 pwm6pin = regval & BIT(0);
3470 if (!fan5pin)
3471 fan5pin = regval_1b & BIT(5);
3472
3473 superio_select(sioreg, NCT6775_LD_12);
3474 regval_eb = superio_inb(sioreg, 0xeb);
3475 if (!fan5pin)
3476 fan5pin = regval_eb & BIT(5);
3477 if (!pwm5pin)
3478 pwm5pin = (regval_eb & BIT(4)) &&
3479 !(regval_2a & BIT(0));
3480 if (!fan6pin)
3481 fan6pin = regval_eb & BIT(3);
3482 if (!pwm6pin)
3483 pwm6pin = regval_eb & BIT(2);
3484 break;
3485 default: /* NCT6779D */
David Bartley578ab5f2013-06-24 22:28:28 -07003486 fan6pin = false;
3487 pwm6pin = false;
Guenter Roecke5c85222017-05-17 18:09:41 -07003488 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003489 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003490
3491 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003492 }
3493
David Bartley578ab5f2013-06-24 22:28:28 -07003494 /* fan 1 and 2 (0x03) are always present */
3495 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3496 (fan5pin << 4) | (fan6pin << 5);
3497 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3498 (fan5pin << 4);
3499 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3500 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003501}
3502
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003503static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3504 int *available, int *mask)
3505{
3506 int i;
3507 u8 src;
3508
3509 for (i = 0; i < data->pwm_num && *available; i++) {
3510 int index;
3511
3512 if (!regp[i])
3513 continue;
3514 src = nct6775_read_value(data, regp[i]);
3515 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003516 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003517 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003518 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003519 continue;
3520
3521 index = __ffs(*available);
3522 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003523 *available &= ~BIT(index);
3524 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003525 }
3526}
3527
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003528static int nct6775_probe(struct platform_device *pdev)
3529{
3530 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003531 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003532 struct nct6775_data *data;
3533 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003534 int i, s, err = 0;
3535 int src, mask, available;
3536 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003537 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003538 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003539 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003540 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003541 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003542 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003543 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003544
3545 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3546 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3547 DRVNAME))
3548 return -EBUSY;
3549
3550 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3551 GFP_KERNEL);
3552 if (!data)
3553 return -ENOMEM;
3554
3555 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003556 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003557 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003558 mutex_init(&data->update_lock);
3559 data->name = nct6775_device_names[data->kind];
3560 data->bank = 0xff; /* Force initial bank selection */
3561 platform_set_drvdata(pdev, data);
3562
3563 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003564 case nct6106:
3565 data->in_num = 9;
3566 data->pwm_num = 3;
3567 data->auto_pwm_num = 4;
3568 data->temp_fixed_num = 3;
3569 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003570 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003571
3572 data->fan_from_reg = fan_from_reg13;
3573 data->fan_from_reg_min = fan_from_reg13;
3574
3575 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003576 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003577
3578 data->REG_VBAT = NCT6106_REG_VBAT;
3579 data->REG_DIODE = NCT6106_REG_DIODE;
3580 data->DIODE_MASK = NCT6106_DIODE_MASK;
3581 data->REG_VIN = NCT6106_REG_IN;
3582 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3583 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3584 data->REG_TARGET = NCT6106_REG_TARGET;
3585 data->REG_FAN = NCT6106_REG_FAN;
3586 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3587 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3588 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3589 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3590 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3591 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3592 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3593 data->REG_PWM[0] = NCT6106_REG_PWM;
3594 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3595 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3596 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3597 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3598 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3599 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3600 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3601 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3602 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3603 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3604 data->REG_CRITICAL_TEMP_TOLERANCE
3605 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3606 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3607 data->CRITICAL_PWM_ENABLE_MASK
3608 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3609 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3610 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3611 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3612 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3613 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3614 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3615 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3616 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3617 data->REG_ALARM = NCT6106_REG_ALARM;
3618 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003619 data->REG_BEEP = NCT6106_REG_BEEP;
3620 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003621
3622 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003623 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003624 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003625 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003626 reg_temp_over = NCT6106_REG_TEMP_OVER;
3627 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3628 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3629 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3630 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003631 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3632 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003633
3634 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003635 case nct6775:
3636 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003637 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003638 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003639 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003640 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003641 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003642 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003643
3644 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003645 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003646
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003647 data->fan_from_reg = fan_from_reg16;
3648 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003649 data->target_temp_mask = 0x7f;
3650 data->tolerance_mask = 0x0f;
3651 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003652
Guenter Roeckaa136e52012-12-04 03:26:05 -08003653 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003654 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003655
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003656 data->REG_CONFIG = NCT6775_REG_CONFIG;
3657 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003658 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003659 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003660 data->REG_VIN = NCT6775_REG_IN;
3661 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3662 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003663 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003664 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003665 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003666 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003667 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003668 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003669 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3670 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3671 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003672 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003673 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3674 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3675 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3676 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003677 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003678 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3679 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3680 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003681 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3682 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3683 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3684 data->REG_CRITICAL_TEMP_TOLERANCE
3685 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003686 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3687 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003688 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003689 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3690 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3691 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3692 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003693 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003694 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003695
3696 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003697 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003698 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003699 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003700 reg_temp_over = NCT6775_REG_TEMP_OVER;
3701 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3702 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3703 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3704 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3705
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003706 break;
3707 case nct6776:
3708 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003709 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003710 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003711 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003712 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003713 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003714 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003715
3716 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003717 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003718
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003719 data->fan_from_reg = fan_from_reg13;
3720 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003721 data->target_temp_mask = 0xff;
3722 data->tolerance_mask = 0x07;
3723 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003724
Guenter Roeckaa136e52012-12-04 03:26:05 -08003725 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003726 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003727
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003728 data->REG_CONFIG = NCT6775_REG_CONFIG;
3729 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003730 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003731 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003732 data->REG_VIN = NCT6775_REG_IN;
3733 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3734 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003735 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003736 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003737 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003738 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003739 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003740 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003741 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003742 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3743 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003744 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003745 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003746 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3747 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003748 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3749 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003750 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3751 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3752 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003753 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3754 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3755 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3756 data->REG_CRITICAL_TEMP_TOLERANCE
3757 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003758 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3759 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003760 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003761 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3762 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3763 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3764 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003765 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003766 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003767
3768 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003769 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003770 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003771 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003772 reg_temp_over = NCT6775_REG_TEMP_OVER;
3773 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3774 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3775 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3776 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3777
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003778 break;
3779 case nct6779:
3780 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003781 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003782 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003783 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003784 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003785 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003786 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003787
3788 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003789 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003790
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003791 data->fan_from_reg = fan_from_reg13;
3792 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003793 data->target_temp_mask = 0xff;
3794 data->tolerance_mask = 0x07;
3795 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003796
Guenter Roeckaa136e52012-12-04 03:26:05 -08003797 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003798 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003799
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003800 data->REG_CONFIG = NCT6775_REG_CONFIG;
3801 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003802 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003803 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003804 data->REG_VIN = NCT6779_REG_IN;
3805 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3806 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003807 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003808 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003809 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003810 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003811 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003812 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003813 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003814 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3815 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003816 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003817 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003818 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3819 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003820 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3821 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003822 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3823 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3824 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003825 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3826 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3827 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3828 data->REG_CRITICAL_TEMP_TOLERANCE
3829 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003830 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3831 data->CRITICAL_PWM_ENABLE_MASK
3832 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3833 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003834 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3835 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003836 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003837 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3838 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3839 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3840 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003841 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003842 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003843
3844 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003845 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003846 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003847 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003848 reg_temp_over = NCT6779_REG_TEMP_OVER;
3849 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3850 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3851 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3852 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3853
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003854 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003855 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003856 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003857 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003858 case nct6795:
David Bartley578ab5f2013-06-24 22:28:28 -07003859 data->in_num = 15;
3860 data->pwm_num = 6;
3861 data->auto_pwm_num = 4;
3862 data->has_fan_div = false;
3863 data->temp_fixed_num = 6;
3864 data->num_temp_alarms = 2;
3865 data->num_temp_beeps = 2;
3866
3867 data->ALARM_BITS = NCT6791_ALARM_BITS;
3868 data->BEEP_BITS = NCT6779_BEEP_BITS;
3869
3870 data->fan_from_reg = fan_from_reg13;
3871 data->fan_from_reg_min = fan_from_reg13;
3872 data->target_temp_mask = 0xff;
3873 data->tolerance_mask = 0x07;
3874 data->speed_tolerance_limit = 63;
3875
Guenter Roeck50224f42015-10-30 07:52:39 -07003876 switch (data->kind) {
3877 default:
3878 case nct6791:
3879 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003880 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003881 break;
3882 case nct6792:
3883 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003884 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003885 break;
3886 case nct6793:
3887 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003888 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003889 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003890 case nct6795:
3891 data->temp_label = nct6795_temp_label;
3892 data->temp_mask = NCT6795_TEMP_MASK;
3893 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07003894 }
David Bartley578ab5f2013-06-24 22:28:28 -07003895
3896 data->REG_CONFIG = NCT6775_REG_CONFIG;
3897 data->REG_VBAT = NCT6775_REG_VBAT;
3898 data->REG_DIODE = NCT6775_REG_DIODE;
3899 data->DIODE_MASK = NCT6775_DIODE_MASK;
3900 data->REG_VIN = NCT6779_REG_IN;
3901 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3902 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3903 data->REG_TARGET = NCT6775_REG_TARGET;
3904 data->REG_FAN = NCT6779_REG_FAN;
3905 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3906 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3907 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3908 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3909 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003910 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3911 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003912 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3913 data->REG_PWM[0] = NCT6775_REG_PWM;
3914 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3915 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003916 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3917 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003918 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3919 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3920 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3921 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3922 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3923 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3924 data->REG_CRITICAL_TEMP_TOLERANCE
3925 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3926 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3927 data->CRITICAL_PWM_ENABLE_MASK
3928 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3929 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3930 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3931 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3932 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003933 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3934 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3935 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3936 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003937 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003938 if (data->kind == nct6791)
3939 data->REG_BEEP = NCT6776_REG_BEEP;
3940 else
3941 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003942
3943 reg_temp = NCT6779_REG_TEMP;
3944 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003945 if (data->kind == nct6791) {
3946 reg_temp_mon = NCT6779_REG_TEMP_MON;
3947 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3948 } else {
3949 reg_temp_mon = NCT6792_REG_TEMP_MON;
3950 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3951 }
David Bartley578ab5f2013-06-24 22:28:28 -07003952 reg_temp_over = NCT6779_REG_TEMP_OVER;
3953 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3954 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3955 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3956 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3957
3958 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003959 default:
3960 return -ENODEV;
3961 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003962 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003963 data->have_temp = 0;
3964
3965 /*
3966 * On some boards, not all available temperature sources are monitored,
3967 * even though some of the monitoring registers are unused.
3968 * Get list of unused monitoring registers, then detect if any fan
3969 * controls are configured to use unmonitored temperature sources.
3970 * If so, assign the unmonitored temperature sources to available
3971 * monitoring registers.
3972 */
3973 mask = 0;
3974 available = 0;
3975 for (i = 0; i < num_reg_temp; i++) {
3976 if (reg_temp[i] == 0)
3977 continue;
3978
3979 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003980 if (!src || (mask & BIT(src)))
3981 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003982
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003983 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003984 }
3985
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003986 /*
3987 * Now find unmonitored temperature registers and enable monitoring
3988 * if additional monitoring registers are available.
3989 */
3990 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3991 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3992
Guenter Roeckaa136e52012-12-04 03:26:05 -08003993 mask = 0;
3994 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3995 for (i = 0; i < num_reg_temp; i++) {
3996 if (reg_temp[i] == 0)
3997 continue;
3998
3999 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004000 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004001 continue;
4002
Guenter Roeckcc66b302017-05-17 18:05:06 -07004003 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004004 dev_info(dev,
4005 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4006 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4007 continue;
4008 }
4009
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004010 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004011
4012 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4013 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004014 data->have_temp |= BIT(src - 1);
4015 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004016 data->reg_temp[0][src - 1] = reg_temp[i];
4017 data->reg_temp[1][src - 1] = reg_temp_over[i];
4018 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004019 if (reg_temp_crit_h && reg_temp_crit_h[i])
4020 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4021 else if (reg_temp_crit[src - 1])
4022 data->reg_temp[3][src - 1]
4023 = reg_temp_crit[src - 1];
4024 if (reg_temp_crit_l && reg_temp_crit_l[i])
4025 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004026 data->reg_temp_config[src - 1] = reg_temp_config[i];
4027 data->temp_src[src - 1] = src;
4028 continue;
4029 }
4030
4031 if (s >= NUM_TEMP)
4032 continue;
4033
4034 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004035 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004036 data->reg_temp[0][s] = reg_temp[i];
4037 data->reg_temp[1][s] = reg_temp_over[i];
4038 data->reg_temp[2][s] = reg_temp_hyst[i];
4039 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004040 if (reg_temp_crit_h && reg_temp_crit_h[i])
4041 data->reg_temp[3][s] = reg_temp_crit_h[i];
4042 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004043 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004044 if (reg_temp_crit_l && reg_temp_crit_l[i])
4045 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004046
4047 data->temp_src[s] = src;
4048 s++;
4049 }
4050
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004051 /*
4052 * Repeat with temperatures used for fan control.
4053 * This set of registers does not support limits.
4054 */
4055 for (i = 0; i < num_reg_temp_mon; i++) {
4056 if (reg_temp_mon[i] == 0)
4057 continue;
4058
4059 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004060 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004061 continue;
4062
Guenter Roeckcc66b302017-05-17 18:05:06 -07004063 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004064 dev_info(dev,
4065 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4066 src, i, data->REG_TEMP_SEL[i],
4067 reg_temp_mon[i]);
4068 continue;
4069 }
4070
Guenter Roeck7ce41902016-09-11 12:42:52 -07004071 /*
4072 * For virtual temperature sources, the 'virtual' temperature
4073 * for each fan reflects a different temperature, and there
4074 * are no duplicates.
4075 */
4076 if (src != TEMP_SOURCE_VIRTUAL) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004077 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004078 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004079 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004080 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004081
4082 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4083 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004084 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004085 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004086 data->have_temp |= BIT(src - 1);
4087 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004088 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4089 data->temp_src[src - 1] = src;
4090 continue;
4091 }
4092
4093 if (s >= NUM_TEMP)
4094 continue;
4095
4096 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004097 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004098 data->reg_temp[0][s] = reg_temp_mon[i];
4099 data->temp_src[s] = src;
4100 s++;
4101 }
4102
Guenter Roeckaa136e52012-12-04 03:26:05 -08004103#ifdef USE_ALTERNATE
4104 /*
4105 * Go through the list of alternate temp registers and enable
4106 * if possible.
4107 * The temperature is already monitored if the respective bit in <mask>
4108 * is set.
4109 */
Guenter Roeckcc66b302017-05-17 18:05:06 -07004110 for (i = 0; i < 32; i++) {
4111 if (!(data->temp_mask & BIT(i + 1)))
4112 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004113 if (!reg_temp_alternate[i])
4114 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004115 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004116 continue;
4117 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004118 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004119 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004120 data->have_temp |= BIT(i);
4121 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004122 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07004123 if (i < num_reg_temp) {
4124 data->reg_temp[1][i] = reg_temp_over[i];
4125 data->reg_temp[2][i] = reg_temp_hyst[i];
4126 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004127 data->temp_src[i] = i + 1;
4128 continue;
4129 }
4130
4131 if (s >= NUM_TEMP) /* Abort if no more space */
4132 break;
4133
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004134 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004135 data->reg_temp[0][s] = reg_temp_alternate[i];
4136 data->temp_src[s] = i + 1;
4137 s++;
4138 }
4139#endif /* USE_ALTERNATE */
4140
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004141 /* Initialize the chip */
4142 nct6775_init_device(data);
4143
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004144 err = superio_enter(sio_data->sioreg);
4145 if (err)
4146 return err;
4147
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004148 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4149 switch (data->kind) {
4150 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004151 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004152 break;
4153 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004154 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004155 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004156 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004157 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004158 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004159 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004160 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004161 case nct6795:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004162 break;
4163 }
4164
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004165 /*
4166 * Read VID value
4167 * We can get the VID input values directly at logical device D 0xe3.
4168 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004169 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004170 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4171 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4172 data->vrm = vid_which_vrm();
4173 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004174
4175 if (fan_debounce) {
4176 u8 tmp;
4177
4178 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4179 tmp = superio_inb(sio_data->sioreg,
4180 NCT6775_REG_CR_FAN_DEBOUNCE);
4181 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004182 case nct6106:
4183 tmp |= 0xe0;
4184 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004185 case nct6775:
4186 tmp |= 0x1e;
4187 break;
4188 case nct6776:
4189 case nct6779:
4190 tmp |= 0x3e;
4191 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004192 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004193 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004194 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004195 case nct6795:
David Bartley578ab5f2013-06-24 22:28:28 -07004196 tmp |= 0x7e;
4197 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004198 }
4199 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4200 tmp);
4201 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4202 data->name);
4203 }
4204
Guenter Roeckdf612d52013-07-08 13:15:04 -07004205 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004206
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004207 superio_exit(sio_data->sioreg);
4208
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004209 /* Read fan clock dividers immediately */
4210 nct6775_init_fan_common(dev, data);
4211
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004212 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004213 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4214 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004215 if (IS_ERR(group))
4216 return PTR_ERR(group);
4217
Axel Lin55bdee62014-07-24 08:59:34 +08004218 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004219
Guenter Roeckf73cf632013-03-18 09:22:50 -07004220 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4221 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004222 if (IS_ERR(group))
4223 return PTR_ERR(group);
4224
Axel Lin55bdee62014-07-24 08:59:34 +08004225 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004226
Guenter Roeckf73cf632013-03-18 09:22:50 -07004227 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4228 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004229 if (IS_ERR(group))
4230 return PTR_ERR(group);
4231
Axel Lin55bdee62014-07-24 08:59:34 +08004232 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004233
Guenter Roeckf73cf632013-03-18 09:22:50 -07004234 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4235 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004236 if (IS_ERR(group))
4237 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004238
Axel Lin55bdee62014-07-24 08:59:34 +08004239 data->groups[num_attr_groups++] = group;
4240 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004241
Guenter Roecka150d952013-07-11 22:55:22 -07004242 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4243 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004244 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004245}
4246
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004247static void nct6791_enable_io_mapping(int sioaddr)
4248{
4249 int val;
4250
4251 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4252 if (val & 0x10) {
4253 pr_info("Enabling hardware monitor logical device mappings.\n");
4254 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4255 val & ~0x10);
4256 }
4257}
4258
Guenter Roeck48e93182015-02-07 08:48:49 -08004259static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004260{
4261 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004262
4263 mutex_lock(&data->update_lock);
4264 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004265 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004266 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4267 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4268 }
4269 mutex_unlock(&data->update_lock);
4270
4271 return 0;
4272}
4273
Guenter Roeck48e93182015-02-07 08:48:49 -08004274static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004275{
4276 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004277 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004278 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004279 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004280
4281 mutex_lock(&data->update_lock);
4282 data->bank = 0xff; /* Force initial bank selection */
4283
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004284 err = superio_enter(sioreg);
4285 if (err)
4286 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004287
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004288 superio_select(sioreg, NCT6775_LD_HWM);
4289 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4290 if (reg != data->sio_reg_enable)
4291 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4292
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004293 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck419220d2017-05-17 18:19:18 -07004294 data->kind == nct6793 || data->kind == nct6795)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004295 nct6791_enable_io_mapping(sioreg);
4296
4297 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004298
Guenter Roeck84d19d92012-12-04 08:01:39 -08004299 /* Restore limits */
4300 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004301 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004302 continue;
4303
4304 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4305 data->in[i][1]);
4306 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4307 data->in[i][2]);
4308 }
4309
Guenter Roeckc409fd42013-04-09 05:04:00 -07004310 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004311 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004312 continue;
4313
4314 nct6775_write_value(data, data->REG_FAN_MIN[i],
4315 data->fan_min[i]);
4316 }
4317
4318 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004319 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004320 continue;
4321
Guenter Roeckc409fd42013-04-09 05:04:00 -07004322 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004323 if (data->reg_temp[j][i])
4324 nct6775_write_temp(data, data->reg_temp[j][i],
4325 data->temp[j][i]);
4326 }
4327
4328 /* Restore other settings */
4329 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004330 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004331 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4332 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4333 }
4334
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004335abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004336 /* Force re-reading all values */
4337 data->valid = false;
4338 mutex_unlock(&data->update_lock);
4339
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004340 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004341}
4342
Guenter Roeck48e93182015-02-07 08:48:49 -08004343static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004344
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004345static struct platform_driver nct6775_driver = {
4346 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004347 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004348 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004349 },
4350 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004351};
4352
4353/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004354static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004355{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004356 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004357 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004358 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004359
4360 err = superio_enter(sioaddr);
4361 if (err)
4362 return err;
4363
Guenter Roeckfc72af32016-08-03 22:07:18 -07004364 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4365 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4366 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004367 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004368
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004369 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004370 case SIO_NCT6106_ID:
4371 sio_data->kind = nct6106;
4372 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004373 case SIO_NCT6775_ID:
4374 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004375 break;
4376 case SIO_NCT6776_ID:
4377 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004378 break;
4379 case SIO_NCT6779_ID:
4380 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004381 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004382 case SIO_NCT6791_ID:
4383 sio_data->kind = nct6791;
4384 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004385 case SIO_NCT6792_ID:
4386 sio_data->kind = nct6792;
4387 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004388 case SIO_NCT6793_ID:
4389 sio_data->kind = nct6793;
4390 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004391 case SIO_NCT6795_ID:
4392 sio_data->kind = nct6795;
4393 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004394 default:
4395 if (val != 0xffff)
4396 pr_debug("unsupported chip ID: 0x%04x\n", val);
4397 superio_exit(sioaddr);
4398 return -ENODEV;
4399 }
4400
4401 /* We have a known chip, find the HWM I/O address */
4402 superio_select(sioaddr, NCT6775_LD_HWM);
4403 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4404 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004405 addr = val & IOREGION_ALIGNMENT;
4406 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004407 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4408 superio_exit(sioaddr);
4409 return -ENODEV;
4410 }
4411
4412 /* Activate logical device if needed */
4413 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4414 if (!(val & 0x01)) {
4415 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4416 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4417 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004418
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004419 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck419220d2017-05-17 18:19:18 -07004420 sio_data->kind == nct6793 || sio_data->kind == nct6795)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004421 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004422
4423 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004424 pr_info("Found %s or compatible chip at %#x:%#x\n",
4425 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004426 sio_data->sioreg = sioaddr;
4427
Guenter Roeck698a7c22013-04-05 07:35:25 -07004428 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004429}
4430
4431/*
4432 * when Super-I/O functions move to a separate file, the Super-I/O
4433 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004434 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004435 * must keep track of the device
4436 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004437static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004438
4439static int __init sensors_nct6775_init(void)
4440{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004441 int i, err;
4442 bool found = false;
4443 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004444 struct resource res;
4445 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004446 int sioaddr[2] = { 0x2e, 0x4e };
4447
4448 err = platform_driver_register(&nct6775_driver);
4449 if (err)
4450 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004451
4452 /*
4453 * initialize sio_data->kind and sio_data->sioreg.
4454 *
4455 * when Super-I/O functions move to a separate file, the Super-I/O
4456 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4457 * nct6775 hardware monitor, and call probe()
4458 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004459 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4460 address = nct6775_find(sioaddr[i], &sio_data);
4461 if (address <= 0)
4462 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004463
Guenter Roeck698a7c22013-04-05 07:35:25 -07004464 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004465
Guenter Roeck698a7c22013-04-05 07:35:25 -07004466 pdev[i] = platform_device_alloc(DRVNAME, address);
4467 if (!pdev[i]) {
4468 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004469 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004470 }
4471
4472 err = platform_device_add_data(pdev[i], &sio_data,
4473 sizeof(struct nct6775_sio_data));
4474 if (err)
4475 goto exit_device_put;
4476
4477 memset(&res, 0, sizeof(res));
4478 res.name = DRVNAME;
4479 res.start = address + IOREGION_OFFSET;
4480 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4481 res.flags = IORESOURCE_IO;
4482
4483 err = acpi_check_resource_conflict(&res);
4484 if (err) {
4485 platform_device_put(pdev[i]);
4486 pdev[i] = NULL;
4487 continue;
4488 }
4489
4490 err = platform_device_add_resources(pdev[i], &res, 1);
4491 if (err)
4492 goto exit_device_put;
4493
4494 /* platform_device_add calls probe() */
4495 err = platform_device_add(pdev[i]);
4496 if (err)
4497 goto exit_device_put;
4498 }
4499 if (!found) {
4500 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004501 goto exit_unregister;
4502 }
4503
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004504 return 0;
4505
4506exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004507 platform_device_put(pdev[i]);
4508exit_device_unregister:
4509 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004510 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004511 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004512 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004513exit_unregister:
4514 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004515 return err;
4516}
4517
4518static void __exit sensors_nct6775_exit(void)
4519{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004520 int i;
4521
4522 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4523 if (pdev[i])
4524 platform_device_unregister(pdev[i]);
4525 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004526 platform_driver_unregister(&nct6775_driver);
4527}
4528
4529MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004530MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004531MODULE_LICENSE("GPL");
4532
4533module_init(sensors_nct6775_init);
4534module_exit(sensors_nct6775_exit);