blob: 006f090c1b0a73b25dd7c13297ffa153cb19baf1 [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 Roeck9de2e2e2012-05-20 19:29:48 -070043 *
44 * #temp lists the number of monitored temperature sources (first value) plus
45 * the number of directly connectable temperature sensors (second value).
46 */
47
48#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
50#include <linux/module.h>
51#include <linux/init.h>
52#include <linux/slab.h>
53#include <linux/jiffies.h>
54#include <linux/platform_device.h>
55#include <linux/hwmon.h>
56#include <linux/hwmon-sysfs.h>
57#include <linux/hwmon-vid.h>
58#include <linux/err.h>
59#include <linux/mutex.h>
60#include <linux/acpi.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080061#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070062#include <linux/io.h>
63#include "lm75.h"
64
Guenter Roeckaa136e52012-12-04 03:26:05 -080065#define USE_ALTERNATE
66
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070067enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070068
69/* used to set data->name = nct6775_device_names[data->sio_kind] */
70static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070071 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070072 "nct6775",
73 "nct6776",
74 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070075 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080076 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070077 "nct6793",
78};
79
80static const char * const nct6775_sio_names[] __initconst = {
81 "NCT6106D",
82 "NCT6775F",
83 "NCT6776D/F",
84 "NCT6779D",
85 "NCT6791D",
86 "NCT6792D",
87 "NCT6793D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070088};
89
90static unsigned short force_id;
91module_param(force_id, ushort, 0);
92MODULE_PARM_DESC(force_id, "Override the detected device ID");
93
Guenter Roeck47ece962012-12-04 07:59:32 -080094static unsigned short fan_debounce;
95module_param(fan_debounce, ushort, 0);
96MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
97
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070098#define DRVNAME "nct6775"
99
100/*
101 * Super-I/O constants and functions
102 */
103
Guenter Roecka6bd5872012-12-04 03:13:34 -0800104#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700105#define NCT6775_LD_HWM 0x0b
106#define NCT6775_LD_VID 0x0d
107
108#define SIO_REG_LDSEL 0x07 /* Logical device select */
109#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
110#define SIO_REG_ENABLE 0x30 /* Logical device enable */
111#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
112
Guenter Roeck6c009502012-07-01 08:23:15 -0700113#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114#define SIO_NCT6775_ID 0xb470
115#define SIO_NCT6776_ID 0xc330
116#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700117#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800118#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700119#define SIO_NCT6793_ID 0xd120
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700120#define SIO_ID_MASK 0xFFF0
121
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800122enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
123
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700124static inline void
125superio_outb(int ioreg, int reg, int val)
126{
127 outb(reg, ioreg);
128 outb(val, ioreg + 1);
129}
130
131static inline int
132superio_inb(int ioreg, int reg)
133{
134 outb(reg, ioreg);
135 return inb(ioreg + 1);
136}
137
138static inline void
139superio_select(int ioreg, int ld)
140{
141 outb(SIO_REG_LDSEL, ioreg);
142 outb(ld, ioreg + 1);
143}
144
145static inline int
146superio_enter(int ioreg)
147{
148 /*
149 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
150 */
151 if (!request_muxed_region(ioreg, 2, DRVNAME))
152 return -EBUSY;
153
154 outb(0x87, ioreg);
155 outb(0x87, ioreg);
156
157 return 0;
158}
159
160static inline void
161superio_exit(int ioreg)
162{
163 outb(0xaa, ioreg);
164 outb(0x02, ioreg);
165 outb(0x02, ioreg + 1);
166 release_region(ioreg, 2);
167}
168
169/*
170 * ISA constants
171 */
172
173#define IOREGION_ALIGNMENT (~7)
174#define IOREGION_OFFSET 5
175#define IOREGION_LENGTH 2
176#define ADDR_REG_OFFSET 0
177#define DATA_REG_OFFSET 1
178
179#define NCT6775_REG_BANK 0x4E
180#define NCT6775_REG_CONFIG 0x40
181
182/*
183 * Not currently used:
184 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
185 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
186 * REG_MAN_ID is at port 0x4f
187 * REG_CHIP_ID is at port 0x58
188 */
189
Guenter Roeckaa136e52012-12-04 03:26:05 -0800190#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
191#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
192
Guenter Roeck6c009502012-07-01 08:23:15 -0700193#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700194#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700195
David Bartley578ab5f2013-06-24 22:28:28 -0700196#define NUM_FAN 6
197
Guenter Roeck7ce41902016-09-11 12:42:52 -0700198#define TEMP_SOURCE_VIRTUAL 0x1f
199
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700200/* Common and NCT6775 specific data */
201
202/* Voltage min/max registers for nr=7..14 are in bank 5 */
203
204static const u16 NCT6775_REG_IN_MAX[] = {
205 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
206 0x55c, 0x55e, 0x560, 0x562 };
207static const u16 NCT6775_REG_IN_MIN[] = {
208 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
209 0x55d, 0x55f, 0x561, 0x563 };
210static const u16 NCT6775_REG_IN[] = {
211 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
212};
213
214#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800215#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700216#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700217
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800218#define NCT6775_REG_FANDIV1 0x506
219#define NCT6775_REG_FANDIV2 0x507
220
Guenter Roeck47ece962012-12-04 07:59:32 -0800221#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
222
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700223static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
224
Guenter Roeck30846992013-06-24 22:21:59 -0700225/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700226
227static const s8 NCT6775_ALARM_BITS[] = {
228 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
229 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
230 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700231 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700232 -1, -1, -1, /* unused */
233 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
234 12, -1 }; /* intrusion0, intrusion1 */
235
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800236#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800237#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800238#define INTRUSION_ALARM_BASE 30
239
Guenter Roeck30846992013-06-24 22:21:59 -0700240static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
241
242/*
243 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
244 * 30..31 intrusion
245 */
246static const s8 NCT6775_BEEP_BITS[] = {
247 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
248 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
249 21, /* global beep enable */
250 6, 7, 11, 28, -1, /* fan1..fan5 */
251 -1, -1, -1, /* unused */
252 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
253 12, -1 }; /* intrusion0, intrusion1 */
254
255#define BEEP_ENABLE_BASE 15
256
Guenter Roecka6bd5872012-12-04 03:13:34 -0800257static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
258static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
259
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800260/* DC or PWM output fan configuration */
261static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
262static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
263
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800264/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800265
David Bartley578ab5f2013-06-24 22:28:28 -0700266static const u16 NCT6775_REG_TARGET[] = {
267 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
268static const u16 NCT6775_REG_FAN_MODE[] = {
269 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800270static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700271 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800272static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700273 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800274static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700275 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
276static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
277 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800278static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
279static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
280
281static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700282 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
283static const u16 NCT6775_REG_PWM[] = {
284 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
285static const u16 NCT6775_REG_PWM_READ[] = {
286 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800287
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800288static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
289static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800290static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700291static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800292
Guenter Roeckaa136e52012-12-04 03:26:05 -0800293static const u16 NCT6775_REG_TEMP[] = {
294 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
295
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800296static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
297
Guenter Roeckaa136e52012-12-04 03:26:05 -0800298static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
299 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
300static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
301 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
302static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
303 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
304
305static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
306 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
307
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800308static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700309 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800310
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800311static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700312 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800313static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700314 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800315static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700316 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800317static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700318 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800319static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700320 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800321
Guenter Roeckaa136e52012-12-04 03:26:05 -0800322static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
323
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800324static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700325 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800326static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700327 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800328
329#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
330#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
331
332static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
333
334static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700335 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800336static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700337 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800338
Guenter Roeckaa136e52012-12-04 03:26:05 -0800339static const char *const nct6775_temp_label[] = {
340 "",
341 "SYSTIN",
342 "CPUTIN",
343 "AUXTIN",
344 "AMD SB-TSI",
345 "PECI Agent 0",
346 "PECI Agent 1",
347 "PECI Agent 2",
348 "PECI Agent 3",
349 "PECI Agent 4",
350 "PECI Agent 5",
351 "PECI Agent 6",
352 "PECI Agent 7",
353 "PCH_CHIP_CPU_MAX_TEMP",
354 "PCH_CHIP_TEMP",
355 "PCH_CPU_TEMP",
356 "PCH_MCH_TEMP",
357 "PCH_DIM0_TEMP",
358 "PCH_DIM1_TEMP",
359 "PCH_DIM2_TEMP",
360 "PCH_DIM3_TEMP"
361};
362
363static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
364 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
365
366static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
367 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
368 0xa07 };
369
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700370/* NCT6776 specific data */
371
Guenter Roeck728d2942015-08-31 16:13:47 -0700372/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
373#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
374#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
375
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700376static const s8 NCT6776_ALARM_BITS[] = {
377 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
378 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
379 -1, /* unused */
380 6, 7, 11, 10, 23, /* fan1..fan5 */
381 -1, -1, -1, /* unused */
382 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
383 12, 9 }; /* intrusion0, intrusion1 */
384
Guenter Roeck30846992013-06-24 22:21:59 -0700385static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
386
387static const s8 NCT6776_BEEP_BITS[] = {
388 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
389 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
390 24, /* global beep enable */
391 25, 26, 27, 28, 29, /* fan1..fan5 */
392 -1, -1, -1, /* unused */
393 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
394 30, 31 }; /* intrusion0, intrusion1 */
395
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800396static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700397 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800398
David Bartley578ab5f2013-06-24 22:28:28 -0700399static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
400static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800401
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800402static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800403static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800404
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800405static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700406 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800407
Guenter Roeckaa136e52012-12-04 03:26:05 -0800408static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
409 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
410
411static const char *const nct6776_temp_label[] = {
412 "",
413 "SYSTIN",
414 "CPUTIN",
415 "AUXTIN",
416 "SMBUSMASTER 0",
417 "SMBUSMASTER 1",
418 "SMBUSMASTER 2",
419 "SMBUSMASTER 3",
420 "SMBUSMASTER 4",
421 "SMBUSMASTER 5",
422 "SMBUSMASTER 6",
423 "SMBUSMASTER 7",
424 "PECI Agent 0",
425 "PECI Agent 1",
426 "PCH_CHIP_CPU_MAX_TEMP",
427 "PCH_CHIP_TEMP",
428 "PCH_CPU_TEMP",
429 "PCH_MCH_TEMP",
430 "PCH_DIM0_TEMP",
431 "PCH_DIM1_TEMP",
432 "PCH_DIM2_TEMP",
433 "PCH_DIM3_TEMP",
434 "BYTE_TEMP"
435};
436
437static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
438 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
439
440static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
441 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
442
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700443/* NCT6779 specific data */
444
445static const u16 NCT6779_REG_IN[] = {
446 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
447 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
448
449static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
450 0x459, 0x45A, 0x45B, 0x568 };
451
452static const s8 NCT6779_ALARM_BITS[] = {
453 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
454 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
455 -1, /* unused */
456 6, 7, 11, 10, 23, /* fan1..fan5 */
457 -1, -1, -1, /* unused */
458 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
459 12, 9 }; /* intrusion0, intrusion1 */
460
Guenter Roeck30846992013-06-24 22:21:59 -0700461static const s8 NCT6779_BEEP_BITS[] = {
462 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
463 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
464 24, /* global beep enable */
465 25, 26, 27, 28, 29, /* fan1..fan5 */
466 -1, -1, -1, /* unused */
467 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
468 30, 31 }; /* intrusion0, intrusion1 */
469
David Bartley578ab5f2013-06-24 22:28:28 -0700470static const u16 NCT6779_REG_FAN[] = {
471 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800472static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700473 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800474
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800475static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700476 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700477#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800478static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700479 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800480
Guenter Roeckaa136e52012-12-04 03:26:05 -0800481static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800482static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800483static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
484 0x18, 0x152 };
485static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
486 0x3a, 0x153 };
487static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
488 0x39, 0x155 };
489
490static const u16 NCT6779_REG_TEMP_OFFSET[] = {
491 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
492
493static const char *const nct6779_temp_label[] = {
494 "",
495 "SYSTIN",
496 "CPUTIN",
497 "AUXTIN0",
498 "AUXTIN1",
499 "AUXTIN2",
500 "AUXTIN3",
501 "",
502 "SMBUSMASTER 0",
503 "SMBUSMASTER 1",
504 "SMBUSMASTER 2",
505 "SMBUSMASTER 3",
506 "SMBUSMASTER 4",
507 "SMBUSMASTER 5",
508 "SMBUSMASTER 6",
509 "SMBUSMASTER 7",
510 "PECI Agent 0",
511 "PECI Agent 1",
512 "PCH_CHIP_CPU_MAX_TEMP",
513 "PCH_CHIP_TEMP",
514 "PCH_CPU_TEMP",
515 "PCH_MCH_TEMP",
516 "PCH_DIM0_TEMP",
517 "PCH_DIM1_TEMP",
518 "PCH_DIM2_TEMP",
519 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700520 "BYTE_TEMP",
521 "",
522 "",
523 "",
524 "",
525 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800526};
527
Guenter Roeck9a383712015-08-29 15:29:25 -0700528#define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5)
529#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label)
530
531static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800532 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
533 0, 0, 0, 0, 0, 0, 0, 0,
534 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
535 0x408, 0 };
536
Guenter Roeck9a383712015-08-29 15:29:25 -0700537static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800538 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
539
David Bartley578ab5f2013-06-24 22:28:28 -0700540/* NCT6791 specific data */
541
542#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
543
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800544static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
545static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
546static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
547static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
548static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
549static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
550
David Bartley578ab5f2013-06-24 22:28:28 -0700551static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
552 0x459, 0x45A, 0x45B, 0x568, 0x45D };
553
554static const s8 NCT6791_ALARM_BITS[] = {
555 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
556 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
557 -1, /* unused */
558 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
559 -1, -1, /* unused */
560 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
561 12, 9 }; /* intrusion0, intrusion1 */
562
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700563/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800564
565static const u16 NCT6792_REG_TEMP_MON[] = {
566 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
567static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
568 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700569
Guenter Roeck50224f42015-10-30 07:52:39 -0700570static const char *const nct6792_temp_label[] = {
571 "",
572 "SYSTIN",
573 "CPUTIN",
574 "AUXTIN0",
575 "AUXTIN1",
576 "AUXTIN2",
577 "AUXTIN3",
578 "",
579 "SMBUSMASTER 0",
580 "SMBUSMASTER 1",
581 "SMBUSMASTER 2",
582 "SMBUSMASTER 3",
583 "SMBUSMASTER 4",
584 "SMBUSMASTER 5",
585 "SMBUSMASTER 6",
586 "SMBUSMASTER 7",
587 "PECI Agent 0",
588 "PECI Agent 1",
589 "PCH_CHIP_CPU_MAX_TEMP",
590 "PCH_CHIP_TEMP",
591 "PCH_CPU_TEMP",
592 "PCH_MCH_TEMP",
593 "PCH_DIM0_TEMP",
594 "PCH_DIM1_TEMP",
595 "PCH_DIM2_TEMP",
596 "PCH_DIM3_TEMP",
597 "BYTE_TEMP",
598 "PECI Agent 0 Calibration",
599 "PECI Agent 1 Calibration",
600 "",
601 "",
602 "Virtual_TEMP"
603};
604
605static const char *const nct6793_temp_label[] = {
606 "",
607 "SYSTIN",
608 "CPUTIN",
609 "AUXTIN0",
610 "AUXTIN1",
611 "AUXTIN2",
612 "AUXTIN3",
613 "",
614 "SMBUSMASTER 0",
615 "SMBUSMASTER 1",
616 "",
617 "",
618 "",
619 "",
620 "",
621 "",
622 "PECI Agent 0",
623 "PECI Agent 1",
624 "PCH_CHIP_CPU_MAX_TEMP",
625 "PCH_CHIP_TEMP",
626 "PCH_CPU_TEMP",
627 "PCH_MCH_TEMP",
628 "Agent0 Dimm0 ",
629 "Agent0 Dimm1",
630 "Agent1 Dimm0",
631 "Agent1 Dimm1",
632 "BYTE_TEMP0",
633 "BYTE_TEMP1",
634 "PECI Agent 0 Calibration",
635 "PECI Agent 1 Calibration",
636 "",
637 "Virtual_TEMP"
638};
639
Guenter Roeck6c009502012-07-01 08:23:15 -0700640/* NCT6102D/NCT6106D specific data */
641
642#define NCT6106_REG_VBAT 0x318
643#define NCT6106_REG_DIODE 0x319
644#define NCT6106_DIODE_MASK 0x01
645
646static const u16 NCT6106_REG_IN_MAX[] = {
647 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
648static const u16 NCT6106_REG_IN_MIN[] = {
649 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
650static const u16 NCT6106_REG_IN[] = {
651 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
652
653static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800654static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700655static const u16 NCT6106_REG_TEMP_HYST[] = {
656 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
657static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700658 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
659static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
660 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
661static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
662 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700663static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
664static const u16 NCT6106_REG_TEMP_CONFIG[] = {
665 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
666
667static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
668static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
669static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
670static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
671
672static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
673static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
674static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
675static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
676static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
677static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
678static const u16 NCT6106_REG_TEMP_SOURCE[] = {
679 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
680
681static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
682static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
683 0x11b, 0x12b, 0x13b };
684
685static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
686#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
687static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
688
689static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
690static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
691static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
692static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
693static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
694static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
695
696static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
697
698static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
699static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
700static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
Björn Gerhart71faaeb2019-07-15 18:33:55 +0200701static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
Guenter Roeck6c009502012-07-01 08:23:15 -0700702static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
703static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
704
705static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
706static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
707
708static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
709 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
710
711static const s8 NCT6106_ALARM_BITS[] = {
712 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
713 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
714 -1, /* unused */
715 32, 33, 34, -1, -1, /* fan1..fan5 */
716 -1, -1, -1, /* unused */
717 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
718 48, -1 /* intrusion0, intrusion1 */
719};
720
Guenter Roeck30846992013-06-24 22:21:59 -0700721static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
722 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
723
724static const s8 NCT6106_BEEP_BITS[] = {
725 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
726 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
727 32, /* global beep enable */
728 24, 25, 26, 27, 28, /* fan1..fan5 */
729 -1, -1, -1, /* unused */
730 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
731 34, -1 /* intrusion0, intrusion1 */
732};
733
Guenter Roeck6c009502012-07-01 08:23:15 -0700734static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
735 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
736
737static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
738 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
739
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800740static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
741{
742 if (mode == 0 && pwm == 255)
743 return off;
744 return mode + 1;
745}
746
747static int pwm_enable_to_reg(enum pwm_enable mode)
748{
749 if (mode == off)
750 return 0;
751 return mode - 1;
752}
753
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700754/*
755 * Conversions
756 */
757
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800758/* 1 is DC mode, output in ms */
759static unsigned int step_time_from_reg(u8 reg, u8 mode)
760{
761 return mode ? 400 * reg : 100 * reg;
762}
763
764static u8 step_time_to_reg(unsigned int msec, u8 mode)
765{
766 return clamp_val((mode ? (msec + 200) / 400 :
767 (msec + 50) / 100), 1, 255);
768}
769
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800770static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
771{
772 if (reg == 0 || reg == 255)
773 return 0;
774 return 1350000U / (reg << divreg);
775}
776
777static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
778{
779 if ((reg & 0xff1f) == 0xff1f)
780 return 0;
781
782 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
783
784 if (reg == 0)
785 return 0;
786
787 return 1350000U / reg;
788}
789
790static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
791{
792 if (reg == 0 || reg == 0xffff)
793 return 0;
794
795 /*
796 * Even though the registers are 16 bit wide, the fan divisor
797 * still applies.
798 */
799 return 1350000U / (reg << divreg);
800}
801
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800802static u16 fan_to_reg(u32 fan, unsigned int divreg)
803{
804 if (!fan)
805 return 0;
806
807 return (1350000U / fan) >> divreg;
808}
809
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800810static inline unsigned int
811div_from_reg(u8 reg)
812{
813 return 1 << reg;
814}
815
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700816/*
817 * Some of the voltage inputs have internal scaling, the tables below
818 * contain 8 (the ADC LSB in mV) * scaling factor * 100
819 */
820static const u16 scale_in[15] = {
821 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
822 800, 800
823};
824
825static inline long in_from_reg(u8 reg, u8 nr)
826{
827 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
828}
829
830static inline u8 in_to_reg(u32 val, u8 nr)
831{
832 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
833}
834
835/*
836 * Data structures and manipulation thereof
837 */
838
839struct nct6775_data {
840 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700841 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700842 enum kinds kind;
843 const char *name;
844
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700845 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700846
Guenter Roeckb7a61352013-04-02 22:14:06 -0700847 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
848 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800849 */
850 u8 temp_src[NUM_TEMP];
851 u16 reg_temp_config[NUM_TEMP];
852 const char * const *temp_label;
853 int temp_label_num;
854
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700855 u16 REG_CONFIG;
856 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800857 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700858 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700859
860 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700861 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700862
863 const u16 *REG_VIN;
864 const u16 *REG_IN_MINMAX[2];
865
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800866 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800867 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800868 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800869 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800870 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700871 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800872 const u16 *REG_FAN_TIME[3];
873
874 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800875
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800876 const u8 *REG_PWM_MODE;
877 const u8 *PWM_MODE_MASK;
878
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800879 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
880 * [3]=pwm_max, [4]=pwm_step,
881 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800882 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800883 const u16 *REG_PWM_READ;
884
Guenter Roeck6c009502012-07-01 08:23:15 -0700885 const u16 *REG_CRITICAL_PWM_ENABLE;
886 u8 CRITICAL_PWM_ENABLE_MASK;
887 const u16 *REG_CRITICAL_PWM;
888
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800889 const u16 *REG_AUTO_TEMP;
890 const u16 *REG_AUTO_PWM;
891
892 const u16 *REG_CRITICAL_TEMP;
893 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
894
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800895 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800896 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800897 const u16 *REG_WEIGHT_TEMP_SEL;
898 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
899
Guenter Roeckaa136e52012-12-04 03:26:05 -0800900 const u16 *REG_TEMP_OFFSET;
901
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700902 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700903 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700904
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800905 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
906 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
907
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700908 struct mutex update_lock;
909 bool valid; /* true if following fields are valid */
910 unsigned long last_updated; /* In jiffies */
911
912 /* Register values */
913 u8 bank; /* current register bank */
914 u8 in_num; /* number of in inputs we have */
915 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700916 unsigned int rpm[NUM_FAN];
917 u16 fan_min[NUM_FAN];
918 u8 fan_pulses[NUM_FAN];
919 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800920 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800921 u8 has_fan; /* some fan inputs can be disabled */
922 u8 has_fan_min; /* some fans don't have min register */
923 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700924
Guenter Roeck6c009502012-07-01 08:23:15 -0700925 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700926 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800927 u8 temp_fixed_num; /* 3 or 6 */
928 u8 temp_type[NUM_TEMP_FIXED];
929 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300930 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
931 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700932 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700933 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700934
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800935 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700936 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
937 * 0->PWM variable duty cycle
938 */
939 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800940 /* 0->off
941 * 1->manual
942 * 2->thermal cruise mode (also called SmartFan I)
943 * 3->fan speed cruise mode
944 * 4->SmartFan III
945 * 5->enhanced variable thermal cruise (SmartFan IV)
946 */
David Bartley578ab5f2013-06-24 22:28:28 -0700947 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
948 * [3]=pwm_max, [4]=pwm_step,
949 * [5]=weight_duty_step, [6]=weight_duty_base
950 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800951
David Bartley578ab5f2013-06-24 22:28:28 -0700952 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800953 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700954 u32 target_speed[NUM_FAN];
955 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800956 u8 speed_tolerance_limit;
957
David Bartley578ab5f2013-06-24 22:28:28 -0700958 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800959 u8 tolerance_mask;
960
David Bartley578ab5f2013-06-24 22:28:28 -0700961 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800962
963 /* Automatic fan speed control registers */
964 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700965 u8 auto_pwm[NUM_FAN][7];
966 u8 auto_temp[NUM_FAN][7];
967 u8 pwm_temp_sel[NUM_FAN];
968 u8 pwm_weight_temp_sel[NUM_FAN];
969 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
970 * 2->temp_base
971 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800972
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700973 u8 vid;
974 u8 vrm;
975
Guenter Roeckf73cf632013-03-18 09:22:50 -0700976 bool have_vid;
977
Guenter Roeckaa136e52012-12-04 03:26:05 -0800978 u16 have_temp;
979 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700980 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800981
Guenter Roeck84d19d92012-12-04 08:01:39 -0800982 /* Remember extra register values over suspend/resume */
983 u8 vbat;
984 u8 fandiv1;
985 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800986 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700987};
988
989struct nct6775_sio_data {
990 int sioreg;
991 enum kinds kind;
992};
993
Guenter Roeckf73cf632013-03-18 09:22:50 -0700994struct sensor_device_template {
995 struct device_attribute dev_attr;
996 union {
997 struct {
998 u8 nr;
999 u8 index;
1000 } s;
1001 int index;
1002 } u;
1003 bool s2; /* true if both index and nr are used */
1004};
1005
1006struct sensor_device_attr_u {
1007 union {
1008 struct sensor_device_attribute a1;
1009 struct sensor_device_attribute_2 a2;
1010 } u;
1011 char name[32];
1012};
1013
1014#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1015 .attr = {.name = _template, .mode = _mode }, \
1016 .show = _show, \
1017 .store = _store, \
1018}
1019
1020#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1021 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1022 .u.index = _index, \
1023 .s2 = false }
1024
1025#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1026 _nr, _index) \
1027 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1028 .u.s.index = _index, \
1029 .u.s.nr = _nr, \
1030 .s2 = true }
1031
1032#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1033static struct sensor_device_template sensor_dev_template_##_name \
1034 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1035 _index)
1036
1037#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1038 _nr, _index) \
1039static struct sensor_device_template sensor_dev_template_##_name \
1040 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1041 _nr, _index)
1042
1043struct sensor_template_group {
1044 struct sensor_device_template **templates;
1045 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1046 int base;
1047};
1048
1049static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001050nct6775_create_attr_group(struct device *dev,
1051 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001052 int repeat)
1053{
1054 struct attribute_group *group;
1055 struct sensor_device_attr_u *su;
1056 struct sensor_device_attribute *a;
1057 struct sensor_device_attribute_2 *a2;
1058 struct attribute **attrs;
1059 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001060 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001061
1062 if (repeat <= 0)
1063 return ERR_PTR(-EINVAL);
1064
1065 t = tg->templates;
1066 for (count = 0; *t; t++, count++)
1067 ;
1068
1069 if (count == 0)
1070 return ERR_PTR(-EINVAL);
1071
1072 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1073 if (group == NULL)
1074 return ERR_PTR(-ENOMEM);
1075
1076 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1077 GFP_KERNEL);
1078 if (attrs == NULL)
1079 return ERR_PTR(-ENOMEM);
1080
1081 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1082 GFP_KERNEL);
1083 if (su == NULL)
1084 return ERR_PTR(-ENOMEM);
1085
1086 group->attrs = attrs;
1087 group->is_visible = tg->is_visible;
1088
1089 for (i = 0; i < repeat; i++) {
1090 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001091 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001092 snprintf(su->name, sizeof(su->name),
1093 (*t)->dev_attr.attr.name, tg->base + i);
1094 if ((*t)->s2) {
1095 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001096 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001097 a2->dev_attr.attr.name = su->name;
1098 a2->nr = (*t)->u.s.nr + i;
1099 a2->index = (*t)->u.s.index;
1100 a2->dev_attr.attr.mode =
1101 (*t)->dev_attr.attr.mode;
1102 a2->dev_attr.show = (*t)->dev_attr.show;
1103 a2->dev_attr.store = (*t)->dev_attr.store;
1104 *attrs = &a2->dev_attr.attr;
1105 } else {
1106 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001107 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001108 a->dev_attr.attr.name = su->name;
1109 a->index = (*t)->u.index + i;
1110 a->dev_attr.attr.mode =
1111 (*t)->dev_attr.attr.mode;
1112 a->dev_attr.show = (*t)->dev_attr.show;
1113 a->dev_attr.store = (*t)->dev_attr.store;
1114 *attrs = &a->dev_attr.attr;
1115 }
1116 attrs++;
1117 su++;
1118 t++;
1119 }
1120 }
1121
Guenter Roeckf73cf632013-03-18 09:22:50 -07001122 return group;
1123}
1124
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001125static bool is_word_sized(struct nct6775_data *data, u16 reg)
1126{
1127 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001128 case nct6106:
1129 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1130 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1131 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001132 case nct6775:
1133 return (((reg & 0xff00) == 0x100 ||
1134 (reg & 0xff00) == 0x200) &&
1135 ((reg & 0x00ff) == 0x50 ||
1136 (reg & 0x00ff) == 0x53 ||
1137 (reg & 0x00ff) == 0x55)) ||
1138 (reg & 0xfff0) == 0x630 ||
1139 reg == 0x640 || reg == 0x642 ||
1140 reg == 0x662 ||
1141 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1142 reg == 0x73 || reg == 0x75 || reg == 0x77;
1143 case nct6776:
1144 return (((reg & 0xff00) == 0x100 ||
1145 (reg & 0xff00) == 0x200) &&
1146 ((reg & 0x00ff) == 0x50 ||
1147 (reg & 0x00ff) == 0x53 ||
1148 (reg & 0x00ff) == 0x55)) ||
1149 (reg & 0xfff0) == 0x630 ||
1150 reg == 0x402 ||
1151 reg == 0x640 || reg == 0x642 ||
1152 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1153 reg == 0x73 || reg == 0x75 || reg == 0x77;
1154 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001155 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001156 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001157 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001158 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001159 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001160 reg == 0x402 ||
1161 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1162 reg == 0x640 || reg == 0x642 ||
1163 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001164 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001165 }
1166 return false;
1167}
1168
1169/*
1170 * On older chips, only registers 0x50-0x5f are banked.
1171 * On more recent chips, all registers are banked.
1172 * Assume that is the case and set the bank number for each access.
1173 * Cache the bank number so it only needs to be set if it changes.
1174 */
1175static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1176{
1177 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001178
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001179 if (data->bank != bank) {
1180 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1181 outb_p(bank, data->addr + DATA_REG_OFFSET);
1182 data->bank = bank;
1183 }
1184}
1185
1186static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1187{
1188 int res, word_sized = is_word_sized(data, reg);
1189
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001190 nct6775_set_bank(data, reg);
1191 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1192 res = inb_p(data->addr + DATA_REG_OFFSET);
1193 if (word_sized) {
1194 outb_p((reg & 0xff) + 1,
1195 data->addr + ADDR_REG_OFFSET);
1196 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1197 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001198 return res;
1199}
1200
1201static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1202{
1203 int word_sized = is_word_sized(data, reg);
1204
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001205 nct6775_set_bank(data, reg);
1206 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1207 if (word_sized) {
1208 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1209 outb_p((reg & 0xff) + 1,
1210 data->addr + ADDR_REG_OFFSET);
1211 }
1212 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001213 return 0;
1214}
1215
Guenter Roeckaa136e52012-12-04 03:26:05 -08001216/* We left-align 8-bit temperature values to make the code simpler */
1217static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1218{
1219 u16 res;
1220
1221 res = nct6775_read_value(data, reg);
1222 if (!is_word_sized(data, reg))
1223 res <<= 8;
1224
1225 return res;
1226}
1227
1228static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1229{
1230 if (!is_word_sized(data, reg))
1231 value >>= 8;
1232 return nct6775_write_value(data, reg, value);
1233}
1234
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001235/* This function assumes that the caller holds data->update_lock */
1236static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1237{
1238 u8 reg;
1239
1240 switch (nr) {
1241 case 0:
1242 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1243 | (data->fan_div[0] & 0x7);
1244 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1245 break;
1246 case 1:
1247 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1248 | ((data->fan_div[1] << 4) & 0x70);
1249 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1250 break;
1251 case 2:
1252 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1253 | (data->fan_div[2] & 0x7);
1254 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1255 break;
1256 case 3:
1257 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1258 | ((data->fan_div[3] << 4) & 0x70);
1259 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1260 break;
1261 }
1262}
1263
1264static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1265{
1266 if (data->kind == nct6775)
1267 nct6775_write_fan_div(data, nr);
1268}
1269
1270static void nct6775_update_fan_div(struct nct6775_data *data)
1271{
1272 u8 i;
1273
1274 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1275 data->fan_div[0] = i & 0x7;
1276 data->fan_div[1] = (i & 0x70) >> 4;
1277 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1278 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001279 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001280 data->fan_div[3] = (i & 0x70) >> 4;
1281}
1282
1283static void nct6775_update_fan_div_common(struct nct6775_data *data)
1284{
1285 if (data->kind == nct6775)
1286 nct6775_update_fan_div(data);
1287}
1288
1289static void nct6775_init_fan_div(struct nct6775_data *data)
1290{
1291 int i;
1292
1293 nct6775_update_fan_div_common(data);
1294 /*
1295 * For all fans, start with highest divider value if the divider
1296 * register is not initialized. This ensures that we get a
1297 * reading from the fan count register, even if it is not optimal.
1298 * We'll compute a better divider later on.
1299 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001300 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001301 if (!(data->has_fan & (1 << i)))
1302 continue;
1303 if (data->fan_div[i] == 0) {
1304 data->fan_div[i] = 7;
1305 nct6775_write_fan_div_common(data, i);
1306 }
1307 }
1308}
1309
1310static void nct6775_init_fan_common(struct device *dev,
1311 struct nct6775_data *data)
1312{
1313 int i;
1314 u8 reg;
1315
1316 if (data->has_fan_div)
1317 nct6775_init_fan_div(data);
1318
1319 /*
1320 * If fan_min is not set (0), set it to 0xff to disable it. This
1321 * prevents the unnecessary warning when fanX_min is reported as 0.
1322 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001323 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001324 if (data->has_fan_min & (1 << i)) {
1325 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1326 if (!reg)
1327 nct6775_write_value(data, data->REG_FAN_MIN[i],
1328 data->has_fan_div ? 0xff
1329 : 0xff1f);
1330 }
1331 }
1332}
1333
1334static void nct6775_select_fan_div(struct device *dev,
1335 struct nct6775_data *data, int nr, u16 reg)
1336{
1337 u8 fan_div = data->fan_div[nr];
1338 u16 fan_min;
1339
1340 if (!data->has_fan_div)
1341 return;
1342
1343 /*
1344 * If we failed to measure the fan speed, or the reported value is not
1345 * in the optimal range, and the clock divider can be modified,
1346 * let's try that for next time.
1347 */
1348 if (reg == 0x00 && fan_div < 0x07)
1349 fan_div++;
1350 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1351 fan_div--;
1352
1353 if (fan_div != data->fan_div[nr]) {
1354 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1355 nr + 1, div_from_reg(data->fan_div[nr]),
1356 div_from_reg(fan_div));
1357
1358 /* Preserve min limit if possible */
1359 if (data->has_fan_min & (1 << nr)) {
1360 fan_min = data->fan_min[nr];
1361 if (fan_div > data->fan_div[nr]) {
1362 if (fan_min != 255 && fan_min > 1)
1363 fan_min >>= 1;
1364 } else {
1365 if (fan_min != 255) {
1366 fan_min <<= 1;
1367 if (fan_min > 254)
1368 fan_min = 254;
1369 }
1370 }
1371 if (fan_min != data->fan_min[nr]) {
1372 data->fan_min[nr] = fan_min;
1373 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1374 fan_min);
1375 }
1376 }
1377 data->fan_div[nr] = fan_div;
1378 nct6775_write_fan_div_common(data, nr);
1379 }
1380}
1381
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001382static void nct6775_update_pwm(struct device *dev)
1383{
1384 struct nct6775_data *data = dev_get_drvdata(dev);
1385 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001386 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001387 bool duty_is_dc;
1388
1389 for (i = 0; i < data->pwm_num; i++) {
1390 if (!(data->has_pwm & (1 << i)))
1391 continue;
1392
1393 duty_is_dc = data->REG_PWM_MODE[i] &&
1394 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1395 & data->PWM_MODE_MASK[i]);
Guenter Roeck2a48e892018-03-26 19:50:31 -07001396 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001397
1398 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1399 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1400 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1401 data->pwm[j][i]
1402 = nct6775_read_value(data,
1403 data->REG_PWM[j][i]);
1404 }
1405 }
1406
1407 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1408 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001409
1410 if (!data->temp_tolerance[0][i] ||
1411 data->pwm_enable[i] != speed_cruise)
1412 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1413 if (!data->target_speed_tolerance[i] ||
1414 data->pwm_enable[i] == speed_cruise) {
1415 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001416
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001417 if (data->REG_TOLERANCE_H) {
1418 t |= (nct6775_read_value(data,
1419 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1420 }
1421 data->target_speed_tolerance[i] = t;
1422 }
1423
1424 data->temp_tolerance[1][i] =
1425 nct6775_read_value(data,
1426 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1427
1428 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1429 data->pwm_temp_sel[i] = reg & 0x1f;
1430 /* If fan can stop, report floor as 0 */
1431 if (reg & 0x80)
1432 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001433
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001434 if (!data->REG_WEIGHT_TEMP_SEL[i])
1435 continue;
1436
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001437 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1438 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1439 /* If weight is disabled, report weight source as 0 */
1440 if (j == 1 && !(reg & 0x80))
1441 data->pwm_weight_temp_sel[i] = 0;
1442
1443 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001444 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001445 data->weight_temp[j][i]
1446 = nct6775_read_value(data,
1447 data->REG_WEIGHT_TEMP[j][i]);
1448 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001449 }
1450}
1451
1452static void nct6775_update_pwm_limits(struct device *dev)
1453{
1454 struct nct6775_data *data = dev_get_drvdata(dev);
1455 int i, j;
1456 u8 reg;
1457 u16 reg_t;
1458
1459 for (i = 0; i < data->pwm_num; i++) {
1460 if (!(data->has_pwm & (1 << i)))
1461 continue;
1462
Guenter Roeckc409fd42013-04-09 05:04:00 -07001463 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001464 data->fan_time[j][i] =
1465 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1466 }
1467
1468 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1469 /* Update only in matching mode or if never updated */
1470 if (!data->target_temp[i] ||
1471 data->pwm_enable[i] == thermal_cruise)
1472 data->target_temp[i] = reg_t & data->target_temp_mask;
1473 if (!data->target_speed[i] ||
1474 data->pwm_enable[i] == speed_cruise) {
1475 if (data->REG_TOLERANCE_H) {
1476 reg_t |= (nct6775_read_value(data,
1477 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1478 }
1479 data->target_speed[i] = reg_t;
1480 }
1481
1482 for (j = 0; j < data->auto_pwm_num; j++) {
1483 data->auto_pwm[i][j] =
1484 nct6775_read_value(data,
1485 NCT6775_AUTO_PWM(data, i, j));
1486 data->auto_temp[i][j] =
1487 nct6775_read_value(data,
1488 NCT6775_AUTO_TEMP(data, i, j));
1489 }
1490
1491 /* critical auto_pwm temperature data */
1492 data->auto_temp[i][data->auto_pwm_num] =
1493 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1494
1495 switch (data->kind) {
1496 case nct6775:
1497 reg = nct6775_read_value(data,
1498 NCT6775_REG_CRITICAL_ENAB[i]);
1499 data->auto_pwm[i][data->auto_pwm_num] =
1500 (reg & 0x02) ? 0xff : 0x00;
1501 break;
1502 case nct6776:
1503 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1504 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001505 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001506 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001507 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001508 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001509 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001510 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001511 data->REG_CRITICAL_PWM_ENABLE[i]);
1512 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1513 reg = nct6775_read_value(data,
1514 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001515 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001516 reg = 0xff;
1517 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001518 break;
1519 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001520 }
1521}
1522
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001523static struct nct6775_data *nct6775_update_device(struct device *dev)
1524{
1525 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001526 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001527
1528 mutex_lock(&data->update_lock);
1529
Guenter Roeck6445e662013-04-21 09:13:28 -07001530 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001531 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001532 /* Fan clock dividers */
1533 nct6775_update_fan_div_common(data);
1534
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001535 /* Measured voltages and limits */
1536 for (i = 0; i < data->in_num; i++) {
1537 if (!(data->have_in & (1 << i)))
1538 continue;
1539
1540 data->in[i][0] = nct6775_read_value(data,
1541 data->REG_VIN[i]);
1542 data->in[i][1] = nct6775_read_value(data,
1543 data->REG_IN_MINMAX[0][i]);
1544 data->in[i][2] = nct6775_read_value(data,
1545 data->REG_IN_MINMAX[1][i]);
1546 }
1547
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001548 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001549 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001550 u16 reg;
1551
1552 if (!(data->has_fan & (1 << i)))
1553 continue;
1554
1555 reg = nct6775_read_value(data, data->REG_FAN[i]);
1556 data->rpm[i] = data->fan_from_reg(reg,
1557 data->fan_div[i]);
1558
1559 if (data->has_fan_min & (1 << i))
1560 data->fan_min[i] = nct6775_read_value(data,
1561 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001562 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001563 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1564 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001565
1566 nct6775_select_fan_div(dev, data, i, reg);
1567 }
1568
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001569 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001570 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001571
Guenter Roeckaa136e52012-12-04 03:26:05 -08001572 /* Measured temperatures and limits */
1573 for (i = 0; i < NUM_TEMP; i++) {
1574 if (!(data->have_temp & (1 << i)))
1575 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001576 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001577 if (data->reg_temp[j][i])
1578 data->temp[j][i]
1579 = nct6775_read_temp(data,
1580 data->reg_temp[j][i]);
1581 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001582 if (i >= NUM_TEMP_FIXED ||
1583 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001584 continue;
1585 data->temp_offset[i]
1586 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1587 }
1588
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001589 data->alarms = 0;
1590 for (i = 0; i < NUM_REG_ALARM; i++) {
1591 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001592
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001593 if (!data->REG_ALARM[i])
1594 continue;
1595 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1596 data->alarms |= ((u64)alarm) << (i << 3);
1597 }
1598
Guenter Roeck30846992013-06-24 22:21:59 -07001599 data->beeps = 0;
1600 for (i = 0; i < NUM_REG_BEEP; i++) {
1601 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001602
Guenter Roeck30846992013-06-24 22:21:59 -07001603 if (!data->REG_BEEP[i])
1604 continue;
1605 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1606 data->beeps |= ((u64)beep) << (i << 3);
1607 }
1608
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001609 data->last_updated = jiffies;
1610 data->valid = true;
1611 }
1612
1613 mutex_unlock(&data->update_lock);
1614 return data;
1615}
1616
1617/*
1618 * Sysfs callback functions
1619 */
1620static ssize_t
1621show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1622{
1623 struct nct6775_data *data = nct6775_update_device(dev);
1624 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001625 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001626 int nr = sattr->nr;
1627
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001628 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1629}
1630
1631static ssize_t
1632store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1633 size_t count)
1634{
1635 struct nct6775_data *data = dev_get_drvdata(dev);
1636 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001637 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001638 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001639 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001640 int err;
1641
1642 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001643 if (err < 0)
1644 return err;
1645 mutex_lock(&data->update_lock);
1646 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001647 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001648 data->in[nr][index]);
1649 mutex_unlock(&data->update_lock);
1650 return count;
1651}
1652
1653static ssize_t
1654show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1655{
1656 struct nct6775_data *data = nct6775_update_device(dev);
1657 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1658 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001659
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001660 return sprintf(buf, "%u\n",
1661 (unsigned int)((data->alarms >> nr) & 0x01));
1662}
1663
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001664static int find_temp_source(struct nct6775_data *data, int index, int count)
1665{
1666 int source = data->temp_src[index];
1667 int nr;
1668
1669 for (nr = 0; nr < count; nr++) {
1670 int src;
1671
1672 src = nct6775_read_value(data,
1673 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1674 if (src == source)
1675 return nr;
1676 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001677 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001678}
1679
1680static ssize_t
1681show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1682{
1683 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1684 struct nct6775_data *data = nct6775_update_device(dev);
1685 unsigned int alarm = 0;
1686 int nr;
1687
1688 /*
1689 * For temperatures, there is no fixed mapping from registers to alarm
1690 * bits. Alarm bits are determined by the temperature source mapping.
1691 */
1692 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1693 if (nr >= 0) {
1694 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001695
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001696 alarm = (data->alarms >> bit) & 0x01;
1697 }
1698 return sprintf(buf, "%u\n", alarm);
1699}
1700
Guenter Roeck30846992013-06-24 22:21:59 -07001701static ssize_t
1702show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1703{
1704 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1705 struct nct6775_data *data = nct6775_update_device(dev);
1706 int nr = data->BEEP_BITS[sattr->index];
1707
1708 return sprintf(buf, "%u\n",
1709 (unsigned int)((data->beeps >> nr) & 0x01));
1710}
1711
1712static ssize_t
1713store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1714 size_t count)
1715{
1716 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1717 struct nct6775_data *data = dev_get_drvdata(dev);
1718 int nr = data->BEEP_BITS[sattr->index];
1719 int regindex = nr >> 3;
1720 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001721 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001722
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001723 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001724 if (err < 0)
1725 return err;
1726 if (val > 1)
1727 return -EINVAL;
1728
1729 mutex_lock(&data->update_lock);
1730 if (val)
1731 data->beeps |= (1ULL << nr);
1732 else
1733 data->beeps &= ~(1ULL << nr);
1734 nct6775_write_value(data, data->REG_BEEP[regindex],
1735 (data->beeps >> (regindex << 3)) & 0xff);
1736 mutex_unlock(&data->update_lock);
1737 return count;
1738}
1739
1740static ssize_t
1741show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1742{
1743 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1744 struct nct6775_data *data = nct6775_update_device(dev);
1745 unsigned int beep = 0;
1746 int nr;
1747
1748 /*
1749 * For temperatures, there is no fixed mapping from registers to beep
1750 * enable bits. Beep enable bits are determined by the temperature
1751 * source mapping.
1752 */
1753 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1754 if (nr >= 0) {
1755 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001756
Guenter Roeck30846992013-06-24 22:21:59 -07001757 beep = (data->beeps >> bit) & 0x01;
1758 }
1759 return sprintf(buf, "%u\n", beep);
1760}
1761
1762static ssize_t
1763store_temp_beep(struct device *dev, struct device_attribute *attr,
1764 const char *buf, size_t count)
1765{
1766 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1767 struct nct6775_data *data = dev_get_drvdata(dev);
1768 int nr, bit, regindex;
1769 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001770 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001771
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001772 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001773 if (err < 0)
1774 return err;
1775 if (val > 1)
1776 return -EINVAL;
1777
1778 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1779 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001780 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001781
1782 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1783 regindex = bit >> 3;
1784
1785 mutex_lock(&data->update_lock);
1786 if (val)
1787 data->beeps |= (1ULL << bit);
1788 else
1789 data->beeps &= ~(1ULL << bit);
1790 nct6775_write_value(data, data->REG_BEEP[regindex],
1791 (data->beeps >> (regindex << 3)) & 0xff);
1792 mutex_unlock(&data->update_lock);
1793
1794 return count;
1795}
1796
Guenter Roeckf73cf632013-03-18 09:22:50 -07001797static umode_t nct6775_in_is_visible(struct kobject *kobj,
1798 struct attribute *attr, int index)
1799{
1800 struct device *dev = container_of(kobj, struct device, kobj);
1801 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001802 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001803
Guenter Roeckf73cf632013-03-18 09:22:50 -07001804 if (!(data->have_in & (1 << in)))
1805 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001806
Guenter Roeckf73cf632013-03-18 09:22:50 -07001807 return attr->mode;
1808}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001809
Guenter Roeckf73cf632013-03-18 09:22:50 -07001810SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1811SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001812SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1813 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001814SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1815 store_in_reg, 0, 1);
1816SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1817 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001818
Guenter Roeckf73cf632013-03-18 09:22:50 -07001819/*
1820 * nct6775_in_is_visible uses the index into the following array
1821 * to determine if attributes should be created or not.
1822 * Any change in order or content must be matched.
1823 */
1824static struct sensor_device_template *nct6775_attributes_in_template[] = {
1825 &sensor_dev_template_in_input,
1826 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001827 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001828 &sensor_dev_template_in_min,
1829 &sensor_dev_template_in_max,
1830 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001831};
1832
Julia Lawallc60fdf82015-12-12 17:36:39 +01001833static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001834 .templates = nct6775_attributes_in_template,
1835 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001836};
1837
1838static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001839show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1840{
1841 struct nct6775_data *data = nct6775_update_device(dev);
1842 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1843 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001844
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001845 return sprintf(buf, "%d\n", data->rpm[nr]);
1846}
1847
1848static ssize_t
1849show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1850{
1851 struct nct6775_data *data = nct6775_update_device(dev);
1852 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1853 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001854
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001855 return sprintf(buf, "%d\n",
1856 data->fan_from_reg_min(data->fan_min[nr],
1857 data->fan_div[nr]));
1858}
1859
1860static ssize_t
1861show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1862{
1863 struct nct6775_data *data = nct6775_update_device(dev);
1864 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1865 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001866
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001867 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1868}
1869
1870static ssize_t
1871store_fan_min(struct device *dev, struct device_attribute *attr,
1872 const char *buf, size_t count)
1873{
1874 struct nct6775_data *data = dev_get_drvdata(dev);
1875 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1876 int nr = sattr->index;
1877 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001878 unsigned int reg;
1879 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001880 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001881
1882 err = kstrtoul(buf, 10, &val);
1883 if (err < 0)
1884 return err;
1885
1886 mutex_lock(&data->update_lock);
1887 if (!data->has_fan_div) {
1888 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1889 if (!val) {
1890 val = 0xff1f;
1891 } else {
1892 if (val > 1350000U)
1893 val = 135000U;
1894 val = 1350000U / val;
1895 val = (val & 0x1f) | ((val << 3) & 0xff00);
1896 }
1897 data->fan_min[nr] = val;
1898 goto write_min; /* Leave fan divider alone */
1899 }
1900 if (!val) {
1901 /* No min limit, alarm disabled */
1902 data->fan_min[nr] = 255;
1903 new_div = data->fan_div[nr]; /* No change */
1904 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1905 goto write_div;
1906 }
1907 reg = 1350000U / val;
1908 if (reg >= 128 * 255) {
1909 /*
1910 * Speed below this value cannot possibly be represented,
1911 * even with the highest divider (128)
1912 */
1913 data->fan_min[nr] = 254;
1914 new_div = 7; /* 128 == (1 << 7) */
1915 dev_warn(dev,
1916 "fan%u low limit %lu below minimum %u, set to minimum\n",
1917 nr + 1, val, data->fan_from_reg_min(254, 7));
1918 } else if (!reg) {
1919 /*
1920 * Speed above this value cannot possibly be represented,
1921 * even with the lowest divider (1)
1922 */
1923 data->fan_min[nr] = 1;
1924 new_div = 0; /* 1 == (1 << 0) */
1925 dev_warn(dev,
1926 "fan%u low limit %lu above maximum %u, set to maximum\n",
1927 nr + 1, val, data->fan_from_reg_min(1, 0));
1928 } else {
1929 /*
1930 * Automatically pick the best divider, i.e. the one such
1931 * that the min limit will correspond to a register value
1932 * in the 96..192 range
1933 */
1934 new_div = 0;
1935 while (reg > 192 && new_div < 7) {
1936 reg >>= 1;
1937 new_div++;
1938 }
1939 data->fan_min[nr] = reg;
1940 }
1941
1942write_div:
1943 /*
1944 * Write both the fan clock divider (if it changed) and the new
1945 * fan min (unconditionally)
1946 */
1947 if (new_div != data->fan_div[nr]) {
1948 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1949 nr + 1, div_from_reg(data->fan_div[nr]),
1950 div_from_reg(new_div));
1951 data->fan_div[nr] = new_div;
1952 nct6775_write_fan_div_common(data, nr);
1953 /* Give the chip time to sample a new speed value */
1954 data->last_updated = jiffies;
1955 }
1956
1957write_min:
1958 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1959 mutex_unlock(&data->update_lock);
1960
1961 return count;
1962}
1963
Guenter Roeck5c25d952012-12-11 07:29:06 -08001964static ssize_t
1965show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1966{
1967 struct nct6775_data *data = nct6775_update_device(dev);
1968 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1969 int p = data->fan_pulses[sattr->index];
1970
1971 return sprintf(buf, "%d\n", p ? : 4);
1972}
1973
1974static ssize_t
1975store_fan_pulses(struct device *dev, struct device_attribute *attr,
1976 const char *buf, size_t count)
1977{
1978 struct nct6775_data *data = dev_get_drvdata(dev);
1979 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1980 int nr = sattr->index;
1981 unsigned long val;
1982 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001983 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001984
1985 err = kstrtoul(buf, 10, &val);
1986 if (err < 0)
1987 return err;
1988
1989 if (val > 4)
1990 return -EINVAL;
1991
1992 mutex_lock(&data->update_lock);
1993 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001994 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1995 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1996 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1997 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001998 mutex_unlock(&data->update_lock);
1999
2000 return count;
2001}
2002
Guenter Roeckf73cf632013-03-18 09:22:50 -07002003static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2004 struct attribute *attr, int index)
2005{
2006 struct device *dev = container_of(kobj, struct device, kobj);
2007 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002008 int fan = index / 6; /* fan index */
2009 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002010
2011 if (!(data->has_fan & (1 << fan)))
2012 return 0;
2013
2014 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2015 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002016 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002017 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002018 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
2019 return 0;
2020 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002021 return 0;
2022
2023 return attr->mode;
2024}
2025
2026SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2027SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2028 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002029SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2030 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002031SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2032 store_fan_pulses, 0);
2033SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2034 store_fan_min, 0);
2035SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2036
2037/*
2038 * nct6775_fan_is_visible uses the index into the following array
2039 * to determine if attributes should be created or not.
2040 * Any change in order or content must be matched.
2041 */
2042static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2043 &sensor_dev_template_fan_input,
2044 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002045 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002046 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002047 &sensor_dev_template_fan_min, /* 4 */
2048 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002049 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002050};
2051
Julia Lawallc60fdf82015-12-12 17:36:39 +01002052static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002053 .templates = nct6775_attributes_fan_template,
2054 .is_visible = nct6775_fan_is_visible,
2055 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002056};
2057
2058static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002059show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2060{
2061 struct nct6775_data *data = nct6775_update_device(dev);
2062 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2063 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002064
Guenter Roeckaa136e52012-12-04 03:26:05 -08002065 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2066}
2067
2068static ssize_t
2069show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2070{
2071 struct nct6775_data *data = nct6775_update_device(dev);
2072 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2073 int nr = sattr->nr;
2074 int index = sattr->index;
2075
2076 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2077}
2078
2079static ssize_t
2080store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2081 size_t count)
2082{
2083 struct nct6775_data *data = dev_get_drvdata(dev);
2084 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2085 int nr = sattr->nr;
2086 int index = sattr->index;
2087 int err;
2088 long val;
2089
2090 err = kstrtol(buf, 10, &val);
2091 if (err < 0)
2092 return err;
2093
2094 mutex_lock(&data->update_lock);
2095 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2096 nct6775_write_temp(data, data->reg_temp[index][nr],
2097 data->temp[index][nr]);
2098 mutex_unlock(&data->update_lock);
2099 return count;
2100}
2101
2102static ssize_t
2103show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2104{
2105 struct nct6775_data *data = nct6775_update_device(dev);
2106 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2107
2108 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2109}
2110
2111static ssize_t
2112store_temp_offset(struct device *dev, struct device_attribute *attr,
2113 const char *buf, size_t count)
2114{
2115 struct nct6775_data *data = dev_get_drvdata(dev);
2116 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2117 int nr = sattr->index;
2118 long val;
2119 int err;
2120
2121 err = kstrtol(buf, 10, &val);
2122 if (err < 0)
2123 return err;
2124
2125 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2126
2127 mutex_lock(&data->update_lock);
2128 data->temp_offset[nr] = val;
2129 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2130 mutex_unlock(&data->update_lock);
2131
2132 return count;
2133}
2134
2135static ssize_t
2136show_temp_type(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, "%d\n", (int)data->temp_type[nr]);
2143}
2144
2145static ssize_t
2146store_temp_type(struct device *dev, struct device_attribute *attr,
2147 const char *buf, size_t count)
2148{
2149 struct nct6775_data *data = nct6775_update_device(dev);
2150 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2151 int nr = sattr->index;
2152 unsigned long val;
2153 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002154 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002155
2156 err = kstrtoul(buf, 10, &val);
2157 if (err < 0)
2158 return err;
2159
2160 if (val != 1 && val != 3 && val != 4)
2161 return -EINVAL;
2162
2163 mutex_lock(&data->update_lock);
2164
2165 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002166 vbit = 0x02 << nr;
2167 dbit = data->DIODE_MASK << nr;
2168 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2169 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002170 switch (val) {
2171 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002172 vbat |= vbit;
2173 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002174 break;
2175 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002176 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002177 break;
2178 case 4: /* thermistor */
2179 break;
2180 }
2181 nct6775_write_value(data, data->REG_VBAT, vbat);
2182 nct6775_write_value(data, data->REG_DIODE, diode);
2183
2184 mutex_unlock(&data->update_lock);
2185 return count;
2186}
2187
Guenter Roeckf73cf632013-03-18 09:22:50 -07002188static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2189 struct attribute *attr, int index)
2190{
2191 struct device *dev = container_of(kobj, struct device, kobj);
2192 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002193 int temp = index / 10; /* temp index */
2194 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002195
2196 if (!(data->have_temp & (1 << temp)))
2197 return 0;
2198
2199 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2200 return 0; /* alarm */
2201
Guenter Roeck30846992013-06-24 22:21:59 -07002202 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2203 return 0; /* beep */
2204
2205 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002206 return 0;
2207
Guenter Roeck30846992013-06-24 22:21:59 -07002208 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002209 return 0;
2210
Guenter Roeck30846992013-06-24 22:21:59 -07002211 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002212 return 0;
2213
Guenter Roeck30846992013-06-24 22:21:59 -07002214 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002215 return 0;
2216
2217 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002218 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002219 return 0;
2220
2221 return attr->mode;
2222}
2223
2224SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2225SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2226SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2227 store_temp, 0, 1);
2228SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2229 show_temp, store_temp, 0, 2);
2230SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2231 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002232SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2233 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002234SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2235 show_temp_offset, store_temp_offset, 0);
2236SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2237 store_temp_type, 0);
2238SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002239SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2240 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002241
2242/*
2243 * nct6775_temp_is_visible uses the index into the following array
2244 * to determine if attributes should be created or not.
2245 * Any change in order or content must be matched.
2246 */
2247static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2248 &sensor_dev_template_temp_input,
2249 &sensor_dev_template_temp_label,
2250 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002251 &sensor_dev_template_temp_beep, /* 3 */
2252 &sensor_dev_template_temp_max, /* 4 */
2253 &sensor_dev_template_temp_max_hyst, /* 5 */
2254 &sensor_dev_template_temp_crit, /* 6 */
2255 &sensor_dev_template_temp_lcrit, /* 7 */
2256 &sensor_dev_template_temp_offset, /* 8 */
2257 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002258 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002259};
2260
Julia Lawallc60fdf82015-12-12 17:36:39 +01002261static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002262 .templates = nct6775_attributes_temp_template,
2263 .is_visible = nct6775_temp_is_visible,
2264 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002265};
2266
Guenter Roeckaa136e52012-12-04 03:26:05 -08002267static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002268show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2269{
2270 struct nct6775_data *data = nct6775_update_device(dev);
2271 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2272
Guenter Roeck2a48e892018-03-26 19:50:31 -07002273 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002274}
2275
2276static ssize_t
2277store_pwm_mode(struct device *dev, struct device_attribute *attr,
2278 const char *buf, size_t count)
2279{
2280 struct nct6775_data *data = dev_get_drvdata(dev);
2281 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2282 int nr = sattr->index;
2283 unsigned long val;
2284 int err;
2285 u8 reg;
2286
2287 err = kstrtoul(buf, 10, &val);
2288 if (err < 0)
2289 return err;
2290
2291 if (val > 1)
2292 return -EINVAL;
2293
Guenter Roeck2a48e892018-03-26 19:50:31 -07002294 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002295 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck2a48e892018-03-26 19:50:31 -07002296 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002297 return -EINVAL;
2298 return count;
2299 }
2300
2301 mutex_lock(&data->update_lock);
2302 data->pwm_mode[nr] = val;
2303 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2304 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck2a48e892018-03-26 19:50:31 -07002305 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002306 reg |= data->PWM_MODE_MASK[nr];
2307 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2308 mutex_unlock(&data->update_lock);
2309 return count;
2310}
2311
2312static ssize_t
2313show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2314{
2315 struct nct6775_data *data = nct6775_update_device(dev);
2316 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2317 int nr = sattr->nr;
2318 int index = sattr->index;
2319 int pwm;
2320
2321 /*
2322 * For automatic fan control modes, show current pwm readings.
2323 * Otherwise, show the configured value.
2324 */
2325 if (index == 0 && data->pwm_enable[nr] > manual)
2326 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2327 else
2328 pwm = data->pwm[index][nr];
2329
2330 return sprintf(buf, "%d\n", pwm);
2331}
2332
2333static ssize_t
2334store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2335 size_t count)
2336{
2337 struct nct6775_data *data = dev_get_drvdata(dev);
2338 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2339 int nr = sattr->nr;
2340 int index = sattr->index;
2341 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002342 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2343 int maxval[7]
2344 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002345 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002346 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002347
2348 err = kstrtoul(buf, 10, &val);
2349 if (err < 0)
2350 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002351 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002352
2353 mutex_lock(&data->update_lock);
2354 data->pwm[index][nr] = val;
2355 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002356 if (index == 2) { /* floor: disable if val == 0 */
2357 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2358 reg &= 0x7f;
2359 if (val)
2360 reg |= 0x80;
2361 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2362 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002363 mutex_unlock(&data->update_lock);
2364 return count;
2365}
2366
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002367/* Returns 0 if OK, -EINVAL otherwise */
2368static int check_trip_points(struct nct6775_data *data, int nr)
2369{
2370 int i;
2371
2372 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2373 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2374 return -EINVAL;
2375 }
2376 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2377 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2378 return -EINVAL;
2379 }
2380 /* validate critical temperature and pwm if enabled (pwm > 0) */
2381 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2382 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2383 data->auto_temp[nr][data->auto_pwm_num] ||
2384 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2385 data->auto_pwm[nr][data->auto_pwm_num])
2386 return -EINVAL;
2387 }
2388 return 0;
2389}
2390
2391static void pwm_update_registers(struct nct6775_data *data, int nr)
2392{
2393 u8 reg;
2394
2395 switch (data->pwm_enable[nr]) {
2396 case off:
2397 case manual:
2398 break;
2399 case speed_cruise:
2400 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2401 reg = (reg & ~data->tolerance_mask) |
2402 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2403 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2404 nct6775_write_value(data, data->REG_TARGET[nr],
2405 data->target_speed[nr] & 0xff);
2406 if (data->REG_TOLERANCE_H) {
2407 reg = (data->target_speed[nr] >> 8) & 0x0f;
2408 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2409 nct6775_write_value(data,
2410 data->REG_TOLERANCE_H[nr],
2411 reg);
2412 }
2413 break;
2414 case thermal_cruise:
2415 nct6775_write_value(data, data->REG_TARGET[nr],
2416 data->target_temp[nr]);
2417 /* intentional */
2418 default:
2419 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2420 reg = (reg & ~data->tolerance_mask) |
2421 data->temp_tolerance[0][nr];
2422 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2423 break;
2424 }
2425}
2426
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002427static ssize_t
2428show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2429{
2430 struct nct6775_data *data = nct6775_update_device(dev);
2431 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2432
2433 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2434}
2435
2436static ssize_t
2437store_pwm_enable(struct device *dev, struct device_attribute *attr,
2438 const char *buf, size_t count)
2439{
2440 struct nct6775_data *data = dev_get_drvdata(dev);
2441 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2442 int nr = sattr->index;
2443 unsigned long val;
2444 int err;
2445 u16 reg;
2446
2447 err = kstrtoul(buf, 10, &val);
2448 if (err < 0)
2449 return err;
2450
2451 if (val > sf4)
2452 return -EINVAL;
2453
2454 if (val == sf3 && data->kind != nct6775)
2455 return -EINVAL;
2456
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002457 if (val == sf4 && check_trip_points(data, nr)) {
2458 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2459 dev_err(dev, "Adjust trip points and try again\n");
2460 return -EINVAL;
2461 }
2462
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002463 mutex_lock(&data->update_lock);
2464 data->pwm_enable[nr] = val;
2465 if (val == off) {
2466 /*
2467 * turn off pwm control: select manual mode, set pwm to maximum
2468 */
2469 data->pwm[0][nr] = 255;
2470 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2471 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002472 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002473 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2474 reg &= 0x0f;
2475 reg |= pwm_enable_to_reg(val) << 4;
2476 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2477 mutex_unlock(&data->update_lock);
2478 return count;
2479}
2480
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002481static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002482show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002483{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002484 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002485
2486 for (i = 0; i < NUM_TEMP; i++) {
2487 if (!(data->have_temp & (1 << i)))
2488 continue;
2489 if (src == data->temp_src[i]) {
2490 sel = i + 1;
2491 break;
2492 }
2493 }
2494
2495 return sprintf(buf, "%d\n", sel);
2496}
2497
2498static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002499show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2500{
2501 struct nct6775_data *data = nct6775_update_device(dev);
2502 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2503 int index = sattr->index;
2504
2505 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2506}
2507
2508static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002509store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2510 const char *buf, size_t count)
2511{
2512 struct nct6775_data *data = nct6775_update_device(dev);
2513 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2514 int nr = sattr->index;
2515 unsigned long val;
2516 int err, reg, src;
2517
2518 err = kstrtoul(buf, 10, &val);
2519 if (err < 0)
2520 return err;
2521 if (val == 0 || val > NUM_TEMP)
2522 return -EINVAL;
2523 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2524 return -EINVAL;
2525
2526 mutex_lock(&data->update_lock);
2527 src = data->temp_src[val - 1];
2528 data->pwm_temp_sel[nr] = src;
2529 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2530 reg &= 0xe0;
2531 reg |= src;
2532 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2533 mutex_unlock(&data->update_lock);
2534
2535 return count;
2536}
2537
2538static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002539show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2540 char *buf)
2541{
2542 struct nct6775_data *data = nct6775_update_device(dev);
2543 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2544 int index = sattr->index;
2545
2546 return show_pwm_temp_sel_common(data, buf,
2547 data->pwm_weight_temp_sel[index]);
2548}
2549
2550static ssize_t
2551store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2552 const char *buf, size_t count)
2553{
2554 struct nct6775_data *data = nct6775_update_device(dev);
2555 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2556 int nr = sattr->index;
2557 unsigned long val;
2558 int err, reg, src;
2559
2560 err = kstrtoul(buf, 10, &val);
2561 if (err < 0)
2562 return err;
2563 if (val > NUM_TEMP)
2564 return -EINVAL;
2565 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2566 !data->temp_src[val - 1]))
2567 return -EINVAL;
2568
2569 mutex_lock(&data->update_lock);
2570 if (val) {
2571 src = data->temp_src[val - 1];
2572 data->pwm_weight_temp_sel[nr] = src;
2573 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2574 reg &= 0xe0;
2575 reg |= (src | 0x80);
2576 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2577 } else {
2578 data->pwm_weight_temp_sel[nr] = 0;
2579 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2580 reg &= 0x7f;
2581 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2582 }
2583 mutex_unlock(&data->update_lock);
2584
2585 return count;
2586}
2587
2588static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002589show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2590{
2591 struct nct6775_data *data = nct6775_update_device(dev);
2592 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2593
2594 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2595}
2596
2597static ssize_t
2598store_target_temp(struct device *dev, struct device_attribute *attr,
2599 const char *buf, size_t count)
2600{
2601 struct nct6775_data *data = dev_get_drvdata(dev);
2602 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2603 int nr = sattr->index;
2604 unsigned long val;
2605 int err;
2606
2607 err = kstrtoul(buf, 10, &val);
2608 if (err < 0)
2609 return err;
2610
2611 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2612 data->target_temp_mask);
2613
2614 mutex_lock(&data->update_lock);
2615 data->target_temp[nr] = val;
2616 pwm_update_registers(data, nr);
2617 mutex_unlock(&data->update_lock);
2618 return count;
2619}
2620
2621static ssize_t
2622show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2623{
2624 struct nct6775_data *data = nct6775_update_device(dev);
2625 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2626 int nr = sattr->index;
2627
2628 return sprintf(buf, "%d\n",
2629 fan_from_reg16(data->target_speed[nr],
2630 data->fan_div[nr]));
2631}
2632
2633static ssize_t
2634store_target_speed(struct device *dev, struct device_attribute *attr,
2635 const char *buf, size_t count)
2636{
2637 struct nct6775_data *data = dev_get_drvdata(dev);
2638 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2639 int nr = sattr->index;
2640 unsigned long val;
2641 int err;
2642 u16 speed;
2643
2644 err = kstrtoul(buf, 10, &val);
2645 if (err < 0)
2646 return err;
2647
2648 val = clamp_val(val, 0, 1350000U);
2649 speed = fan_to_reg(val, data->fan_div[nr]);
2650
2651 mutex_lock(&data->update_lock);
2652 data->target_speed[nr] = speed;
2653 pwm_update_registers(data, nr);
2654 mutex_unlock(&data->update_lock);
2655 return count;
2656}
2657
2658static ssize_t
2659show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2660 char *buf)
2661{
2662 struct nct6775_data *data = nct6775_update_device(dev);
2663 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2664 int nr = sattr->nr;
2665 int index = sattr->index;
2666
2667 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2668}
2669
2670static ssize_t
2671store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2672 const char *buf, size_t count)
2673{
2674 struct nct6775_data *data = dev_get_drvdata(dev);
2675 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2676 int nr = sattr->nr;
2677 int index = sattr->index;
2678 unsigned long val;
2679 int err;
2680
2681 err = kstrtoul(buf, 10, &val);
2682 if (err < 0)
2683 return err;
2684
2685 /* Limit tolerance as needed */
2686 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2687
2688 mutex_lock(&data->update_lock);
2689 data->temp_tolerance[index][nr] = val;
2690 if (index)
2691 pwm_update_registers(data, nr);
2692 else
2693 nct6775_write_value(data,
2694 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2695 val);
2696 mutex_unlock(&data->update_lock);
2697 return count;
2698}
2699
2700/*
2701 * Fan speed tolerance is a tricky beast, since the associated register is
2702 * a tick counter, but the value is reported and configured as rpm.
2703 * Compute resulting low and high rpm values and report the difference.
2704 */
2705static ssize_t
2706show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2707 char *buf)
2708{
2709 struct nct6775_data *data = nct6775_update_device(dev);
2710 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2711 int nr = sattr->index;
2712 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2713 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2714 int tolerance;
2715
2716 if (low <= 0)
2717 low = 1;
2718 if (high > 0xffff)
2719 high = 0xffff;
2720 if (high < low)
2721 high = low;
2722
2723 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2724 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2725
2726 return sprintf(buf, "%d\n", tolerance);
2727}
2728
2729static ssize_t
2730store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2731 const char *buf, size_t count)
2732{
2733 struct nct6775_data *data = dev_get_drvdata(dev);
2734 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2735 int nr = sattr->index;
2736 unsigned long val;
2737 int err;
2738 int low, high;
2739
2740 err = kstrtoul(buf, 10, &val);
2741 if (err < 0)
2742 return err;
2743
2744 high = fan_from_reg16(data->target_speed[nr],
2745 data->fan_div[nr]) + val;
2746 low = fan_from_reg16(data->target_speed[nr],
2747 data->fan_div[nr]) - val;
2748 if (low <= 0)
2749 low = 1;
2750 if (high < low)
2751 high = low;
2752
2753 val = (fan_to_reg(low, data->fan_div[nr]) -
2754 fan_to_reg(high, data->fan_div[nr])) / 2;
2755
2756 /* Limit tolerance as needed */
2757 val = clamp_val(val, 0, data->speed_tolerance_limit);
2758
2759 mutex_lock(&data->update_lock);
2760 data->target_speed_tolerance[nr] = val;
2761 pwm_update_registers(data, nr);
2762 mutex_unlock(&data->update_lock);
2763 return count;
2764}
2765
Guenter Roeckf73cf632013-03-18 09:22:50 -07002766SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2767SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2768 store_pwm_mode, 0);
2769SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2770 store_pwm_enable, 0);
2771SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2772 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2773SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2774 show_target_temp, store_target_temp, 0);
2775SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2776 show_target_speed, store_target_speed, 0);
2777SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2778 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002779
2780/* Smart Fan registers */
2781
2782static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002783show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2784{
2785 struct nct6775_data *data = nct6775_update_device(dev);
2786 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2787 int nr = sattr->nr;
2788 int index = sattr->index;
2789
2790 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2791}
2792
2793static ssize_t
2794store_weight_temp(struct device *dev, struct device_attribute *attr,
2795 const char *buf, size_t count)
2796{
2797 struct nct6775_data *data = dev_get_drvdata(dev);
2798 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2799 int nr = sattr->nr;
2800 int index = sattr->index;
2801 unsigned long val;
2802 int err;
2803
2804 err = kstrtoul(buf, 10, &val);
2805 if (err < 0)
2806 return err;
2807
2808 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2809
2810 mutex_lock(&data->update_lock);
2811 data->weight_temp[index][nr] = val;
2812 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2813 mutex_unlock(&data->update_lock);
2814 return count;
2815}
2816
Guenter Roeckf73cf632013-03-18 09:22:50 -07002817SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2818 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2819SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2820 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2821SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2822 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2823SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2824 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2825SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2826 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2827SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2828 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002829
2830static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002831show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2832{
2833 struct nct6775_data *data = nct6775_update_device(dev);
2834 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2835 int nr = sattr->nr;
2836 int index = sattr->index;
2837
2838 return sprintf(buf, "%d\n",
2839 step_time_from_reg(data->fan_time[index][nr],
2840 data->pwm_mode[nr]));
2841}
2842
2843static ssize_t
2844store_fan_time(struct device *dev, struct device_attribute *attr,
2845 const char *buf, size_t count)
2846{
2847 struct nct6775_data *data = dev_get_drvdata(dev);
2848 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2849 int nr = sattr->nr;
2850 int index = sattr->index;
2851 unsigned long val;
2852 int err;
2853
2854 err = kstrtoul(buf, 10, &val);
2855 if (err < 0)
2856 return err;
2857
2858 val = step_time_to_reg(val, data->pwm_mode[nr]);
2859 mutex_lock(&data->update_lock);
2860 data->fan_time[index][nr] = val;
2861 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2862 mutex_unlock(&data->update_lock);
2863 return count;
2864}
2865
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002866static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002867show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2868{
2869 struct nct6775_data *data = nct6775_update_device(dev);
2870 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2871
2872 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2873}
2874
2875static ssize_t
2876store_auto_pwm(struct device *dev, struct device_attribute *attr,
2877 const char *buf, size_t count)
2878{
2879 struct nct6775_data *data = dev_get_drvdata(dev);
2880 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2881 int nr = sattr->nr;
2882 int point = sattr->index;
2883 unsigned long val;
2884 int err;
2885 u8 reg;
2886
2887 err = kstrtoul(buf, 10, &val);
2888 if (err < 0)
2889 return err;
2890 if (val > 255)
2891 return -EINVAL;
2892
2893 if (point == data->auto_pwm_num) {
2894 if (data->kind != nct6775 && !val)
2895 return -EINVAL;
2896 if (data->kind != nct6779 && val)
2897 val = 0xff;
2898 }
2899
2900 mutex_lock(&data->update_lock);
2901 data->auto_pwm[nr][point] = val;
2902 if (point < data->auto_pwm_num) {
2903 nct6775_write_value(data,
2904 NCT6775_AUTO_PWM(data, nr, point),
2905 data->auto_pwm[nr][point]);
2906 } else {
2907 switch (data->kind) {
2908 case nct6775:
2909 /* disable if needed (pwm == 0) */
2910 reg = nct6775_read_value(data,
2911 NCT6775_REG_CRITICAL_ENAB[nr]);
2912 if (val)
2913 reg |= 0x02;
2914 else
2915 reg &= ~0x02;
2916 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2917 reg);
2918 break;
2919 case nct6776:
2920 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002921 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002922 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002923 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002924 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002925 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002926 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002927 val);
2928 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002929 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002930 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002931 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002932 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002933 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002934 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002935 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002936 reg);
2937 break;
2938 }
2939 }
2940 mutex_unlock(&data->update_lock);
2941 return count;
2942}
2943
2944static ssize_t
2945show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2946{
2947 struct nct6775_data *data = nct6775_update_device(dev);
2948 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2949 int nr = sattr->nr;
2950 int point = sattr->index;
2951
2952 /*
2953 * We don't know for sure if the temperature is signed or unsigned.
2954 * Assume it is unsigned.
2955 */
2956 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2957}
2958
2959static ssize_t
2960store_auto_temp(struct device *dev, struct device_attribute *attr,
2961 const char *buf, size_t count)
2962{
2963 struct nct6775_data *data = dev_get_drvdata(dev);
2964 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2965 int nr = sattr->nr;
2966 int point = sattr->index;
2967 unsigned long val;
2968 int err;
2969
2970 err = kstrtoul(buf, 10, &val);
2971 if (err)
2972 return err;
2973 if (val > 255000)
2974 return -EINVAL;
2975
2976 mutex_lock(&data->update_lock);
2977 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2978 if (point < data->auto_pwm_num) {
2979 nct6775_write_value(data,
2980 NCT6775_AUTO_TEMP(data, nr, point),
2981 data->auto_temp[nr][point]);
2982 } else {
2983 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2984 data->auto_temp[nr][point]);
2985 }
2986 mutex_unlock(&data->update_lock);
2987 return count;
2988}
2989
Guenter Roeckf73cf632013-03-18 09:22:50 -07002990static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2991 struct attribute *attr, int index)
2992{
2993 struct device *dev = container_of(kobj, struct device, kobj);
2994 struct nct6775_data *data = dev_get_drvdata(dev);
2995 int pwm = index / 36; /* pwm index */
2996 int nr = index % 36; /* attribute index */
2997
2998 if (!(data->has_pwm & (1 << pwm)))
2999 return 0;
3000
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003001 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3002 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3003 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003004 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3005 return 0;
3006 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3007 return 0;
3008 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3009 return 0;
3010
3011 if (nr >= 22 && nr <= 35) { /* auto point */
3012 int api = (nr - 22) / 2; /* auto point index */
3013
3014 if (api > data->auto_pwm_num)
3015 return 0;
3016 }
3017 return attr->mode;
3018}
3019
3020SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3021 show_fan_time, store_fan_time, 0, 0);
3022SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3023 show_fan_time, store_fan_time, 0, 1);
3024SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3025 show_fan_time, store_fan_time, 0, 2);
3026SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3027 store_pwm, 0, 1);
3028SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3029 store_pwm, 0, 2);
3030SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3031 show_temp_tolerance, store_temp_tolerance, 0, 0);
3032SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3033 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3034 0, 1);
3035
3036SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3037 0, 3);
3038
3039SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3040 store_pwm, 0, 4);
3041
3042SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3043 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3044SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3045 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3046
3047SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3048 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3049SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3050 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3051
3052SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3053 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3054SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3055 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3056
3057SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3058 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3059SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3060 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3061
3062SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3063 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3064SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3065 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3066
3067SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3068 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3069SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3070 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3071
3072SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3073 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3074SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3075 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3076
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003077/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003078 * nct6775_pwm_is_visible uses the index into the following array
3079 * to determine if attributes should be created or not.
3080 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003081 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003082static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3083 &sensor_dev_template_pwm,
3084 &sensor_dev_template_pwm_mode,
3085 &sensor_dev_template_pwm_enable,
3086 &sensor_dev_template_pwm_temp_sel,
3087 &sensor_dev_template_pwm_temp_tolerance,
3088 &sensor_dev_template_pwm_crit_temp_tolerance,
3089 &sensor_dev_template_pwm_target_temp,
3090 &sensor_dev_template_fan_target,
3091 &sensor_dev_template_fan_tolerance,
3092 &sensor_dev_template_pwm_stop_time,
3093 &sensor_dev_template_pwm_step_up_time,
3094 &sensor_dev_template_pwm_step_down_time,
3095 &sensor_dev_template_pwm_start,
3096 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003097 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003098 &sensor_dev_template_pwm_weight_temp_step,
3099 &sensor_dev_template_pwm_weight_temp_step_tol,
3100 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003101 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003102 &sensor_dev_template_pwm_max, /* 19 */
3103 &sensor_dev_template_pwm_step, /* 20 */
3104 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3105 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3106 &sensor_dev_template_pwm_auto_point1_temp,
3107 &sensor_dev_template_pwm_auto_point2_pwm,
3108 &sensor_dev_template_pwm_auto_point2_temp,
3109 &sensor_dev_template_pwm_auto_point3_pwm,
3110 &sensor_dev_template_pwm_auto_point3_temp,
3111 &sensor_dev_template_pwm_auto_point4_pwm,
3112 &sensor_dev_template_pwm_auto_point4_temp,
3113 &sensor_dev_template_pwm_auto_point5_pwm,
3114 &sensor_dev_template_pwm_auto_point5_temp,
3115 &sensor_dev_template_pwm_auto_point6_pwm,
3116 &sensor_dev_template_pwm_auto_point6_temp,
3117 &sensor_dev_template_pwm_auto_point7_pwm,
3118 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003119
Guenter Roeckf73cf632013-03-18 09:22:50 -07003120 NULL
3121};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003122
Julia Lawallc60fdf82015-12-12 17:36:39 +01003123static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003124 .templates = nct6775_attributes_pwm_template,
3125 .is_visible = nct6775_pwm_is_visible,
3126 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003127};
3128
3129static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003130show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3131{
3132 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003133
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003134 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3135}
3136
3137static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3138
Guenter Roecka6bd5872012-12-04 03:13:34 -08003139/* Case open detection */
3140
3141static ssize_t
3142clear_caseopen(struct device *dev, struct device_attribute *attr,
3143 const char *buf, size_t count)
3144{
3145 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003146 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3147 unsigned long val;
3148 u8 reg;
3149 int ret;
3150
3151 if (kstrtoul(buf, 10, &val) || val != 0)
3152 return -EINVAL;
3153
3154 mutex_lock(&data->update_lock);
3155
3156 /*
3157 * Use CR registers to clear caseopen status.
3158 * The CR registers are the same for all chips, and not all chips
3159 * support clearing the caseopen status through "regular" registers.
3160 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003161 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003162 if (ret) {
3163 count = ret;
3164 goto error;
3165 }
3166
Guenter Roeckdf612d52013-07-08 13:15:04 -07003167 superio_select(data->sioreg, NCT6775_LD_ACPI);
3168 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003169 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003170 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003171 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003172 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3173 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003174
3175 data->valid = false; /* Force cache refresh */
3176error:
3177 mutex_unlock(&data->update_lock);
3178 return count;
3179}
3180
Guenter Roeckf73cf632013-03-18 09:22:50 -07003181static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3182 clear_caseopen, INTRUSION_ALARM_BASE);
3183static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3184 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003185static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3186 store_beep, INTRUSION_ALARM_BASE);
3187static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3188 store_beep, INTRUSION_ALARM_BASE + 1);
3189static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3190 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003191
3192static umode_t nct6775_other_is_visible(struct kobject *kobj,
3193 struct attribute *attr, int index)
3194{
3195 struct device *dev = container_of(kobj, struct device, kobj);
3196 struct nct6775_data *data = dev_get_drvdata(dev);
3197
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003198 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003199 return 0;
3200
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003201 if (index == 1 || index == 2) {
3202 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003203 return 0;
3204 }
3205
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003206 if (index == 3 || index == 4) {
3207 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003208 return 0;
3209 }
3210
Guenter Roeckf73cf632013-03-18 09:22:50 -07003211 return attr->mode;
3212}
3213
3214/*
3215 * nct6775_other_is_visible uses the index into the following array
3216 * to determine if attributes should be created or not.
3217 * Any change in order or content must be matched.
3218 */
3219static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003220 &dev_attr_cpu0_vid.attr, /* 0 */
3221 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3222 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3223 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3224 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3225 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003226
3227 NULL
3228};
3229
3230static const struct attribute_group nct6775_group_other = {
3231 .attrs = nct6775_attributes_other,
3232 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003233};
3234
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003235static inline void nct6775_init_device(struct nct6775_data *data)
3236{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003237 int i;
3238 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003239
3240 /* Start monitoring if needed */
3241 if (data->REG_CONFIG) {
3242 tmp = nct6775_read_value(data, data->REG_CONFIG);
3243 if (!(tmp & 0x01))
3244 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3245 }
3246
Guenter Roeckaa136e52012-12-04 03:26:05 -08003247 /* Enable temperature sensors if needed */
3248 for (i = 0; i < NUM_TEMP; i++) {
3249 if (!(data->have_temp & (1 << i)))
3250 continue;
3251 if (!data->reg_temp_config[i])
3252 continue;
3253 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3254 if (tmp & 0x01)
3255 nct6775_write_value(data, data->reg_temp_config[i],
3256 tmp & 0xfe);
3257 }
3258
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003259 /* Enable VBAT monitoring if needed */
3260 tmp = nct6775_read_value(data, data->REG_VBAT);
3261 if (!(tmp & 0x01))
3262 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003263
3264 diode = nct6775_read_value(data, data->REG_DIODE);
3265
3266 for (i = 0; i < data->temp_fixed_num; i++) {
3267 if (!(data->have_temp_fixed & (1 << i)))
3268 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003269 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3270 data->temp_type[i]
3271 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003272 else /* thermistor */
3273 data->temp_type[i] = 4;
3274 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003275}
3276
Guenter Roeckf73cf632013-03-18 09:22:50 -07003277static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003278nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003279{
David Bartley578ab5f2013-06-24 22:28:28 -07003280 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3281 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003282 int sioreg = data->sioreg;
3283 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003284
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003285 /* Store SIO_REG_ENABLE for use during resume */
3286 superio_select(sioreg, NCT6775_LD_HWM);
3287 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3288
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003289 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3290 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003291 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003292
3293 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003294 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003295
3296 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003297 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003298 fan4min = false;
3299 fan5pin = false;
3300 fan6pin = false;
3301 pwm4pin = false;
3302 pwm5pin = false;
3303 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003304 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003305 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003306 const char *board_vendor, *board_name;
3307
3308 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3309 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3310
3311 if (board_name && board_vendor &&
3312 !strcmp(board_vendor, "ASRock")) {
3313 /*
3314 * Auxiliary fan monitoring is not enabled on ASRock
3315 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3316 * Observed with BIOS version 2.00.
3317 */
3318 if (!strcmp(board_name, "Z77 Pro4-M")) {
3319 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3320 data->sio_reg_enable |= 0xe0;
3321 superio_outb(sioreg, SIO_REG_ENABLE,
3322 data->sio_reg_enable);
3323 }
3324 }
3325 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003326
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003327 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003328 fan3pin = gpok;
3329 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003330 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003331
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003332 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003333 fan4pin = gpok;
3334 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003335 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003336
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003337 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003338 fan5pin = gpok;
3339 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003340 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003341
3342 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003343 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003344 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003345 pwm4pin = false;
3346 pwm5pin = false;
3347 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003348 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003349 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003350 fan3pin = !(regval & 0x80);
3351 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003352
3353 fan4pin = false;
3354 fan4min = false;
3355 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003356 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003357 pwm4pin = false;
3358 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003359 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003360 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003361 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003362
3363 fan3pin = !(regval & (1 << 5));
3364 fan4pin = !(regval & (1 << 6));
3365 fan5pin = !(regval & (1 << 7));
3366
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003367 pwm3pin = !(regval & (1 << 0));
3368 pwm4pin = !(regval & (1 << 1));
3369 pwm5pin = !(regval & (1 << 2));
3370
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003371 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003372
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003373 if (data->kind == nct6791 || data->kind == nct6792 ||
3374 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003375 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003376 fan6pin = (regval & (1 << 1));
3377 pwm6pin = (regval & (1 << 0));
3378 } else { /* NCT6779D */
3379 fan6pin = false;
3380 pwm6pin = false;
3381 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003382 }
3383
David Bartley578ab5f2013-06-24 22:28:28 -07003384 /* fan 1 and 2 (0x03) are always present */
3385 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3386 (fan5pin << 4) | (fan6pin << 5);
3387 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3388 (fan5pin << 4);
3389 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3390 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003391}
3392
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003393static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3394 int *available, int *mask)
3395{
3396 int i;
3397 u8 src;
3398
3399 for (i = 0; i < data->pwm_num && *available; i++) {
3400 int index;
3401
3402 if (!regp[i])
3403 continue;
3404 src = nct6775_read_value(data, regp[i]);
3405 src &= 0x1f;
3406 if (!src || (*mask & (1 << src)))
3407 continue;
3408 if (src >= data->temp_label_num ||
3409 !strlen(data->temp_label[src]))
3410 continue;
3411
3412 index = __ffs(*available);
3413 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3414 *available &= ~(1 << index);
3415 *mask |= 1 << src;
3416 }
3417}
3418
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003419static int nct6775_probe(struct platform_device *pdev)
3420{
3421 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003422 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003423 struct nct6775_data *data;
3424 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003425 int i, s, err = 0;
3426 int src, mask, available;
3427 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003428 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003429 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003430 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003431 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003432 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003433 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003434 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003435
3436 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3437 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3438 DRVNAME))
3439 return -EBUSY;
3440
3441 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3442 GFP_KERNEL);
3443 if (!data)
3444 return -ENOMEM;
3445
3446 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003447 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003448 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003449 mutex_init(&data->update_lock);
3450 data->name = nct6775_device_names[data->kind];
3451 data->bank = 0xff; /* Force initial bank selection */
3452 platform_set_drvdata(pdev, data);
3453
3454 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003455 case nct6106:
3456 data->in_num = 9;
3457 data->pwm_num = 3;
3458 data->auto_pwm_num = 4;
3459 data->temp_fixed_num = 3;
3460 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003461 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003462
3463 data->fan_from_reg = fan_from_reg13;
3464 data->fan_from_reg_min = fan_from_reg13;
3465
3466 data->temp_label = nct6776_temp_label;
3467 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3468
3469 data->REG_VBAT = NCT6106_REG_VBAT;
3470 data->REG_DIODE = NCT6106_REG_DIODE;
3471 data->DIODE_MASK = NCT6106_DIODE_MASK;
3472 data->REG_VIN = NCT6106_REG_IN;
3473 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3474 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3475 data->REG_TARGET = NCT6106_REG_TARGET;
3476 data->REG_FAN = NCT6106_REG_FAN;
3477 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3478 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3479 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3480 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3481 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3482 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3483 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
Björn Gerhart71faaeb2019-07-15 18:33:55 +02003484 data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003485 data->REG_PWM[0] = NCT6106_REG_PWM;
3486 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3487 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3488 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3489 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3490 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3491 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3492 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3493 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3494 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3495 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3496 data->REG_CRITICAL_TEMP_TOLERANCE
3497 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3498 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3499 data->CRITICAL_PWM_ENABLE_MASK
3500 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3501 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3502 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3503 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3504 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3505 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3506 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3507 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3508 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3509 data->REG_ALARM = NCT6106_REG_ALARM;
3510 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003511 data->REG_BEEP = NCT6106_REG_BEEP;
3512 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003513
3514 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003515 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003516 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003517 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003518 reg_temp_over = NCT6106_REG_TEMP_OVER;
3519 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3520 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3521 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3522 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003523 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3524 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003525
3526 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003527 case nct6775:
3528 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003529 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003530 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003531 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003532 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003533 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003534 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003535
3536 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003537 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003538
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003539 data->fan_from_reg = fan_from_reg16;
3540 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003541 data->target_temp_mask = 0x7f;
3542 data->tolerance_mask = 0x0f;
3543 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003544
Guenter Roeckaa136e52012-12-04 03:26:05 -08003545 data->temp_label = nct6775_temp_label;
3546 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3547
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003548 data->REG_CONFIG = NCT6775_REG_CONFIG;
3549 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003550 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003551 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003552 data->REG_VIN = NCT6775_REG_IN;
3553 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3554 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003555 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003556 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003557 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003558 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003559 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003560 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003561 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3562 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3563 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003564 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003565 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3566 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3567 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3568 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003569 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003570 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3571 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3572 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003573 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3574 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3575 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3576 data->REG_CRITICAL_TEMP_TOLERANCE
3577 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003578 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3579 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003580 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003581 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3582 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3583 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3584 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003585 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003586 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003587
3588 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003589 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003590 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003591 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003592 reg_temp_over = NCT6775_REG_TEMP_OVER;
3593 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3594 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3595 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3596 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3597
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003598 break;
3599 case nct6776:
3600 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003601 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003602 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003603 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003604 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003605 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003606 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003607
3608 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003609 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003610
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003611 data->fan_from_reg = fan_from_reg13;
3612 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003613 data->target_temp_mask = 0xff;
3614 data->tolerance_mask = 0x07;
3615 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003616
Guenter Roeckaa136e52012-12-04 03:26:05 -08003617 data->temp_label = nct6776_temp_label;
3618 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3619
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003620 data->REG_CONFIG = NCT6775_REG_CONFIG;
3621 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003622 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003623 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003624 data->REG_VIN = NCT6775_REG_IN;
3625 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3626 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003627 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003628 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003629 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003630 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003631 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003632 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003633 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003634 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3635 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003636 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003637 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003638 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3639 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003640 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3641 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003642 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3643 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3644 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003645 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3646 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3647 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3648 data->REG_CRITICAL_TEMP_TOLERANCE
3649 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003650 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3651 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003652 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003653 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3654 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3655 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3656 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003657 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003658 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003659
3660 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003661 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003662 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003663 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003664 reg_temp_over = NCT6775_REG_TEMP_OVER;
3665 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3666 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3667 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3668 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3669
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003670 break;
3671 case nct6779:
3672 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003673 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003674 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003675 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003676 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003677 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003678 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003679
3680 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003681 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003682
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003683 data->fan_from_reg = fan_from_reg13;
3684 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003685 data->target_temp_mask = 0xff;
3686 data->tolerance_mask = 0x07;
3687 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003688
Guenter Roeckaa136e52012-12-04 03:26:05 -08003689 data->temp_label = nct6779_temp_label;
Guenter Roeck9a383712015-08-29 15:29:25 -07003690 data->temp_label_num = NCT6779_NUM_LABELS;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003691
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003692 data->REG_CONFIG = NCT6775_REG_CONFIG;
3693 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003694 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003695 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003696 data->REG_VIN = NCT6779_REG_IN;
3697 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3698 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003699 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003700 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003701 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003702 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003703 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003704 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003705 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003706 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3707 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003708 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003709 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003710 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3711 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003712 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3713 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003714 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3715 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3716 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003717 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3718 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3719 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3720 data->REG_CRITICAL_TEMP_TOLERANCE
3721 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003722 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3723 data->CRITICAL_PWM_ENABLE_MASK
3724 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3725 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003726 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3727 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003728 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003729 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3730 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3731 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3732 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003733 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003734 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003735
3736 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003737 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003738 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003739 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003740 reg_temp_over = NCT6779_REG_TEMP_OVER;
3741 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3742 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3743 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3744 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3745
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003746 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003747 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003748 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003749 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003750 data->in_num = 15;
3751 data->pwm_num = 6;
3752 data->auto_pwm_num = 4;
3753 data->has_fan_div = false;
3754 data->temp_fixed_num = 6;
3755 data->num_temp_alarms = 2;
3756 data->num_temp_beeps = 2;
3757
3758 data->ALARM_BITS = NCT6791_ALARM_BITS;
3759 data->BEEP_BITS = NCT6779_BEEP_BITS;
3760
3761 data->fan_from_reg = fan_from_reg13;
3762 data->fan_from_reg_min = fan_from_reg13;
3763 data->target_temp_mask = 0xff;
3764 data->tolerance_mask = 0x07;
3765 data->speed_tolerance_limit = 63;
3766
Guenter Roeck50224f42015-10-30 07:52:39 -07003767 switch (data->kind) {
3768 default:
3769 case nct6791:
3770 data->temp_label = nct6779_temp_label;
3771 break;
3772 case nct6792:
3773 data->temp_label = nct6792_temp_label;
3774 break;
3775 case nct6793:
3776 data->temp_label = nct6793_temp_label;
3777 break;
3778 }
Guenter Roeck9a383712015-08-29 15:29:25 -07003779 data->temp_label_num = NCT6791_NUM_LABELS;
David Bartley578ab5f2013-06-24 22:28:28 -07003780
3781 data->REG_CONFIG = NCT6775_REG_CONFIG;
3782 data->REG_VBAT = NCT6775_REG_VBAT;
3783 data->REG_DIODE = NCT6775_REG_DIODE;
3784 data->DIODE_MASK = NCT6775_DIODE_MASK;
3785 data->REG_VIN = NCT6779_REG_IN;
3786 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3787 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3788 data->REG_TARGET = NCT6775_REG_TARGET;
3789 data->REG_FAN = NCT6779_REG_FAN;
3790 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3791 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3792 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3793 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3794 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003795 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3796 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003797 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3798 data->REG_PWM[0] = NCT6775_REG_PWM;
3799 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3800 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003801 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3802 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003803 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3804 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3805 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3806 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3807 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3808 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3809 data->REG_CRITICAL_TEMP_TOLERANCE
3810 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3811 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3812 data->CRITICAL_PWM_ENABLE_MASK
3813 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3814 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3815 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3816 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3817 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003818 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3819 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3820 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3821 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003822 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003823 if (data->kind == nct6791)
3824 data->REG_BEEP = NCT6776_REG_BEEP;
3825 else
3826 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003827
3828 reg_temp = NCT6779_REG_TEMP;
3829 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003830 if (data->kind == nct6791) {
3831 reg_temp_mon = NCT6779_REG_TEMP_MON;
3832 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3833 } else {
3834 reg_temp_mon = NCT6792_REG_TEMP_MON;
3835 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3836 }
David Bartley578ab5f2013-06-24 22:28:28 -07003837 reg_temp_over = NCT6779_REG_TEMP_OVER;
3838 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3839 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3840 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3841 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3842
3843 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003844 default:
3845 return -ENODEV;
3846 }
3847 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003848 data->have_temp = 0;
3849
3850 /*
3851 * On some boards, not all available temperature sources are monitored,
3852 * even though some of the monitoring registers are unused.
3853 * Get list of unused monitoring registers, then detect if any fan
3854 * controls are configured to use unmonitored temperature sources.
3855 * If so, assign the unmonitored temperature sources to available
3856 * monitoring registers.
3857 */
3858 mask = 0;
3859 available = 0;
3860 for (i = 0; i < num_reg_temp; i++) {
3861 if (reg_temp[i] == 0)
3862 continue;
3863
3864 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3865 if (!src || (mask & (1 << src)))
3866 available |= 1 << i;
3867
3868 mask |= 1 << src;
3869 }
3870
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003871 /*
3872 * Now find unmonitored temperature registers and enable monitoring
3873 * if additional monitoring registers are available.
3874 */
3875 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3876 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3877
Guenter Roeckaa136e52012-12-04 03:26:05 -08003878 mask = 0;
3879 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3880 for (i = 0; i < num_reg_temp; i++) {
3881 if (reg_temp[i] == 0)
3882 continue;
3883
3884 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3885 if (!src || (mask & (1 << src)))
3886 continue;
3887
3888 if (src >= data->temp_label_num ||
3889 !strlen(data->temp_label[src])) {
3890 dev_info(dev,
3891 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3892 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3893 continue;
3894 }
3895
3896 mask |= 1 << src;
3897
3898 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3899 if (src <= data->temp_fixed_num) {
3900 data->have_temp |= 1 << (src - 1);
3901 data->have_temp_fixed |= 1 << (src - 1);
3902 data->reg_temp[0][src - 1] = reg_temp[i];
3903 data->reg_temp[1][src - 1] = reg_temp_over[i];
3904 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003905 if (reg_temp_crit_h && reg_temp_crit_h[i])
3906 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3907 else if (reg_temp_crit[src - 1])
3908 data->reg_temp[3][src - 1]
3909 = reg_temp_crit[src - 1];
3910 if (reg_temp_crit_l && reg_temp_crit_l[i])
3911 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003912 data->reg_temp_config[src - 1] = reg_temp_config[i];
3913 data->temp_src[src - 1] = src;
3914 continue;
3915 }
3916
3917 if (s >= NUM_TEMP)
3918 continue;
3919
3920 /* Use dynamic index for other sources */
3921 data->have_temp |= 1 << s;
3922 data->reg_temp[0][s] = reg_temp[i];
3923 data->reg_temp[1][s] = reg_temp_over[i];
3924 data->reg_temp[2][s] = reg_temp_hyst[i];
3925 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003926 if (reg_temp_crit_h && reg_temp_crit_h[i])
3927 data->reg_temp[3][s] = reg_temp_crit_h[i];
3928 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003929 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003930 if (reg_temp_crit_l && reg_temp_crit_l[i])
3931 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003932
3933 data->temp_src[s] = src;
3934 s++;
3935 }
3936
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003937 /*
3938 * Repeat with temperatures used for fan control.
3939 * This set of registers does not support limits.
3940 */
3941 for (i = 0; i < num_reg_temp_mon; i++) {
3942 if (reg_temp_mon[i] == 0)
3943 continue;
3944
3945 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07003946 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003947 continue;
3948
3949 if (src >= data->temp_label_num ||
3950 !strlen(data->temp_label[src])) {
3951 dev_info(dev,
3952 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3953 src, i, data->REG_TEMP_SEL[i],
3954 reg_temp_mon[i]);
3955 continue;
3956 }
3957
Guenter Roeck7ce41902016-09-11 12:42:52 -07003958 /*
3959 * For virtual temperature sources, the 'virtual' temperature
3960 * for each fan reflects a different temperature, and there
3961 * are no duplicates.
3962 */
3963 if (src != TEMP_SOURCE_VIRTUAL) {
3964 if (mask & (1 << src))
3965 continue;
3966 mask |= 1 << src;
3967 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003968
3969 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3970 if (src <= data->temp_fixed_num) {
3971 if (data->have_temp & (1 << (src - 1)))
3972 continue;
3973 data->have_temp |= 1 << (src - 1);
3974 data->have_temp_fixed |= 1 << (src - 1);
3975 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3976 data->temp_src[src - 1] = src;
3977 continue;
3978 }
3979
3980 if (s >= NUM_TEMP)
3981 continue;
3982
3983 /* Use dynamic index for other sources */
3984 data->have_temp |= 1 << s;
3985 data->reg_temp[0][s] = reg_temp_mon[i];
3986 data->temp_src[s] = src;
3987 s++;
3988 }
3989
Guenter Roeckaa136e52012-12-04 03:26:05 -08003990#ifdef USE_ALTERNATE
3991 /*
3992 * Go through the list of alternate temp registers and enable
3993 * if possible.
3994 * The temperature is already monitored if the respective bit in <mask>
3995 * is set.
3996 */
3997 for (i = 0; i < data->temp_label_num - 1; i++) {
3998 if (!reg_temp_alternate[i])
3999 continue;
4000 if (mask & (1 << (i + 1)))
4001 continue;
4002 if (i < data->temp_fixed_num) {
4003 if (data->have_temp & (1 << i))
4004 continue;
4005 data->have_temp |= 1 << i;
4006 data->have_temp_fixed |= 1 << i;
4007 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07004008 if (i < num_reg_temp) {
4009 data->reg_temp[1][i] = reg_temp_over[i];
4010 data->reg_temp[2][i] = reg_temp_hyst[i];
4011 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004012 data->temp_src[i] = i + 1;
4013 continue;
4014 }
4015
4016 if (s >= NUM_TEMP) /* Abort if no more space */
4017 break;
4018
4019 data->have_temp |= 1 << s;
4020 data->reg_temp[0][s] = reg_temp_alternate[i];
4021 data->temp_src[s] = i + 1;
4022 s++;
4023 }
4024#endif /* USE_ALTERNATE */
4025
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004026 /* Initialize the chip */
4027 nct6775_init_device(data);
4028
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004029 err = superio_enter(sio_data->sioreg);
4030 if (err)
4031 return err;
4032
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004033 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4034 switch (data->kind) {
4035 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004036 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004037 break;
4038 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004039 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004040 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004041 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004042 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004043 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004044 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004045 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004046 break;
4047 }
4048
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004049 /*
4050 * Read VID value
4051 * We can get the VID input values directly at logical device D 0xe3.
4052 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004053 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004054 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4055 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4056 data->vrm = vid_which_vrm();
4057 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004058
4059 if (fan_debounce) {
4060 u8 tmp;
4061
4062 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4063 tmp = superio_inb(sio_data->sioreg,
4064 NCT6775_REG_CR_FAN_DEBOUNCE);
4065 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004066 case nct6106:
4067 tmp |= 0xe0;
4068 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004069 case nct6775:
4070 tmp |= 0x1e;
4071 break;
4072 case nct6776:
4073 case nct6779:
4074 tmp |= 0x3e;
4075 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004076 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004077 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004078 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07004079 tmp |= 0x7e;
4080 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004081 }
4082 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4083 tmp);
4084 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4085 data->name);
4086 }
4087
Guenter Roeckdf612d52013-07-08 13:15:04 -07004088 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004089
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004090 superio_exit(sio_data->sioreg);
4091
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004092 /* Read fan clock dividers immediately */
4093 nct6775_init_fan_common(dev, data);
4094
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004095 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004096 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4097 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004098 if (IS_ERR(group))
4099 return PTR_ERR(group);
4100
Axel Lin55bdee62014-07-24 08:59:34 +08004101 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004102
Guenter Roeckf73cf632013-03-18 09:22:50 -07004103 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4104 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004105 if (IS_ERR(group))
4106 return PTR_ERR(group);
4107
Axel Lin55bdee62014-07-24 08:59:34 +08004108 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004109
Guenter Roeckf73cf632013-03-18 09:22:50 -07004110 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4111 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004112 if (IS_ERR(group))
4113 return PTR_ERR(group);
4114
Axel Lin55bdee62014-07-24 08:59:34 +08004115 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004116
Guenter Roeckf73cf632013-03-18 09:22:50 -07004117 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4118 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004119 if (IS_ERR(group))
4120 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004121
Axel Lin55bdee62014-07-24 08:59:34 +08004122 data->groups[num_attr_groups++] = group;
4123 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004124
Guenter Roecka150d952013-07-11 22:55:22 -07004125 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4126 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004127 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004128}
4129
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004130static void nct6791_enable_io_mapping(int sioaddr)
4131{
4132 int val;
4133
4134 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4135 if (val & 0x10) {
4136 pr_info("Enabling hardware monitor logical device mappings.\n");
4137 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4138 val & ~0x10);
4139 }
4140}
4141
Guenter Roeck48e93182015-02-07 08:48:49 -08004142static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004143{
4144 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004145
4146 mutex_lock(&data->update_lock);
4147 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004148 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004149 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4150 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4151 }
4152 mutex_unlock(&data->update_lock);
4153
4154 return 0;
4155}
4156
Guenter Roeck48e93182015-02-07 08:48:49 -08004157static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004158{
4159 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004160 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004161 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004162 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004163
4164 mutex_lock(&data->update_lock);
4165 data->bank = 0xff; /* Force initial bank selection */
4166
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004167 err = superio_enter(sioreg);
4168 if (err)
4169 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004170
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004171 superio_select(sioreg, NCT6775_LD_HWM);
4172 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4173 if (reg != data->sio_reg_enable)
4174 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4175
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004176 if (data->kind == nct6791 || data->kind == nct6792 ||
4177 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004178 nct6791_enable_io_mapping(sioreg);
4179
4180 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004181
Guenter Roeck84d19d92012-12-04 08:01:39 -08004182 /* Restore limits */
4183 for (i = 0; i < data->in_num; i++) {
4184 if (!(data->have_in & (1 << i)))
4185 continue;
4186
4187 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4188 data->in[i][1]);
4189 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4190 data->in[i][2]);
4191 }
4192
Guenter Roeckc409fd42013-04-09 05:04:00 -07004193 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004194 if (!(data->has_fan_min & (1 << i)))
4195 continue;
4196
4197 nct6775_write_value(data, data->REG_FAN_MIN[i],
4198 data->fan_min[i]);
4199 }
4200
4201 for (i = 0; i < NUM_TEMP; i++) {
4202 if (!(data->have_temp & (1 << i)))
4203 continue;
4204
Guenter Roeckc409fd42013-04-09 05:04:00 -07004205 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004206 if (data->reg_temp[j][i])
4207 nct6775_write_temp(data, data->reg_temp[j][i],
4208 data->temp[j][i]);
4209 }
4210
4211 /* Restore other settings */
4212 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004213 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004214 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4215 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4216 }
4217
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004218abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004219 /* Force re-reading all values */
4220 data->valid = false;
4221 mutex_unlock(&data->update_lock);
4222
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004223 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004224}
4225
Guenter Roeck48e93182015-02-07 08:48:49 -08004226static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004227
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004228static struct platform_driver nct6775_driver = {
4229 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004231 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004232 },
4233 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004234};
4235
4236/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004237static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004238{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004239 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004240 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004241 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004242
4243 err = superio_enter(sioaddr);
4244 if (err)
4245 return err;
4246
Guenter Roeckfc72af32016-08-03 22:07:18 -07004247 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4248 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4249 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004250 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004251
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004252 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004253 case SIO_NCT6106_ID:
4254 sio_data->kind = nct6106;
4255 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004256 case SIO_NCT6775_ID:
4257 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004258 break;
4259 case SIO_NCT6776_ID:
4260 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004261 break;
4262 case SIO_NCT6779_ID:
4263 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004264 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004265 case SIO_NCT6791_ID:
4266 sio_data->kind = nct6791;
4267 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004268 case SIO_NCT6792_ID:
4269 sio_data->kind = nct6792;
4270 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004271 case SIO_NCT6793_ID:
4272 sio_data->kind = nct6793;
4273 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004274 default:
4275 if (val != 0xffff)
4276 pr_debug("unsupported chip ID: 0x%04x\n", val);
4277 superio_exit(sioaddr);
4278 return -ENODEV;
4279 }
4280
4281 /* We have a known chip, find the HWM I/O address */
4282 superio_select(sioaddr, NCT6775_LD_HWM);
4283 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4284 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004285 addr = val & IOREGION_ALIGNMENT;
4286 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004287 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4288 superio_exit(sioaddr);
4289 return -ENODEV;
4290 }
4291
4292 /* Activate logical device if needed */
4293 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4294 if (!(val & 0x01)) {
4295 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4296 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4297 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004298
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004299 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4300 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004301 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004302
4303 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004304 pr_info("Found %s or compatible chip at %#x:%#x\n",
4305 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004306 sio_data->sioreg = sioaddr;
4307
Guenter Roeck698a7c22013-04-05 07:35:25 -07004308 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004309}
4310
4311/*
4312 * when Super-I/O functions move to a separate file, the Super-I/O
4313 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004314 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004315 * must keep track of the device
4316 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004317static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004318
4319static int __init sensors_nct6775_init(void)
4320{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004321 int i, err;
4322 bool found = false;
4323 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004324 struct resource res;
4325 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004326 int sioaddr[2] = { 0x2e, 0x4e };
4327
4328 err = platform_driver_register(&nct6775_driver);
4329 if (err)
4330 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004331
4332 /*
4333 * initialize sio_data->kind and sio_data->sioreg.
4334 *
4335 * when Super-I/O functions move to a separate file, the Super-I/O
4336 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4337 * nct6775 hardware monitor, and call probe()
4338 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004339 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4340 address = nct6775_find(sioaddr[i], &sio_data);
4341 if (address <= 0)
4342 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004343
Guenter Roeck698a7c22013-04-05 07:35:25 -07004344 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004345
Guenter Roeck698a7c22013-04-05 07:35:25 -07004346 pdev[i] = platform_device_alloc(DRVNAME, address);
4347 if (!pdev[i]) {
4348 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004349 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004350 }
4351
4352 err = platform_device_add_data(pdev[i], &sio_data,
4353 sizeof(struct nct6775_sio_data));
4354 if (err)
4355 goto exit_device_put;
4356
4357 memset(&res, 0, sizeof(res));
4358 res.name = DRVNAME;
4359 res.start = address + IOREGION_OFFSET;
4360 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4361 res.flags = IORESOURCE_IO;
4362
4363 err = acpi_check_resource_conflict(&res);
4364 if (err) {
4365 platform_device_put(pdev[i]);
4366 pdev[i] = NULL;
4367 continue;
4368 }
4369
4370 err = platform_device_add_resources(pdev[i], &res, 1);
4371 if (err)
4372 goto exit_device_put;
4373
4374 /* platform_device_add calls probe() */
4375 err = platform_device_add(pdev[i]);
4376 if (err)
4377 goto exit_device_put;
4378 }
4379 if (!found) {
4380 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004381 goto exit_unregister;
4382 }
4383
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004384 return 0;
4385
4386exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004387 platform_device_put(pdev[i]);
4388exit_device_unregister:
4389 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004390 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004391 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004392 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004393exit_unregister:
4394 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004395 return err;
4396}
4397
4398static void __exit sensors_nct6775_exit(void)
4399{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004400 int i;
4401
4402 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4403 if (pdev[i])
4404 platform_device_unregister(pdev[i]);
4405 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004406 platform_driver_unregister(&nct6775_driver);
4407}
4408
4409MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004410MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004411MODULE_LICENSE("GPL");
4412
4413module_init(sensors_nct6775_init);
4414module_exit(sensors_nct6775_exit);