blob: 318e0c5a34c8400d5aeb2c6364fcf6a463bc1284 [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 Roeck8aefb93f2014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070042 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070043 *
44 * #temp lists the number of monitored temperature sources (first value) plus
45 * the number of directly connectable temperature sensors (second value).
46 */
47
48#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
50#include <linux/module.h>
51#include <linux/init.h>
52#include <linux/slab.h>
53#include <linux/jiffies.h>
54#include <linux/platform_device.h>
55#include <linux/hwmon.h>
56#include <linux/hwmon-sysfs.h>
57#include <linux/hwmon-vid.h>
58#include <linux/err.h>
59#include <linux/mutex.h>
60#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070061#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080062#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070063#include <linux/io.h>
64#include "lm75.h"
65
Guenter Roeckaa136e52012-12-04 03:26:05 -080066#define USE_ALTERNATE
67
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070068enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070069
70/* used to set data->name = nct6775_device_names[data->sio_kind] */
71static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070072 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070073 "nct6775",
74 "nct6776",
75 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070076 "nct6791",
Guenter Roeck8aefb93f2014-11-16 09:50:04 -080077 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070078 "nct6793",
79};
80
81static const char * const nct6775_sio_names[] __initconst = {
82 "NCT6106D",
83 "NCT6775F",
84 "NCT6776D/F",
85 "NCT6779D",
86 "NCT6791D",
87 "NCT6792D",
88 "NCT6793D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070089};
90
91static unsigned short force_id;
92module_param(force_id, ushort, 0);
93MODULE_PARM_DESC(force_id, "Override the detected device ID");
94
Guenter Roeck47ece962012-12-04 07:59:32 -080095static unsigned short fan_debounce;
96module_param(fan_debounce, ushort, 0);
97MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
98
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070099#define DRVNAME "nct6775"
100
101/*
102 * Super-I/O constants and functions
103 */
104
Guenter Roecka6bd5872012-12-04 03:13:34 -0800105#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700106#define NCT6775_LD_HWM 0x0b
107#define NCT6775_LD_VID 0x0d
108
109#define SIO_REG_LDSEL 0x07 /* Logical device select */
110#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
111#define SIO_REG_ENABLE 0x30 /* Logical device enable */
112#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
113
Guenter Roeck6c009502012-07-01 08:23:15 -0700114#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700115#define SIO_NCT6775_ID 0xb470
116#define SIO_NCT6776_ID 0xc330
117#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700118#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb93f2014-11-16 09:50:04 -0800119#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700120#define SIO_NCT6793_ID 0xd120
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700121#define SIO_ID_MASK 0xFFF0
122
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800123enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
124
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700125static inline void
126superio_outb(int ioreg, int reg, int val)
127{
128 outb(reg, ioreg);
129 outb(val, ioreg + 1);
130}
131
132static inline int
133superio_inb(int ioreg, int reg)
134{
135 outb(reg, ioreg);
136 return inb(ioreg + 1);
137}
138
139static inline void
140superio_select(int ioreg, int ld)
141{
142 outb(SIO_REG_LDSEL, ioreg);
143 outb(ld, ioreg + 1);
144}
145
146static inline int
147superio_enter(int ioreg)
148{
149 /*
150 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
151 */
152 if (!request_muxed_region(ioreg, 2, DRVNAME))
153 return -EBUSY;
154
155 outb(0x87, ioreg);
156 outb(0x87, ioreg);
157
158 return 0;
159}
160
161static inline void
162superio_exit(int ioreg)
163{
164 outb(0xaa, ioreg);
165 outb(0x02, ioreg);
166 outb(0x02, ioreg + 1);
167 release_region(ioreg, 2);
168}
169
170/*
171 * ISA constants
172 */
173
174#define IOREGION_ALIGNMENT (~7)
175#define IOREGION_OFFSET 5
176#define IOREGION_LENGTH 2
177#define ADDR_REG_OFFSET 0
178#define DATA_REG_OFFSET 1
179
180#define NCT6775_REG_BANK 0x4E
181#define NCT6775_REG_CONFIG 0x40
182
183/*
184 * Not currently used:
185 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
186 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
187 * REG_MAN_ID is at port 0x4f
188 * REG_CHIP_ID is at port 0x58
189 */
190
Guenter Roeckaa136e52012-12-04 03:26:05 -0800191#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
192#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
193
Guenter Roeck6c009502012-07-01 08:23:15 -0700194#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700195#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700196
David Bartley578ab5f2013-06-24 22:28:28 -0700197#define NUM_FAN 6
198
Guenter Roeck7ce41902016-09-11 12:42:52 -0700199#define TEMP_SOURCE_VIRTUAL 0x1f
200
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700201/* Common and NCT6775 specific data */
202
203/* Voltage min/max registers for nr=7..14 are in bank 5 */
204
205static const u16 NCT6775_REG_IN_MAX[] = {
206 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
207 0x55c, 0x55e, 0x560, 0x562 };
208static const u16 NCT6775_REG_IN_MIN[] = {
209 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
210 0x55d, 0x55f, 0x561, 0x563 };
211static const u16 NCT6775_REG_IN[] = {
212 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
213};
214
215#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800216#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700217#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700218
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800219#define NCT6775_REG_FANDIV1 0x506
220#define NCT6775_REG_FANDIV2 0x507
221
Guenter Roeck47ece962012-12-04 07:59:32 -0800222#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
223
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700224static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
225
Guenter Roeck30846992013-06-24 22:21:59 -0700226/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700227
228static const s8 NCT6775_ALARM_BITS[] = {
229 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
230 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
231 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700232 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700233 -1, -1, -1, /* unused */
234 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
235 12, -1 }; /* intrusion0, intrusion1 */
236
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800237#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800238#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800239#define INTRUSION_ALARM_BASE 30
240
Guenter Roeck30846992013-06-24 22:21:59 -0700241static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
242
243/*
244 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
245 * 30..31 intrusion
246 */
247static const s8 NCT6775_BEEP_BITS[] = {
248 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
249 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
250 21, /* global beep enable */
251 6, 7, 11, 28, -1, /* fan1..fan5 */
252 -1, -1, -1, /* unused */
253 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
254 12, -1 }; /* intrusion0, intrusion1 */
255
256#define BEEP_ENABLE_BASE 15
257
Guenter Roecka6bd5872012-12-04 03:13:34 -0800258static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
259static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
260
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800261/* DC or PWM output fan configuration */
262static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
263static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
264
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800265/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800266
David Bartley578ab5f2013-06-24 22:28:28 -0700267static const u16 NCT6775_REG_TARGET[] = {
268 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
269static const u16 NCT6775_REG_FAN_MODE[] = {
270 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800271static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700272 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800273static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700274 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800275static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700276 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
277static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
278 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800279static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
280static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
281
282static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700283 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
284static const u16 NCT6775_REG_PWM[] = {
285 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
286static const u16 NCT6775_REG_PWM_READ[] = {
287 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800288
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800289static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
290static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800291static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700292static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800293
Guenter Roeckaa136e52012-12-04 03:26:05 -0800294static const u16 NCT6775_REG_TEMP[] = {
295 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
296
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800297static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
298
Guenter Roeckaa136e52012-12-04 03:26:05 -0800299static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
300 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
301static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
302 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
303static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
304 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
305
306static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
307 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
308
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800309static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700310 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800311
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800312static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700313 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800314static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700315 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800316static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700317 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800318static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700319 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800320static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700321 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800322
Guenter Roeckaa136e52012-12-04 03:26:05 -0800323static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
324
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800325static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700326 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800327static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700328 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800329
330#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
331#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
332
333static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
334
335static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700336 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800337static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700338 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800339
Guenter Roeckaa136e52012-12-04 03:26:05 -0800340static const char *const nct6775_temp_label[] = {
341 "",
342 "SYSTIN",
343 "CPUTIN",
344 "AUXTIN",
345 "AMD SB-TSI",
346 "PECI Agent 0",
347 "PECI Agent 1",
348 "PECI Agent 2",
349 "PECI Agent 3",
350 "PECI Agent 4",
351 "PECI Agent 5",
352 "PECI Agent 6",
353 "PECI Agent 7",
354 "PCH_CHIP_CPU_MAX_TEMP",
355 "PCH_CHIP_TEMP",
356 "PCH_CPU_TEMP",
357 "PCH_MCH_TEMP",
358 "PCH_DIM0_TEMP",
359 "PCH_DIM1_TEMP",
360 "PCH_DIM2_TEMP",
361 "PCH_DIM3_TEMP"
362};
363
Guenter Roeckcc66b302017-05-17 18:05:06 -0700364#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800365
Guenter Roeckcc66b302017-05-17 18:05:06 -0700366static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
367 [13] = 0x661,
368 [14] = 0x662,
369 [15] = 0x664,
370};
371
372static const u16 NCT6775_REG_TEMP_CRIT[32] = {
373 [4] = 0xa00,
374 [5] = 0xa01,
375 [6] = 0xa02,
376 [7] = 0xa03,
377 [8] = 0xa04,
378 [9] = 0xa05,
379 [10] = 0xa06,
380 [11] = 0xa07
381};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800382
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700383/* NCT6776 specific data */
384
Guenter Roeck728d2942015-08-31 16:13:47 -0700385/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
386#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
387#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
388
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700389static const s8 NCT6776_ALARM_BITS[] = {
390 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
391 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
392 -1, /* unused */
393 6, 7, 11, 10, 23, /* fan1..fan5 */
394 -1, -1, -1, /* unused */
395 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
396 12, 9 }; /* intrusion0, intrusion1 */
397
Guenter Roeck30846992013-06-24 22:21:59 -0700398static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
399
400static const s8 NCT6776_BEEP_BITS[] = {
401 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
402 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
403 24, /* global beep enable */
404 25, 26, 27, 28, 29, /* fan1..fan5 */
405 -1, -1, -1, /* unused */
406 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
407 30, 31 }; /* intrusion0, intrusion1 */
408
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800409static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700410 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800411
David Bartley578ab5f2013-06-24 22:28:28 -0700412static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
413static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800414
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800415static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800416static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800417
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800418static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700419 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800420
Guenter Roeckaa136e52012-12-04 03:26:05 -0800421static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
422 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
423
424static const char *const nct6776_temp_label[] = {
425 "",
426 "SYSTIN",
427 "CPUTIN",
428 "AUXTIN",
429 "SMBUSMASTER 0",
430 "SMBUSMASTER 1",
431 "SMBUSMASTER 2",
432 "SMBUSMASTER 3",
433 "SMBUSMASTER 4",
434 "SMBUSMASTER 5",
435 "SMBUSMASTER 6",
436 "SMBUSMASTER 7",
437 "PECI Agent 0",
438 "PECI Agent 1",
439 "PCH_CHIP_CPU_MAX_TEMP",
440 "PCH_CHIP_TEMP",
441 "PCH_CPU_TEMP",
442 "PCH_MCH_TEMP",
443 "PCH_DIM0_TEMP",
444 "PCH_DIM1_TEMP",
445 "PCH_DIM2_TEMP",
446 "PCH_DIM3_TEMP",
447 "BYTE_TEMP"
448};
449
Guenter Roeckcc66b302017-05-17 18:05:06 -0700450#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800451
Guenter Roeckcc66b302017-05-17 18:05:06 -0700452static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
453 [14] = 0x401,
454 [15] = 0x402,
455 [16] = 0x404,
456};
457
458static const u16 NCT6776_REG_TEMP_CRIT[32] = {
459 [11] = 0x709,
460 [12] = 0x70a,
461};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800462
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700463/* NCT6779 specific data */
464
465static const u16 NCT6779_REG_IN[] = {
466 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
467 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
468
469static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
470 0x459, 0x45A, 0x45B, 0x568 };
471
472static const s8 NCT6779_ALARM_BITS[] = {
473 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
474 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
475 -1, /* unused */
476 6, 7, 11, 10, 23, /* fan1..fan5 */
477 -1, -1, -1, /* unused */
478 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
479 12, 9 }; /* intrusion0, intrusion1 */
480
Guenter Roeck30846992013-06-24 22:21:59 -0700481static const s8 NCT6779_BEEP_BITS[] = {
482 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
483 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
484 24, /* global beep enable */
485 25, 26, 27, 28, 29, /* fan1..fan5 */
486 -1, -1, -1, /* unused */
487 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
488 30, 31 }; /* intrusion0, intrusion1 */
489
David Bartley578ab5f2013-06-24 22:28:28 -0700490static const u16 NCT6779_REG_FAN[] = {
491 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800492static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700493 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800494
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800495static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700496 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700497#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800498static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700499 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800500
Guenter Roeckaa136e52012-12-04 03:26:05 -0800501static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800502static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800503static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
504 0x18, 0x152 };
505static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
506 0x3a, 0x153 };
507static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
508 0x39, 0x155 };
509
510static const u16 NCT6779_REG_TEMP_OFFSET[] = {
511 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
512
513static const char *const nct6779_temp_label[] = {
514 "",
515 "SYSTIN",
516 "CPUTIN",
517 "AUXTIN0",
518 "AUXTIN1",
519 "AUXTIN2",
520 "AUXTIN3",
521 "",
522 "SMBUSMASTER 0",
523 "SMBUSMASTER 1",
524 "SMBUSMASTER 2",
525 "SMBUSMASTER 3",
526 "SMBUSMASTER 4",
527 "SMBUSMASTER 5",
528 "SMBUSMASTER 6",
529 "SMBUSMASTER 7",
530 "PECI Agent 0",
531 "PECI Agent 1",
532 "PCH_CHIP_CPU_MAX_TEMP",
533 "PCH_CHIP_TEMP",
534 "PCH_CPU_TEMP",
535 "PCH_MCH_TEMP",
536 "PCH_DIM0_TEMP",
537 "PCH_DIM1_TEMP",
538 "PCH_DIM2_TEMP",
539 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700540 "BYTE_TEMP",
541 "",
542 "",
543 "",
544 "",
545 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800546};
547
Guenter Roeckcc66b302017-05-17 18:05:06 -0700548#define NCT6779_TEMP_MASK 0x07ffff7e
549#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck9a383712015-08-29 15:29:25 -0700550
Guenter Roeckcc66b302017-05-17 18:05:06 -0700551static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800552 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
553 0, 0, 0, 0, 0, 0, 0, 0,
554 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
555 0x408, 0 };
556
Guenter Roeckcc66b302017-05-17 18:05:06 -0700557static const u16 NCT6779_REG_TEMP_CRIT[32] = {
558 [15] = 0x709,
559 [16] = 0x70a,
560};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800561
David Bartley578ab5f2013-06-24 22:28:28 -0700562/* NCT6791 specific data */
563
564#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
565
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800566static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
567static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
568static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
569static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
570static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
571static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
572
David Bartley578ab5f2013-06-24 22:28:28 -0700573static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
574 0x459, 0x45A, 0x45B, 0x568, 0x45D };
575
576static const s8 NCT6791_ALARM_BITS[] = {
577 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
578 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
579 -1, /* unused */
580 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
581 -1, -1, /* unused */
582 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
583 12, 9 }; /* intrusion0, intrusion1 */
584
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700585/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb93f2014-11-16 09:50:04 -0800586
587static const u16 NCT6792_REG_TEMP_MON[] = {
588 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
589static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
590 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700591
Guenter Roeck50224f42015-10-30 07:52:39 -0700592static const char *const nct6792_temp_label[] = {
593 "",
594 "SYSTIN",
595 "CPUTIN",
596 "AUXTIN0",
597 "AUXTIN1",
598 "AUXTIN2",
599 "AUXTIN3",
600 "",
601 "SMBUSMASTER 0",
602 "SMBUSMASTER 1",
603 "SMBUSMASTER 2",
604 "SMBUSMASTER 3",
605 "SMBUSMASTER 4",
606 "SMBUSMASTER 5",
607 "SMBUSMASTER 6",
608 "SMBUSMASTER 7",
609 "PECI Agent 0",
610 "PECI Agent 1",
611 "PCH_CHIP_CPU_MAX_TEMP",
612 "PCH_CHIP_TEMP",
613 "PCH_CPU_TEMP",
614 "PCH_MCH_TEMP",
615 "PCH_DIM0_TEMP",
616 "PCH_DIM1_TEMP",
617 "PCH_DIM2_TEMP",
618 "PCH_DIM3_TEMP",
619 "BYTE_TEMP",
620 "PECI Agent 0 Calibration",
621 "PECI Agent 1 Calibration",
622 "",
623 "",
624 "Virtual_TEMP"
625};
626
Guenter Roeckcc66b302017-05-17 18:05:06 -0700627#define NCT6792_TEMP_MASK 0x9fffff7e
628
Guenter Roeck50224f42015-10-30 07:52:39 -0700629static const char *const nct6793_temp_label[] = {
630 "",
631 "SYSTIN",
632 "CPUTIN",
633 "AUXTIN0",
634 "AUXTIN1",
635 "AUXTIN2",
636 "AUXTIN3",
637 "",
638 "SMBUSMASTER 0",
639 "SMBUSMASTER 1",
640 "",
641 "",
642 "",
643 "",
644 "",
645 "",
646 "PECI Agent 0",
647 "PECI Agent 1",
648 "PCH_CHIP_CPU_MAX_TEMP",
649 "PCH_CHIP_TEMP",
650 "PCH_CPU_TEMP",
651 "PCH_MCH_TEMP",
652 "Agent0 Dimm0 ",
653 "Agent0 Dimm1",
654 "Agent1 Dimm0",
655 "Agent1 Dimm1",
656 "BYTE_TEMP0",
657 "BYTE_TEMP1",
658 "PECI Agent 0 Calibration",
659 "PECI Agent 1 Calibration",
660 "",
661 "Virtual_TEMP"
662};
663
Guenter Roeckcc66b302017-05-17 18:05:06 -0700664#define NCT6793_TEMP_MASK 0xbfff037e
665
Guenter Roeck6c009502012-07-01 08:23:15 -0700666/* NCT6102D/NCT6106D specific data */
667
668#define NCT6106_REG_VBAT 0x318
669#define NCT6106_REG_DIODE 0x319
670#define NCT6106_DIODE_MASK 0x01
671
672static const u16 NCT6106_REG_IN_MAX[] = {
673 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
674static const u16 NCT6106_REG_IN_MIN[] = {
675 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
676static const u16 NCT6106_REG_IN[] = {
677 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
678
679static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800680static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700681static const u16 NCT6106_REG_TEMP_HYST[] = {
682 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
683static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700684 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
685static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
686 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
687static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
688 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700689static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
690static const u16 NCT6106_REG_TEMP_CONFIG[] = {
691 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
692
693static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
694static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
695static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
696static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
697
698static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
699static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
700static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
701static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
702static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
703static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
704static const u16 NCT6106_REG_TEMP_SOURCE[] = {
705 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
706
707static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
708static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
709 0x11b, 0x12b, 0x13b };
710
711static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
712#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
713static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
714
715static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
716static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
717static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
718static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
719static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
720static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
721
722static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
723
724static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
725static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
726static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
727static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
728static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
729static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
730
731static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
732static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
733
734static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
735 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
736
737static const s8 NCT6106_ALARM_BITS[] = {
738 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
739 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
740 -1, /* unused */
741 32, 33, 34, -1, -1, /* fan1..fan5 */
742 -1, -1, -1, /* unused */
743 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
744 48, -1 /* intrusion0, intrusion1 */
745};
746
Guenter Roeck30846992013-06-24 22:21:59 -0700747static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
748 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
749
750static const s8 NCT6106_BEEP_BITS[] = {
751 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
752 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
753 32, /* global beep enable */
754 24, 25, 26, 27, 28, /* fan1..fan5 */
755 -1, -1, -1, /* unused */
756 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
757 34, -1 /* intrusion0, intrusion1 */
758};
759
Guenter Roeckcc66b302017-05-17 18:05:06 -0700760static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
761 [14] = 0x51,
762 [15] = 0x52,
763 [16] = 0x54,
764};
Guenter Roeck6c009502012-07-01 08:23:15 -0700765
Guenter Roeckcc66b302017-05-17 18:05:06 -0700766static const u16 NCT6106_REG_TEMP_CRIT[32] = {
767 [11] = 0x204,
768 [12] = 0x205,
769};
Guenter Roeck6c009502012-07-01 08:23:15 -0700770
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800771static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
772{
773 if (mode == 0 && pwm == 255)
774 return off;
775 return mode + 1;
776}
777
778static int pwm_enable_to_reg(enum pwm_enable mode)
779{
780 if (mode == off)
781 return 0;
782 return mode - 1;
783}
784
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700785/*
786 * Conversions
787 */
788
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800789/* 1 is DC mode, output in ms */
790static unsigned int step_time_from_reg(u8 reg, u8 mode)
791{
792 return mode ? 400 * reg : 100 * reg;
793}
794
795static u8 step_time_to_reg(unsigned int msec, u8 mode)
796{
797 return clamp_val((mode ? (msec + 200) / 400 :
798 (msec + 50) / 100), 1, 255);
799}
800
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800801static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
802{
803 if (reg == 0 || reg == 255)
804 return 0;
805 return 1350000U / (reg << divreg);
806}
807
808static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
809{
810 if ((reg & 0xff1f) == 0xff1f)
811 return 0;
812
813 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
814
815 if (reg == 0)
816 return 0;
817
818 return 1350000U / reg;
819}
820
821static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
822{
823 if (reg == 0 || reg == 0xffff)
824 return 0;
825
826 /*
827 * Even though the registers are 16 bit wide, the fan divisor
828 * still applies.
829 */
830 return 1350000U / (reg << divreg);
831}
832
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800833static u16 fan_to_reg(u32 fan, unsigned int divreg)
834{
835 if (!fan)
836 return 0;
837
838 return (1350000U / fan) >> divreg;
839}
840
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800841static inline unsigned int
842div_from_reg(u8 reg)
843{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700844 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800845}
846
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700847/*
848 * Some of the voltage inputs have internal scaling, the tables below
849 * contain 8 (the ADC LSB in mV) * scaling factor * 100
850 */
851static const u16 scale_in[15] = {
852 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
853 800, 800
854};
855
856static inline long in_from_reg(u8 reg, u8 nr)
857{
858 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
859}
860
861static inline u8 in_to_reg(u32 val, u8 nr)
862{
863 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
864}
865
866/*
867 * Data structures and manipulation thereof
868 */
869
870struct nct6775_data {
871 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700872 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700873 enum kinds kind;
874 const char *name;
875
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700876 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700877
Guenter Roeckb7a61352013-04-02 22:14:06 -0700878 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
879 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800880 */
881 u8 temp_src[NUM_TEMP];
882 u16 reg_temp_config[NUM_TEMP];
883 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700884 u32 temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800885
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700886 u16 REG_CONFIG;
887 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800888 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700889 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700890
891 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700892 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700893
894 const u16 *REG_VIN;
895 const u16 *REG_IN_MINMAX[2];
896
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800897 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800898 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800899 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800900 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800901 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700902 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800903 const u16 *REG_FAN_TIME[3];
904
905 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800906
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800907 const u8 *REG_PWM_MODE;
908 const u8 *PWM_MODE_MASK;
909
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800910 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
911 * [3]=pwm_max, [4]=pwm_step,
912 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800913 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800914 const u16 *REG_PWM_READ;
915
Guenter Roeck6c009502012-07-01 08:23:15 -0700916 const u16 *REG_CRITICAL_PWM_ENABLE;
917 u8 CRITICAL_PWM_ENABLE_MASK;
918 const u16 *REG_CRITICAL_PWM;
919
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800920 const u16 *REG_AUTO_TEMP;
921 const u16 *REG_AUTO_PWM;
922
923 const u16 *REG_CRITICAL_TEMP;
924 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
925
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800926 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800927 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800928 const u16 *REG_WEIGHT_TEMP_SEL;
929 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
930
Guenter Roeckaa136e52012-12-04 03:26:05 -0800931 const u16 *REG_TEMP_OFFSET;
932
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700933 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700934 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700935
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800936 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
937 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
938
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700939 struct mutex update_lock;
940 bool valid; /* true if following fields are valid */
941 unsigned long last_updated; /* In jiffies */
942
943 /* Register values */
944 u8 bank; /* current register bank */
945 u8 in_num; /* number of in inputs we have */
946 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700947 unsigned int rpm[NUM_FAN];
948 u16 fan_min[NUM_FAN];
949 u8 fan_pulses[NUM_FAN];
950 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800951 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800952 u8 has_fan; /* some fan inputs can be disabled */
953 u8 has_fan_min; /* some fans don't have min register */
954 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700955
Guenter Roeck6c009502012-07-01 08:23:15 -0700956 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700957 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800958 u8 temp_fixed_num; /* 3 or 6 */
959 u8 temp_type[NUM_TEMP_FIXED];
960 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300961 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
962 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700963 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700964 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700965
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800966 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700967 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
968 * 0->PWM variable duty cycle
969 */
970 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800971 /* 0->off
972 * 1->manual
973 * 2->thermal cruise mode (also called SmartFan I)
974 * 3->fan speed cruise mode
975 * 4->SmartFan III
976 * 5->enhanced variable thermal cruise (SmartFan IV)
977 */
David Bartley578ab5f2013-06-24 22:28:28 -0700978 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
979 * [3]=pwm_max, [4]=pwm_step,
980 * [5]=weight_duty_step, [6]=weight_duty_base
981 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800982
David Bartley578ab5f2013-06-24 22:28:28 -0700983 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800984 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700985 u32 target_speed[NUM_FAN];
986 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800987 u8 speed_tolerance_limit;
988
David Bartley578ab5f2013-06-24 22:28:28 -0700989 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800990 u8 tolerance_mask;
991
David Bartley578ab5f2013-06-24 22:28:28 -0700992 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800993
994 /* Automatic fan speed control registers */
995 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700996 u8 auto_pwm[NUM_FAN][7];
997 u8 auto_temp[NUM_FAN][7];
998 u8 pwm_temp_sel[NUM_FAN];
999 u8 pwm_weight_temp_sel[NUM_FAN];
1000 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1001 * 2->temp_base
1002 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001003
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001004 u8 vid;
1005 u8 vrm;
1006
Guenter Roeckf73cf632013-03-18 09:22:50 -07001007 bool have_vid;
1008
Guenter Roeckaa136e52012-12-04 03:26:05 -08001009 u16 have_temp;
1010 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001011 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001012
Guenter Roeck84d19d92012-12-04 08:01:39 -08001013 /* Remember extra register values over suspend/resume */
1014 u8 vbat;
1015 u8 fandiv1;
1016 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001017 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001018};
1019
1020struct nct6775_sio_data {
1021 int sioreg;
1022 enum kinds kind;
1023};
1024
Guenter Roeckf73cf632013-03-18 09:22:50 -07001025struct sensor_device_template {
1026 struct device_attribute dev_attr;
1027 union {
1028 struct {
1029 u8 nr;
1030 u8 index;
1031 } s;
1032 int index;
1033 } u;
1034 bool s2; /* true if both index and nr are used */
1035};
1036
1037struct sensor_device_attr_u {
1038 union {
1039 struct sensor_device_attribute a1;
1040 struct sensor_device_attribute_2 a2;
1041 } u;
1042 char name[32];
1043};
1044
1045#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1046 .attr = {.name = _template, .mode = _mode }, \
1047 .show = _show, \
1048 .store = _store, \
1049}
1050
1051#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1052 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1053 .u.index = _index, \
1054 .s2 = false }
1055
1056#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1057 _nr, _index) \
1058 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1059 .u.s.index = _index, \
1060 .u.s.nr = _nr, \
1061 .s2 = true }
1062
1063#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1064static struct sensor_device_template sensor_dev_template_##_name \
1065 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1066 _index)
1067
1068#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1069 _nr, _index) \
1070static struct sensor_device_template sensor_dev_template_##_name \
1071 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1072 _nr, _index)
1073
1074struct sensor_template_group {
1075 struct sensor_device_template **templates;
1076 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1077 int base;
1078};
1079
1080static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001081nct6775_create_attr_group(struct device *dev,
1082 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001083 int repeat)
1084{
1085 struct attribute_group *group;
1086 struct sensor_device_attr_u *su;
1087 struct sensor_device_attribute *a;
1088 struct sensor_device_attribute_2 *a2;
1089 struct attribute **attrs;
1090 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001091 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001092
1093 if (repeat <= 0)
1094 return ERR_PTR(-EINVAL);
1095
1096 t = tg->templates;
1097 for (count = 0; *t; t++, count++)
1098 ;
1099
1100 if (count == 0)
1101 return ERR_PTR(-EINVAL);
1102
1103 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1104 if (group == NULL)
1105 return ERR_PTR(-ENOMEM);
1106
1107 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1108 GFP_KERNEL);
1109 if (attrs == NULL)
1110 return ERR_PTR(-ENOMEM);
1111
1112 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1113 GFP_KERNEL);
1114 if (su == NULL)
1115 return ERR_PTR(-ENOMEM);
1116
1117 group->attrs = attrs;
1118 group->is_visible = tg->is_visible;
1119
1120 for (i = 0; i < repeat; i++) {
1121 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001122 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001123 snprintf(su->name, sizeof(su->name),
1124 (*t)->dev_attr.attr.name, tg->base + i);
1125 if ((*t)->s2) {
1126 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001127 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001128 a2->dev_attr.attr.name = su->name;
1129 a2->nr = (*t)->u.s.nr + i;
1130 a2->index = (*t)->u.s.index;
1131 a2->dev_attr.attr.mode =
1132 (*t)->dev_attr.attr.mode;
1133 a2->dev_attr.show = (*t)->dev_attr.show;
1134 a2->dev_attr.store = (*t)->dev_attr.store;
1135 *attrs = &a2->dev_attr.attr;
1136 } else {
1137 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001138 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001139 a->dev_attr.attr.name = su->name;
1140 a->index = (*t)->u.index + i;
1141 a->dev_attr.attr.mode =
1142 (*t)->dev_attr.attr.mode;
1143 a->dev_attr.show = (*t)->dev_attr.show;
1144 a->dev_attr.store = (*t)->dev_attr.store;
1145 *attrs = &a->dev_attr.attr;
1146 }
1147 attrs++;
1148 su++;
1149 t++;
1150 }
1151 }
1152
Guenter Roeckf73cf632013-03-18 09:22:50 -07001153 return group;
1154}
1155
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001156static bool is_word_sized(struct nct6775_data *data, u16 reg)
1157{
1158 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001159 case nct6106:
1160 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1161 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1162 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001163 case nct6775:
1164 return (((reg & 0xff00) == 0x100 ||
1165 (reg & 0xff00) == 0x200) &&
1166 ((reg & 0x00ff) == 0x50 ||
1167 (reg & 0x00ff) == 0x53 ||
1168 (reg & 0x00ff) == 0x55)) ||
1169 (reg & 0xfff0) == 0x630 ||
1170 reg == 0x640 || reg == 0x642 ||
1171 reg == 0x662 ||
1172 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1173 reg == 0x73 || reg == 0x75 || reg == 0x77;
1174 case nct6776:
1175 return (((reg & 0xff00) == 0x100 ||
1176 (reg & 0xff00) == 0x200) &&
1177 ((reg & 0x00ff) == 0x50 ||
1178 (reg & 0x00ff) == 0x53 ||
1179 (reg & 0x00ff) == 0x55)) ||
1180 (reg & 0xfff0) == 0x630 ||
1181 reg == 0x402 ||
1182 reg == 0x640 || reg == 0x642 ||
1183 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1184 reg == 0x73 || reg == 0x75 || reg == 0x77;
1185 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001186 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08001187 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001188 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001189 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001190 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001191 reg == 0x402 ||
1192 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1193 reg == 0x640 || reg == 0x642 ||
1194 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08001195 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001196 }
1197 return false;
1198}
1199
1200/*
1201 * On older chips, only registers 0x50-0x5f are banked.
1202 * On more recent chips, all registers are banked.
1203 * Assume that is the case and set the bank number for each access.
1204 * Cache the bank number so it only needs to be set if it changes.
1205 */
1206static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1207{
1208 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001209
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001210 if (data->bank != bank) {
1211 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1212 outb_p(bank, data->addr + DATA_REG_OFFSET);
1213 data->bank = bank;
1214 }
1215}
1216
1217static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1218{
1219 int res, word_sized = is_word_sized(data, reg);
1220
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001221 nct6775_set_bank(data, reg);
1222 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1223 res = inb_p(data->addr + DATA_REG_OFFSET);
1224 if (word_sized) {
1225 outb_p((reg & 0xff) + 1,
1226 data->addr + ADDR_REG_OFFSET);
1227 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1228 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001229 return res;
1230}
1231
1232static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1233{
1234 int word_sized = is_word_sized(data, reg);
1235
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001236 nct6775_set_bank(data, reg);
1237 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1238 if (word_sized) {
1239 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1240 outb_p((reg & 0xff) + 1,
1241 data->addr + ADDR_REG_OFFSET);
1242 }
1243 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001244 return 0;
1245}
1246
Guenter Roeckaa136e52012-12-04 03:26:05 -08001247/* We left-align 8-bit temperature values to make the code simpler */
1248static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1249{
1250 u16 res;
1251
1252 res = nct6775_read_value(data, reg);
1253 if (!is_word_sized(data, reg))
1254 res <<= 8;
1255
1256 return res;
1257}
1258
1259static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1260{
1261 if (!is_word_sized(data, reg))
1262 value >>= 8;
1263 return nct6775_write_value(data, reg, value);
1264}
1265
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001266/* This function assumes that the caller holds data->update_lock */
1267static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1268{
1269 u8 reg;
1270
1271 switch (nr) {
1272 case 0:
1273 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1274 | (data->fan_div[0] & 0x7);
1275 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1276 break;
1277 case 1:
1278 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1279 | ((data->fan_div[1] << 4) & 0x70);
1280 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1281 break;
1282 case 2:
1283 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1284 | (data->fan_div[2] & 0x7);
1285 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1286 break;
1287 case 3:
1288 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1289 | ((data->fan_div[3] << 4) & 0x70);
1290 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1291 break;
1292 }
1293}
1294
1295static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1296{
1297 if (data->kind == nct6775)
1298 nct6775_write_fan_div(data, nr);
1299}
1300
1301static void nct6775_update_fan_div(struct nct6775_data *data)
1302{
1303 u8 i;
1304
1305 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1306 data->fan_div[0] = i & 0x7;
1307 data->fan_div[1] = (i & 0x70) >> 4;
1308 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1309 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001310 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001311 data->fan_div[3] = (i & 0x70) >> 4;
1312}
1313
1314static void nct6775_update_fan_div_common(struct nct6775_data *data)
1315{
1316 if (data->kind == nct6775)
1317 nct6775_update_fan_div(data);
1318}
1319
1320static void nct6775_init_fan_div(struct nct6775_data *data)
1321{
1322 int i;
1323
1324 nct6775_update_fan_div_common(data);
1325 /*
1326 * For all fans, start with highest divider value if the divider
1327 * register is not initialized. This ensures that we get a
1328 * reading from the fan count register, even if it is not optimal.
1329 * We'll compute a better divider later on.
1330 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001331 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001332 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001333 continue;
1334 if (data->fan_div[i] == 0) {
1335 data->fan_div[i] = 7;
1336 nct6775_write_fan_div_common(data, i);
1337 }
1338 }
1339}
1340
1341static void nct6775_init_fan_common(struct device *dev,
1342 struct nct6775_data *data)
1343{
1344 int i;
1345 u8 reg;
1346
1347 if (data->has_fan_div)
1348 nct6775_init_fan_div(data);
1349
1350 /*
1351 * If fan_min is not set (0), set it to 0xff to disable it. This
1352 * prevents the unnecessary warning when fanX_min is reported as 0.
1353 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001354 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001355 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001356 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1357 if (!reg)
1358 nct6775_write_value(data, data->REG_FAN_MIN[i],
1359 data->has_fan_div ? 0xff
1360 : 0xff1f);
1361 }
1362 }
1363}
1364
1365static void nct6775_select_fan_div(struct device *dev,
1366 struct nct6775_data *data, int nr, u16 reg)
1367{
1368 u8 fan_div = data->fan_div[nr];
1369 u16 fan_min;
1370
1371 if (!data->has_fan_div)
1372 return;
1373
1374 /*
1375 * If we failed to measure the fan speed, or the reported value is not
1376 * in the optimal range, and the clock divider can be modified,
1377 * let's try that for next time.
1378 */
1379 if (reg == 0x00 && fan_div < 0x07)
1380 fan_div++;
1381 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1382 fan_div--;
1383
1384 if (fan_div != data->fan_div[nr]) {
1385 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1386 nr + 1, div_from_reg(data->fan_div[nr]),
1387 div_from_reg(fan_div));
1388
1389 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001390 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001391 fan_min = data->fan_min[nr];
1392 if (fan_div > data->fan_div[nr]) {
1393 if (fan_min != 255 && fan_min > 1)
1394 fan_min >>= 1;
1395 } else {
1396 if (fan_min != 255) {
1397 fan_min <<= 1;
1398 if (fan_min > 254)
1399 fan_min = 254;
1400 }
1401 }
1402 if (fan_min != data->fan_min[nr]) {
1403 data->fan_min[nr] = fan_min;
1404 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1405 fan_min);
1406 }
1407 }
1408 data->fan_div[nr] = fan_div;
1409 nct6775_write_fan_div_common(data, nr);
1410 }
1411}
1412
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001413static void nct6775_update_pwm(struct device *dev)
1414{
1415 struct nct6775_data *data = dev_get_drvdata(dev);
1416 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001417 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001418 bool duty_is_dc;
1419
1420 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001421 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001422 continue;
1423
1424 duty_is_dc = data->REG_PWM_MODE[i] &&
1425 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1426 & data->PWM_MODE_MASK[i]);
1427 data->pwm_mode[i] = duty_is_dc;
1428
1429 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1430 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1431 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1432 data->pwm[j][i]
1433 = nct6775_read_value(data,
1434 data->REG_PWM[j][i]);
1435 }
1436 }
1437
1438 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1439 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001440
1441 if (!data->temp_tolerance[0][i] ||
1442 data->pwm_enable[i] != speed_cruise)
1443 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1444 if (!data->target_speed_tolerance[i] ||
1445 data->pwm_enable[i] == speed_cruise) {
1446 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001447
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001448 if (data->REG_TOLERANCE_H) {
1449 t |= (nct6775_read_value(data,
1450 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1451 }
1452 data->target_speed_tolerance[i] = t;
1453 }
1454
1455 data->temp_tolerance[1][i] =
1456 nct6775_read_value(data,
1457 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1458
1459 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1460 data->pwm_temp_sel[i] = reg & 0x1f;
1461 /* If fan can stop, report floor as 0 */
1462 if (reg & 0x80)
1463 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001464
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001465 if (!data->REG_WEIGHT_TEMP_SEL[i])
1466 continue;
1467
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001468 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1469 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1470 /* If weight is disabled, report weight source as 0 */
1471 if (j == 1 && !(reg & 0x80))
1472 data->pwm_weight_temp_sel[i] = 0;
1473
1474 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001475 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001476 data->weight_temp[j][i]
1477 = nct6775_read_value(data,
1478 data->REG_WEIGHT_TEMP[j][i]);
1479 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001480 }
1481}
1482
1483static void nct6775_update_pwm_limits(struct device *dev)
1484{
1485 struct nct6775_data *data = dev_get_drvdata(dev);
1486 int i, j;
1487 u8 reg;
1488 u16 reg_t;
1489
1490 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001491 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001492 continue;
1493
Guenter Roeckc409fd42013-04-09 05:04:00 -07001494 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001495 data->fan_time[j][i] =
1496 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1497 }
1498
1499 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1500 /* Update only in matching mode or if never updated */
1501 if (!data->target_temp[i] ||
1502 data->pwm_enable[i] == thermal_cruise)
1503 data->target_temp[i] = reg_t & data->target_temp_mask;
1504 if (!data->target_speed[i] ||
1505 data->pwm_enable[i] == speed_cruise) {
1506 if (data->REG_TOLERANCE_H) {
1507 reg_t |= (nct6775_read_value(data,
1508 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1509 }
1510 data->target_speed[i] = reg_t;
1511 }
1512
1513 for (j = 0; j < data->auto_pwm_num; j++) {
1514 data->auto_pwm[i][j] =
1515 nct6775_read_value(data,
1516 NCT6775_AUTO_PWM(data, i, j));
1517 data->auto_temp[i][j] =
1518 nct6775_read_value(data,
1519 NCT6775_AUTO_TEMP(data, i, j));
1520 }
1521
1522 /* critical auto_pwm temperature data */
1523 data->auto_temp[i][data->auto_pwm_num] =
1524 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1525
1526 switch (data->kind) {
1527 case nct6775:
1528 reg = nct6775_read_value(data,
1529 NCT6775_REG_CRITICAL_ENAB[i]);
1530 data->auto_pwm[i][data->auto_pwm_num] =
1531 (reg & 0x02) ? 0xff : 0x00;
1532 break;
1533 case nct6776:
1534 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1535 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001536 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001537 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001538 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08001539 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001540 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001541 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001542 data->REG_CRITICAL_PWM_ENABLE[i]);
1543 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1544 reg = nct6775_read_value(data,
1545 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001546 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001547 reg = 0xff;
1548 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001549 break;
1550 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001551 }
1552}
1553
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001554static struct nct6775_data *nct6775_update_device(struct device *dev)
1555{
1556 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001557 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001558
1559 mutex_lock(&data->update_lock);
1560
Guenter Roeck6445e662013-04-21 09:13:28 -07001561 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001562 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001563 /* Fan clock dividers */
1564 nct6775_update_fan_div_common(data);
1565
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001566 /* Measured voltages and limits */
1567 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001568 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001569 continue;
1570
1571 data->in[i][0] = nct6775_read_value(data,
1572 data->REG_VIN[i]);
1573 data->in[i][1] = nct6775_read_value(data,
1574 data->REG_IN_MINMAX[0][i]);
1575 data->in[i][2] = nct6775_read_value(data,
1576 data->REG_IN_MINMAX[1][i]);
1577 }
1578
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001579 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001580 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001581 u16 reg;
1582
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001583 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001584 continue;
1585
1586 reg = nct6775_read_value(data, data->REG_FAN[i]);
1587 data->rpm[i] = data->fan_from_reg(reg,
1588 data->fan_div[i]);
1589
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001590 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001591 data->fan_min[i] = nct6775_read_value(data,
1592 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001593 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001594 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1595 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001596
1597 nct6775_select_fan_div(dev, data, i, reg);
1598 }
1599
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001600 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001601 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001602
Guenter Roeckaa136e52012-12-04 03:26:05 -08001603 /* Measured temperatures and limits */
1604 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001605 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001606 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001607 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001608 if (data->reg_temp[j][i])
1609 data->temp[j][i]
1610 = nct6775_read_temp(data,
1611 data->reg_temp[j][i]);
1612 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001613 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001614 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001615 continue;
1616 data->temp_offset[i]
1617 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1618 }
1619
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001620 data->alarms = 0;
1621 for (i = 0; i < NUM_REG_ALARM; i++) {
1622 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001623
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001624 if (!data->REG_ALARM[i])
1625 continue;
1626 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1627 data->alarms |= ((u64)alarm) << (i << 3);
1628 }
1629
Guenter Roeck30846992013-06-24 22:21:59 -07001630 data->beeps = 0;
1631 for (i = 0; i < NUM_REG_BEEP; i++) {
1632 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001633
Guenter Roeck30846992013-06-24 22:21:59 -07001634 if (!data->REG_BEEP[i])
1635 continue;
1636 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1637 data->beeps |= ((u64)beep) << (i << 3);
1638 }
1639
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001640 data->last_updated = jiffies;
1641 data->valid = true;
1642 }
1643
1644 mutex_unlock(&data->update_lock);
1645 return data;
1646}
1647
1648/*
1649 * Sysfs callback functions
1650 */
1651static ssize_t
1652show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1653{
1654 struct nct6775_data *data = nct6775_update_device(dev);
1655 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001656 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001657 int nr = sattr->nr;
1658
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001659 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1660}
1661
1662static ssize_t
1663store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1664 size_t count)
1665{
1666 struct nct6775_data *data = dev_get_drvdata(dev);
1667 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001668 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001669 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001670 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001671 int err;
1672
1673 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001674 if (err < 0)
1675 return err;
1676 mutex_lock(&data->update_lock);
1677 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001678 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001679 data->in[nr][index]);
1680 mutex_unlock(&data->update_lock);
1681 return count;
1682}
1683
1684static ssize_t
1685show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1686{
1687 struct nct6775_data *data = nct6775_update_device(dev);
1688 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1689 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001690
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001691 return sprintf(buf, "%u\n",
1692 (unsigned int)((data->alarms >> nr) & 0x01));
1693}
1694
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001695static int find_temp_source(struct nct6775_data *data, int index, int count)
1696{
1697 int source = data->temp_src[index];
1698 int nr;
1699
1700 for (nr = 0; nr < count; nr++) {
1701 int src;
1702
1703 src = nct6775_read_value(data,
1704 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1705 if (src == source)
1706 return nr;
1707 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001708 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001709}
1710
1711static ssize_t
1712show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1713{
1714 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1715 struct nct6775_data *data = nct6775_update_device(dev);
1716 unsigned int alarm = 0;
1717 int nr;
1718
1719 /*
1720 * For temperatures, there is no fixed mapping from registers to alarm
1721 * bits. Alarm bits are determined by the temperature source mapping.
1722 */
1723 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1724 if (nr >= 0) {
1725 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001726
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001727 alarm = (data->alarms >> bit) & 0x01;
1728 }
1729 return sprintf(buf, "%u\n", alarm);
1730}
1731
Guenter Roeck30846992013-06-24 22:21:59 -07001732static ssize_t
1733show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1734{
1735 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1736 struct nct6775_data *data = nct6775_update_device(dev);
1737 int nr = data->BEEP_BITS[sattr->index];
1738
1739 return sprintf(buf, "%u\n",
1740 (unsigned int)((data->beeps >> nr) & 0x01));
1741}
1742
1743static ssize_t
1744store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1745 size_t count)
1746{
1747 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1748 struct nct6775_data *data = dev_get_drvdata(dev);
1749 int nr = data->BEEP_BITS[sattr->index];
1750 int regindex = nr >> 3;
1751 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001752 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001753
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001754 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001755 if (err < 0)
1756 return err;
1757 if (val > 1)
1758 return -EINVAL;
1759
1760 mutex_lock(&data->update_lock);
1761 if (val)
1762 data->beeps |= (1ULL << nr);
1763 else
1764 data->beeps &= ~(1ULL << nr);
1765 nct6775_write_value(data, data->REG_BEEP[regindex],
1766 (data->beeps >> (regindex << 3)) & 0xff);
1767 mutex_unlock(&data->update_lock);
1768 return count;
1769}
1770
1771static ssize_t
1772show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1773{
1774 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1775 struct nct6775_data *data = nct6775_update_device(dev);
1776 unsigned int beep = 0;
1777 int nr;
1778
1779 /*
1780 * For temperatures, there is no fixed mapping from registers to beep
1781 * enable bits. Beep enable bits are determined by the temperature
1782 * source mapping.
1783 */
1784 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1785 if (nr >= 0) {
1786 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001787
Guenter Roeck30846992013-06-24 22:21:59 -07001788 beep = (data->beeps >> bit) & 0x01;
1789 }
1790 return sprintf(buf, "%u\n", beep);
1791}
1792
1793static ssize_t
1794store_temp_beep(struct device *dev, struct device_attribute *attr,
1795 const char *buf, size_t count)
1796{
1797 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1798 struct nct6775_data *data = dev_get_drvdata(dev);
1799 int nr, bit, regindex;
1800 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001801 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001802
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001803 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001804 if (err < 0)
1805 return err;
1806 if (val > 1)
1807 return -EINVAL;
1808
1809 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1810 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001811 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001812
1813 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1814 regindex = bit >> 3;
1815
1816 mutex_lock(&data->update_lock);
1817 if (val)
1818 data->beeps |= (1ULL << bit);
1819 else
1820 data->beeps &= ~(1ULL << bit);
1821 nct6775_write_value(data, data->REG_BEEP[regindex],
1822 (data->beeps >> (regindex << 3)) & 0xff);
1823 mutex_unlock(&data->update_lock);
1824
1825 return count;
1826}
1827
Guenter Roeckf73cf632013-03-18 09:22:50 -07001828static umode_t nct6775_in_is_visible(struct kobject *kobj,
1829 struct attribute *attr, int index)
1830{
1831 struct device *dev = container_of(kobj, struct device, kobj);
1832 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001833 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001834
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001835 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001836 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001837
Guenter Roeckf73cf632013-03-18 09:22:50 -07001838 return attr->mode;
1839}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001840
Guenter Roeckf73cf632013-03-18 09:22:50 -07001841SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1842SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001843SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1844 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001845SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1846 store_in_reg, 0, 1);
1847SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1848 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001849
Guenter Roeckf73cf632013-03-18 09:22:50 -07001850/*
1851 * nct6775_in_is_visible uses the index into the following array
1852 * to determine if attributes should be created or not.
1853 * Any change in order or content must be matched.
1854 */
1855static struct sensor_device_template *nct6775_attributes_in_template[] = {
1856 &sensor_dev_template_in_input,
1857 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001858 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001859 &sensor_dev_template_in_min,
1860 &sensor_dev_template_in_max,
1861 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001862};
1863
Julia Lawallc60fdf82015-12-12 17:36:39 +01001864static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001865 .templates = nct6775_attributes_in_template,
1866 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001867};
1868
1869static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001870show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1871{
1872 struct nct6775_data *data = nct6775_update_device(dev);
1873 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1874 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001875
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001876 return sprintf(buf, "%d\n", data->rpm[nr]);
1877}
1878
1879static ssize_t
1880show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1881{
1882 struct nct6775_data *data = nct6775_update_device(dev);
1883 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1884 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001885
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001886 return sprintf(buf, "%d\n",
1887 data->fan_from_reg_min(data->fan_min[nr],
1888 data->fan_div[nr]));
1889}
1890
1891static ssize_t
1892show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1893{
1894 struct nct6775_data *data = nct6775_update_device(dev);
1895 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1896 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001897
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001898 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1899}
1900
1901static ssize_t
1902store_fan_min(struct device *dev, struct device_attribute *attr,
1903 const char *buf, size_t count)
1904{
1905 struct nct6775_data *data = dev_get_drvdata(dev);
1906 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1907 int nr = sattr->index;
1908 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001909 unsigned int reg;
1910 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001911 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001912
1913 err = kstrtoul(buf, 10, &val);
1914 if (err < 0)
1915 return err;
1916
1917 mutex_lock(&data->update_lock);
1918 if (!data->has_fan_div) {
1919 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1920 if (!val) {
1921 val = 0xff1f;
1922 } else {
1923 if (val > 1350000U)
1924 val = 135000U;
1925 val = 1350000U / val;
1926 val = (val & 0x1f) | ((val << 3) & 0xff00);
1927 }
1928 data->fan_min[nr] = val;
1929 goto write_min; /* Leave fan divider alone */
1930 }
1931 if (!val) {
1932 /* No min limit, alarm disabled */
1933 data->fan_min[nr] = 255;
1934 new_div = data->fan_div[nr]; /* No change */
1935 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1936 goto write_div;
1937 }
1938 reg = 1350000U / val;
1939 if (reg >= 128 * 255) {
1940 /*
1941 * Speed below this value cannot possibly be represented,
1942 * even with the highest divider (128)
1943 */
1944 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001945 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001946 dev_warn(dev,
1947 "fan%u low limit %lu below minimum %u, set to minimum\n",
1948 nr + 1, val, data->fan_from_reg_min(254, 7));
1949 } else if (!reg) {
1950 /*
1951 * Speed above this value cannot possibly be represented,
1952 * even with the lowest divider (1)
1953 */
1954 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001955 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001956 dev_warn(dev,
1957 "fan%u low limit %lu above maximum %u, set to maximum\n",
1958 nr + 1, val, data->fan_from_reg_min(1, 0));
1959 } else {
1960 /*
1961 * Automatically pick the best divider, i.e. the one such
1962 * that the min limit will correspond to a register value
1963 * in the 96..192 range
1964 */
1965 new_div = 0;
1966 while (reg > 192 && new_div < 7) {
1967 reg >>= 1;
1968 new_div++;
1969 }
1970 data->fan_min[nr] = reg;
1971 }
1972
1973write_div:
1974 /*
1975 * Write both the fan clock divider (if it changed) and the new
1976 * fan min (unconditionally)
1977 */
1978 if (new_div != data->fan_div[nr]) {
1979 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1980 nr + 1, div_from_reg(data->fan_div[nr]),
1981 div_from_reg(new_div));
1982 data->fan_div[nr] = new_div;
1983 nct6775_write_fan_div_common(data, nr);
1984 /* Give the chip time to sample a new speed value */
1985 data->last_updated = jiffies;
1986 }
1987
1988write_min:
1989 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1990 mutex_unlock(&data->update_lock);
1991
1992 return count;
1993}
1994
Guenter Roeck5c25d952012-12-11 07:29:06 -08001995static ssize_t
1996show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1997{
1998 struct nct6775_data *data = nct6775_update_device(dev);
1999 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2000 int p = data->fan_pulses[sattr->index];
2001
2002 return sprintf(buf, "%d\n", p ? : 4);
2003}
2004
2005static ssize_t
2006store_fan_pulses(struct device *dev, struct device_attribute *attr,
2007 const char *buf, size_t count)
2008{
2009 struct nct6775_data *data = dev_get_drvdata(dev);
2010 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2011 int nr = sattr->index;
2012 unsigned long val;
2013 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002014 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002015
2016 err = kstrtoul(buf, 10, &val);
2017 if (err < 0)
2018 return err;
2019
2020 if (val > 4)
2021 return -EINVAL;
2022
2023 mutex_lock(&data->update_lock);
2024 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002025 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2026 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2027 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2028 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002029 mutex_unlock(&data->update_lock);
2030
2031 return count;
2032}
2033
Guenter Roeckf73cf632013-03-18 09:22:50 -07002034static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2035 struct attribute *attr, int index)
2036{
2037 struct device *dev = container_of(kobj, struct device, kobj);
2038 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002039 int fan = index / 6; /* fan index */
2040 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002041
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002042 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002043 return 0;
2044
2045 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2046 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002047 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002048 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002049 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002050 return 0;
2051 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002052 return 0;
2053
2054 return attr->mode;
2055}
2056
2057SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2058SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2059 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002060SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2061 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002062SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2063 store_fan_pulses, 0);
2064SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2065 store_fan_min, 0);
2066SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2067
2068/*
2069 * nct6775_fan_is_visible uses the index into the following array
2070 * to determine if attributes should be created or not.
2071 * Any change in order or content must be matched.
2072 */
2073static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2074 &sensor_dev_template_fan_input,
2075 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002076 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002077 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002078 &sensor_dev_template_fan_min, /* 4 */
2079 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002080 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002081};
2082
Julia Lawallc60fdf82015-12-12 17:36:39 +01002083static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002084 .templates = nct6775_attributes_fan_template,
2085 .is_visible = nct6775_fan_is_visible,
2086 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002087};
2088
2089static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002090show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2091{
2092 struct nct6775_data *data = nct6775_update_device(dev);
2093 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2094 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002095
Guenter Roeckaa136e52012-12-04 03:26:05 -08002096 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2097}
2098
2099static ssize_t
2100show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2101{
2102 struct nct6775_data *data = nct6775_update_device(dev);
2103 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2104 int nr = sattr->nr;
2105 int index = sattr->index;
2106
2107 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2108}
2109
2110static ssize_t
2111store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2112 size_t count)
2113{
2114 struct nct6775_data *data = dev_get_drvdata(dev);
2115 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2116 int nr = sattr->nr;
2117 int index = sattr->index;
2118 int err;
2119 long val;
2120
2121 err = kstrtol(buf, 10, &val);
2122 if (err < 0)
2123 return err;
2124
2125 mutex_lock(&data->update_lock);
2126 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2127 nct6775_write_temp(data, data->reg_temp[index][nr],
2128 data->temp[index][nr]);
2129 mutex_unlock(&data->update_lock);
2130 return count;
2131}
2132
2133static ssize_t
2134show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2135{
2136 struct nct6775_data *data = nct6775_update_device(dev);
2137 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2138
2139 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2140}
2141
2142static ssize_t
2143store_temp_offset(struct device *dev, struct device_attribute *attr,
2144 const char *buf, size_t count)
2145{
2146 struct nct6775_data *data = dev_get_drvdata(dev);
2147 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2148 int nr = sattr->index;
2149 long val;
2150 int err;
2151
2152 err = kstrtol(buf, 10, &val);
2153 if (err < 0)
2154 return err;
2155
2156 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2157
2158 mutex_lock(&data->update_lock);
2159 data->temp_offset[nr] = val;
2160 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2161 mutex_unlock(&data->update_lock);
2162
2163 return count;
2164}
2165
2166static ssize_t
2167show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2168{
2169 struct nct6775_data *data = nct6775_update_device(dev);
2170 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2171 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002172
Guenter Roeckaa136e52012-12-04 03:26:05 -08002173 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2174}
2175
2176static ssize_t
2177store_temp_type(struct device *dev, struct device_attribute *attr,
2178 const char *buf, size_t count)
2179{
2180 struct nct6775_data *data = nct6775_update_device(dev);
2181 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2182 int nr = sattr->index;
2183 unsigned long val;
2184 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002185 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002186
2187 err = kstrtoul(buf, 10, &val);
2188 if (err < 0)
2189 return err;
2190
2191 if (val != 1 && val != 3 && val != 4)
2192 return -EINVAL;
2193
2194 mutex_lock(&data->update_lock);
2195
2196 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002197 vbit = 0x02 << nr;
2198 dbit = data->DIODE_MASK << nr;
2199 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2200 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002201 switch (val) {
2202 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002203 vbat |= vbit;
2204 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002205 break;
2206 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002207 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002208 break;
2209 case 4: /* thermistor */
2210 break;
2211 }
2212 nct6775_write_value(data, data->REG_VBAT, vbat);
2213 nct6775_write_value(data, data->REG_DIODE, diode);
2214
2215 mutex_unlock(&data->update_lock);
2216 return count;
2217}
2218
Guenter Roeckf73cf632013-03-18 09:22:50 -07002219static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2220 struct attribute *attr, int index)
2221{
2222 struct device *dev = container_of(kobj, struct device, kobj);
2223 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002224 int temp = index / 10; /* temp index */
2225 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002226
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002227 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002228 return 0;
2229
Guenter Roeckcc66b302017-05-17 18:05:06 -07002230 if (nr == 1 && !data->temp_label)
2231 return 0;
2232
Guenter Roeckf73cf632013-03-18 09:22:50 -07002233 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2234 return 0; /* alarm */
2235
Guenter Roeck30846992013-06-24 22:21:59 -07002236 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2237 return 0; /* beep */
2238
2239 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002240 return 0;
2241
Guenter Roeck30846992013-06-24 22:21:59 -07002242 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002243 return 0;
2244
Guenter Roeck30846992013-06-24 22:21:59 -07002245 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002246 return 0;
2247
Guenter Roeck30846992013-06-24 22:21:59 -07002248 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002249 return 0;
2250
2251 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002252 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002253 return 0;
2254
2255 return attr->mode;
2256}
2257
2258SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2259SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2260SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2261 store_temp, 0, 1);
2262SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2263 show_temp, store_temp, 0, 2);
2264SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2265 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002266SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2267 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002268SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2269 show_temp_offset, store_temp_offset, 0);
2270SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2271 store_temp_type, 0);
2272SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002273SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2274 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002275
2276/*
2277 * nct6775_temp_is_visible uses the index into the following array
2278 * to determine if attributes should be created or not.
2279 * Any change in order or content must be matched.
2280 */
2281static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2282 &sensor_dev_template_temp_input,
2283 &sensor_dev_template_temp_label,
2284 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002285 &sensor_dev_template_temp_beep, /* 3 */
2286 &sensor_dev_template_temp_max, /* 4 */
2287 &sensor_dev_template_temp_max_hyst, /* 5 */
2288 &sensor_dev_template_temp_crit, /* 6 */
2289 &sensor_dev_template_temp_lcrit, /* 7 */
2290 &sensor_dev_template_temp_offset, /* 8 */
2291 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002292 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002293};
2294
Julia Lawallc60fdf82015-12-12 17:36:39 +01002295static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002296 .templates = nct6775_attributes_temp_template,
2297 .is_visible = nct6775_temp_is_visible,
2298 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002299};
2300
Guenter Roeckaa136e52012-12-04 03:26:05 -08002301static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002302show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2303{
2304 struct nct6775_data *data = nct6775_update_device(dev);
2305 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2306
2307 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2308}
2309
2310static ssize_t
2311store_pwm_mode(struct device *dev, struct device_attribute *attr,
2312 const char *buf, size_t count)
2313{
2314 struct nct6775_data *data = dev_get_drvdata(dev);
2315 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2316 int nr = sattr->index;
2317 unsigned long val;
2318 int err;
2319 u8 reg;
2320
2321 err = kstrtoul(buf, 10, &val);
2322 if (err < 0)
2323 return err;
2324
2325 if (val > 1)
2326 return -EINVAL;
2327
2328 /* Setting DC mode is not supported for all chips/channels */
2329 if (data->REG_PWM_MODE[nr] == 0) {
2330 if (val)
2331 return -EINVAL;
2332 return count;
2333 }
2334
2335 mutex_lock(&data->update_lock);
2336 data->pwm_mode[nr] = val;
2337 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2338 reg &= ~data->PWM_MODE_MASK[nr];
2339 if (val)
2340 reg |= data->PWM_MODE_MASK[nr];
2341 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2342 mutex_unlock(&data->update_lock);
2343 return count;
2344}
2345
2346static ssize_t
2347show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2348{
2349 struct nct6775_data *data = nct6775_update_device(dev);
2350 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2351 int nr = sattr->nr;
2352 int index = sattr->index;
2353 int pwm;
2354
2355 /*
2356 * For automatic fan control modes, show current pwm readings.
2357 * Otherwise, show the configured value.
2358 */
2359 if (index == 0 && data->pwm_enable[nr] > manual)
2360 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2361 else
2362 pwm = data->pwm[index][nr];
2363
2364 return sprintf(buf, "%d\n", pwm);
2365}
2366
2367static ssize_t
2368store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2369 size_t count)
2370{
2371 struct nct6775_data *data = dev_get_drvdata(dev);
2372 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2373 int nr = sattr->nr;
2374 int index = sattr->index;
2375 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002376 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2377 int maxval[7]
2378 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002379 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002380 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002381
2382 err = kstrtoul(buf, 10, &val);
2383 if (err < 0)
2384 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002385 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002386
2387 mutex_lock(&data->update_lock);
2388 data->pwm[index][nr] = val;
2389 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002390 if (index == 2) { /* floor: disable if val == 0 */
2391 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2392 reg &= 0x7f;
2393 if (val)
2394 reg |= 0x80;
2395 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2396 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002397 mutex_unlock(&data->update_lock);
2398 return count;
2399}
2400
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002401/* Returns 0 if OK, -EINVAL otherwise */
2402static int check_trip_points(struct nct6775_data *data, int nr)
2403{
2404 int i;
2405
2406 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2407 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2408 return -EINVAL;
2409 }
2410 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2411 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2412 return -EINVAL;
2413 }
2414 /* validate critical temperature and pwm if enabled (pwm > 0) */
2415 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2416 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2417 data->auto_temp[nr][data->auto_pwm_num] ||
2418 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2419 data->auto_pwm[nr][data->auto_pwm_num])
2420 return -EINVAL;
2421 }
2422 return 0;
2423}
2424
2425static void pwm_update_registers(struct nct6775_data *data, int nr)
2426{
2427 u8 reg;
2428
2429 switch (data->pwm_enable[nr]) {
2430 case off:
2431 case manual:
2432 break;
2433 case speed_cruise:
2434 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2435 reg = (reg & ~data->tolerance_mask) |
2436 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2437 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2438 nct6775_write_value(data, data->REG_TARGET[nr],
2439 data->target_speed[nr] & 0xff);
2440 if (data->REG_TOLERANCE_H) {
2441 reg = (data->target_speed[nr] >> 8) & 0x0f;
2442 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2443 nct6775_write_value(data,
2444 data->REG_TOLERANCE_H[nr],
2445 reg);
2446 }
2447 break;
2448 case thermal_cruise:
2449 nct6775_write_value(data, data->REG_TARGET[nr],
2450 data->target_temp[nr]);
2451 /* intentional */
2452 default:
2453 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2454 reg = (reg & ~data->tolerance_mask) |
2455 data->temp_tolerance[0][nr];
2456 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2457 break;
2458 }
2459}
2460
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002461static ssize_t
2462show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2463{
2464 struct nct6775_data *data = nct6775_update_device(dev);
2465 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2466
2467 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2468}
2469
2470static ssize_t
2471store_pwm_enable(struct device *dev, struct device_attribute *attr,
2472 const char *buf, size_t count)
2473{
2474 struct nct6775_data *data = dev_get_drvdata(dev);
2475 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2476 int nr = sattr->index;
2477 unsigned long val;
2478 int err;
2479 u16 reg;
2480
2481 err = kstrtoul(buf, 10, &val);
2482 if (err < 0)
2483 return err;
2484
2485 if (val > sf4)
2486 return -EINVAL;
2487
2488 if (val == sf3 && data->kind != nct6775)
2489 return -EINVAL;
2490
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002491 if (val == sf4 && check_trip_points(data, nr)) {
2492 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2493 dev_err(dev, "Adjust trip points and try again\n");
2494 return -EINVAL;
2495 }
2496
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002497 mutex_lock(&data->update_lock);
2498 data->pwm_enable[nr] = val;
2499 if (val == off) {
2500 /*
2501 * turn off pwm control: select manual mode, set pwm to maximum
2502 */
2503 data->pwm[0][nr] = 255;
2504 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2505 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002506 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002507 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2508 reg &= 0x0f;
2509 reg |= pwm_enable_to_reg(val) << 4;
2510 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2511 mutex_unlock(&data->update_lock);
2512 return count;
2513}
2514
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002515static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002516show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002517{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002518 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002519
2520 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002521 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002522 continue;
2523 if (src == data->temp_src[i]) {
2524 sel = i + 1;
2525 break;
2526 }
2527 }
2528
2529 return sprintf(buf, "%d\n", sel);
2530}
2531
2532static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002533show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2534{
2535 struct nct6775_data *data = nct6775_update_device(dev);
2536 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2537 int index = sattr->index;
2538
2539 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2540}
2541
2542static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002543store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2544 const char *buf, size_t count)
2545{
2546 struct nct6775_data *data = nct6775_update_device(dev);
2547 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2548 int nr = sattr->index;
2549 unsigned long val;
2550 int err, reg, src;
2551
2552 err = kstrtoul(buf, 10, &val);
2553 if (err < 0)
2554 return err;
2555 if (val == 0 || val > NUM_TEMP)
2556 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002557 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002558 return -EINVAL;
2559
2560 mutex_lock(&data->update_lock);
2561 src = data->temp_src[val - 1];
2562 data->pwm_temp_sel[nr] = src;
2563 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2564 reg &= 0xe0;
2565 reg |= src;
2566 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2567 mutex_unlock(&data->update_lock);
2568
2569 return count;
2570}
2571
2572static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002573show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2574 char *buf)
2575{
2576 struct nct6775_data *data = nct6775_update_device(dev);
2577 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2578 int index = sattr->index;
2579
2580 return show_pwm_temp_sel_common(data, buf,
2581 data->pwm_weight_temp_sel[index]);
2582}
2583
2584static ssize_t
2585store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2586 const char *buf, size_t count)
2587{
2588 struct nct6775_data *data = nct6775_update_device(dev);
2589 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2590 int nr = sattr->index;
2591 unsigned long val;
2592 int err, reg, src;
2593
2594 err = kstrtoul(buf, 10, &val);
2595 if (err < 0)
2596 return err;
2597 if (val > NUM_TEMP)
2598 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002599 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002600 !data->temp_src[val - 1]))
2601 return -EINVAL;
2602
2603 mutex_lock(&data->update_lock);
2604 if (val) {
2605 src = data->temp_src[val - 1];
2606 data->pwm_weight_temp_sel[nr] = src;
2607 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2608 reg &= 0xe0;
2609 reg |= (src | 0x80);
2610 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2611 } else {
2612 data->pwm_weight_temp_sel[nr] = 0;
2613 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2614 reg &= 0x7f;
2615 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2616 }
2617 mutex_unlock(&data->update_lock);
2618
2619 return count;
2620}
2621
2622static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002623show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2624{
2625 struct nct6775_data *data = nct6775_update_device(dev);
2626 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2627
2628 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2629}
2630
2631static ssize_t
2632store_target_temp(struct device *dev, struct device_attribute *attr,
2633 const char *buf, size_t count)
2634{
2635 struct nct6775_data *data = dev_get_drvdata(dev);
2636 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2637 int nr = sattr->index;
2638 unsigned long val;
2639 int err;
2640
2641 err = kstrtoul(buf, 10, &val);
2642 if (err < 0)
2643 return err;
2644
2645 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2646 data->target_temp_mask);
2647
2648 mutex_lock(&data->update_lock);
2649 data->target_temp[nr] = val;
2650 pwm_update_registers(data, nr);
2651 mutex_unlock(&data->update_lock);
2652 return count;
2653}
2654
2655static ssize_t
2656show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2657{
2658 struct nct6775_data *data = nct6775_update_device(dev);
2659 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2660 int nr = sattr->index;
2661
2662 return sprintf(buf, "%d\n",
2663 fan_from_reg16(data->target_speed[nr],
2664 data->fan_div[nr]));
2665}
2666
2667static ssize_t
2668store_target_speed(struct device *dev, struct device_attribute *attr,
2669 const char *buf, size_t count)
2670{
2671 struct nct6775_data *data = dev_get_drvdata(dev);
2672 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2673 int nr = sattr->index;
2674 unsigned long val;
2675 int err;
2676 u16 speed;
2677
2678 err = kstrtoul(buf, 10, &val);
2679 if (err < 0)
2680 return err;
2681
2682 val = clamp_val(val, 0, 1350000U);
2683 speed = fan_to_reg(val, data->fan_div[nr]);
2684
2685 mutex_lock(&data->update_lock);
2686 data->target_speed[nr] = speed;
2687 pwm_update_registers(data, nr);
2688 mutex_unlock(&data->update_lock);
2689 return count;
2690}
2691
2692static ssize_t
2693show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2694 char *buf)
2695{
2696 struct nct6775_data *data = nct6775_update_device(dev);
2697 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2698 int nr = sattr->nr;
2699 int index = sattr->index;
2700
2701 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2702}
2703
2704static ssize_t
2705store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2706 const char *buf, size_t count)
2707{
2708 struct nct6775_data *data = dev_get_drvdata(dev);
2709 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2710 int nr = sattr->nr;
2711 int index = sattr->index;
2712 unsigned long val;
2713 int err;
2714
2715 err = kstrtoul(buf, 10, &val);
2716 if (err < 0)
2717 return err;
2718
2719 /* Limit tolerance as needed */
2720 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2721
2722 mutex_lock(&data->update_lock);
2723 data->temp_tolerance[index][nr] = val;
2724 if (index)
2725 pwm_update_registers(data, nr);
2726 else
2727 nct6775_write_value(data,
2728 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2729 val);
2730 mutex_unlock(&data->update_lock);
2731 return count;
2732}
2733
2734/*
2735 * Fan speed tolerance is a tricky beast, since the associated register is
2736 * a tick counter, but the value is reported and configured as rpm.
2737 * Compute resulting low and high rpm values and report the difference.
2738 */
2739static ssize_t
2740show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2741 char *buf)
2742{
2743 struct nct6775_data *data = nct6775_update_device(dev);
2744 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2745 int nr = sattr->index;
2746 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2747 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2748 int tolerance;
2749
2750 if (low <= 0)
2751 low = 1;
2752 if (high > 0xffff)
2753 high = 0xffff;
2754 if (high < low)
2755 high = low;
2756
2757 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2758 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2759
2760 return sprintf(buf, "%d\n", tolerance);
2761}
2762
2763static ssize_t
2764store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2765 const char *buf, size_t count)
2766{
2767 struct nct6775_data *data = dev_get_drvdata(dev);
2768 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2769 int nr = sattr->index;
2770 unsigned long val;
2771 int err;
2772 int low, high;
2773
2774 err = kstrtoul(buf, 10, &val);
2775 if (err < 0)
2776 return err;
2777
2778 high = fan_from_reg16(data->target_speed[nr],
2779 data->fan_div[nr]) + val;
2780 low = fan_from_reg16(data->target_speed[nr],
2781 data->fan_div[nr]) - val;
2782 if (low <= 0)
2783 low = 1;
2784 if (high < low)
2785 high = low;
2786
2787 val = (fan_to_reg(low, data->fan_div[nr]) -
2788 fan_to_reg(high, data->fan_div[nr])) / 2;
2789
2790 /* Limit tolerance as needed */
2791 val = clamp_val(val, 0, data->speed_tolerance_limit);
2792
2793 mutex_lock(&data->update_lock);
2794 data->target_speed_tolerance[nr] = val;
2795 pwm_update_registers(data, nr);
2796 mutex_unlock(&data->update_lock);
2797 return count;
2798}
2799
Guenter Roeckf73cf632013-03-18 09:22:50 -07002800SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2801SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2802 store_pwm_mode, 0);
2803SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2804 store_pwm_enable, 0);
2805SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2806 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2807SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2808 show_target_temp, store_target_temp, 0);
2809SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2810 show_target_speed, store_target_speed, 0);
2811SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2812 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002813
2814/* Smart Fan registers */
2815
2816static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002817show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2818{
2819 struct nct6775_data *data = nct6775_update_device(dev);
2820 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2821 int nr = sattr->nr;
2822 int index = sattr->index;
2823
2824 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2825}
2826
2827static ssize_t
2828store_weight_temp(struct device *dev, struct device_attribute *attr,
2829 const char *buf, size_t count)
2830{
2831 struct nct6775_data *data = dev_get_drvdata(dev);
2832 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2833 int nr = sattr->nr;
2834 int index = sattr->index;
2835 unsigned long val;
2836 int err;
2837
2838 err = kstrtoul(buf, 10, &val);
2839 if (err < 0)
2840 return err;
2841
2842 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2843
2844 mutex_lock(&data->update_lock);
2845 data->weight_temp[index][nr] = val;
2846 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2847 mutex_unlock(&data->update_lock);
2848 return count;
2849}
2850
Guenter Roeckf73cf632013-03-18 09:22:50 -07002851SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2852 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2853SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2854 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2855SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2856 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2857SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2858 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2859SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2860 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2861SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2862 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002863
2864static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002865show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2866{
2867 struct nct6775_data *data = nct6775_update_device(dev);
2868 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2869 int nr = sattr->nr;
2870 int index = sattr->index;
2871
2872 return sprintf(buf, "%d\n",
2873 step_time_from_reg(data->fan_time[index][nr],
2874 data->pwm_mode[nr]));
2875}
2876
2877static ssize_t
2878store_fan_time(struct device *dev, struct device_attribute *attr,
2879 const char *buf, size_t count)
2880{
2881 struct nct6775_data *data = dev_get_drvdata(dev);
2882 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2883 int nr = sattr->nr;
2884 int index = sattr->index;
2885 unsigned long val;
2886 int err;
2887
2888 err = kstrtoul(buf, 10, &val);
2889 if (err < 0)
2890 return err;
2891
2892 val = step_time_to_reg(val, data->pwm_mode[nr]);
2893 mutex_lock(&data->update_lock);
2894 data->fan_time[index][nr] = val;
2895 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2896 mutex_unlock(&data->update_lock);
2897 return count;
2898}
2899
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002900static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002901show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2902{
2903 struct nct6775_data *data = nct6775_update_device(dev);
2904 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2905
2906 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2907}
2908
2909static ssize_t
2910store_auto_pwm(struct device *dev, struct device_attribute *attr,
2911 const char *buf, size_t count)
2912{
2913 struct nct6775_data *data = dev_get_drvdata(dev);
2914 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2915 int nr = sattr->nr;
2916 int point = sattr->index;
2917 unsigned long val;
2918 int err;
2919 u8 reg;
2920
2921 err = kstrtoul(buf, 10, &val);
2922 if (err < 0)
2923 return err;
2924 if (val > 255)
2925 return -EINVAL;
2926
2927 if (point == data->auto_pwm_num) {
2928 if (data->kind != nct6775 && !val)
2929 return -EINVAL;
2930 if (data->kind != nct6779 && val)
2931 val = 0xff;
2932 }
2933
2934 mutex_lock(&data->update_lock);
2935 data->auto_pwm[nr][point] = val;
2936 if (point < data->auto_pwm_num) {
2937 nct6775_write_value(data,
2938 NCT6775_AUTO_PWM(data, nr, point),
2939 data->auto_pwm[nr][point]);
2940 } else {
2941 switch (data->kind) {
2942 case nct6775:
2943 /* disable if needed (pwm == 0) */
2944 reg = nct6775_read_value(data,
2945 NCT6775_REG_CRITICAL_ENAB[nr]);
2946 if (val)
2947 reg |= 0x02;
2948 else
2949 reg &= ~0x02;
2950 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2951 reg);
2952 break;
2953 case nct6776:
2954 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002955 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002956 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002957 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08002958 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002959 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002960 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002961 val);
2962 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002963 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002964 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002965 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002966 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002967 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002968 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002969 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002970 reg);
2971 break;
2972 }
2973 }
2974 mutex_unlock(&data->update_lock);
2975 return count;
2976}
2977
2978static ssize_t
2979show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2980{
2981 struct nct6775_data *data = nct6775_update_device(dev);
2982 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2983 int nr = sattr->nr;
2984 int point = sattr->index;
2985
2986 /*
2987 * We don't know for sure if the temperature is signed or unsigned.
2988 * Assume it is unsigned.
2989 */
2990 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2991}
2992
2993static ssize_t
2994store_auto_temp(struct device *dev, struct device_attribute *attr,
2995 const char *buf, size_t count)
2996{
2997 struct nct6775_data *data = dev_get_drvdata(dev);
2998 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2999 int nr = sattr->nr;
3000 int point = sattr->index;
3001 unsigned long val;
3002 int err;
3003
3004 err = kstrtoul(buf, 10, &val);
3005 if (err)
3006 return err;
3007 if (val > 255000)
3008 return -EINVAL;
3009
3010 mutex_lock(&data->update_lock);
3011 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3012 if (point < data->auto_pwm_num) {
3013 nct6775_write_value(data,
3014 NCT6775_AUTO_TEMP(data, nr, point),
3015 data->auto_temp[nr][point]);
3016 } else {
3017 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3018 data->auto_temp[nr][point]);
3019 }
3020 mutex_unlock(&data->update_lock);
3021 return count;
3022}
3023
Guenter Roeckf73cf632013-03-18 09:22:50 -07003024static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3025 struct attribute *attr, int index)
3026{
3027 struct device *dev = container_of(kobj, struct device, kobj);
3028 struct nct6775_data *data = dev_get_drvdata(dev);
3029 int pwm = index / 36; /* pwm index */
3030 int nr = index % 36; /* attribute index */
3031
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003032 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003033 return 0;
3034
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003035 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3036 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3037 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003038 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3039 return 0;
3040 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3041 return 0;
3042 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3043 return 0;
3044
3045 if (nr >= 22 && nr <= 35) { /* auto point */
3046 int api = (nr - 22) / 2; /* auto point index */
3047
3048 if (api > data->auto_pwm_num)
3049 return 0;
3050 }
3051 return attr->mode;
3052}
3053
3054SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3055 show_fan_time, store_fan_time, 0, 0);
3056SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3057 show_fan_time, store_fan_time, 0, 1);
3058SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3059 show_fan_time, store_fan_time, 0, 2);
3060SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3061 store_pwm, 0, 1);
3062SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3063 store_pwm, 0, 2);
3064SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3065 show_temp_tolerance, store_temp_tolerance, 0, 0);
3066SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3067 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3068 0, 1);
3069
3070SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3071 0, 3);
3072
3073SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3074 store_pwm, 0, 4);
3075
3076SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3077 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3078SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3079 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3080
3081SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3082 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3083SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3084 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3085
3086SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3087 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3088SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3089 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3090
3091SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3092 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3093SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3094 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3095
3096SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3097 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3098SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3099 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3100
3101SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3102 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3103SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3104 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3105
3106SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3107 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3108SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3109 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3110
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003111/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003112 * nct6775_pwm_is_visible uses the index into the following array
3113 * to determine if attributes should be created or not.
3114 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003115 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003116static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3117 &sensor_dev_template_pwm,
3118 &sensor_dev_template_pwm_mode,
3119 &sensor_dev_template_pwm_enable,
3120 &sensor_dev_template_pwm_temp_sel,
3121 &sensor_dev_template_pwm_temp_tolerance,
3122 &sensor_dev_template_pwm_crit_temp_tolerance,
3123 &sensor_dev_template_pwm_target_temp,
3124 &sensor_dev_template_fan_target,
3125 &sensor_dev_template_fan_tolerance,
3126 &sensor_dev_template_pwm_stop_time,
3127 &sensor_dev_template_pwm_step_up_time,
3128 &sensor_dev_template_pwm_step_down_time,
3129 &sensor_dev_template_pwm_start,
3130 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003131 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003132 &sensor_dev_template_pwm_weight_temp_step,
3133 &sensor_dev_template_pwm_weight_temp_step_tol,
3134 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003135 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003136 &sensor_dev_template_pwm_max, /* 19 */
3137 &sensor_dev_template_pwm_step, /* 20 */
3138 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3139 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3140 &sensor_dev_template_pwm_auto_point1_temp,
3141 &sensor_dev_template_pwm_auto_point2_pwm,
3142 &sensor_dev_template_pwm_auto_point2_temp,
3143 &sensor_dev_template_pwm_auto_point3_pwm,
3144 &sensor_dev_template_pwm_auto_point3_temp,
3145 &sensor_dev_template_pwm_auto_point4_pwm,
3146 &sensor_dev_template_pwm_auto_point4_temp,
3147 &sensor_dev_template_pwm_auto_point5_pwm,
3148 &sensor_dev_template_pwm_auto_point5_temp,
3149 &sensor_dev_template_pwm_auto_point6_pwm,
3150 &sensor_dev_template_pwm_auto_point6_temp,
3151 &sensor_dev_template_pwm_auto_point7_pwm,
3152 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003153
Guenter Roeckf73cf632013-03-18 09:22:50 -07003154 NULL
3155};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003156
Julia Lawallc60fdf82015-12-12 17:36:39 +01003157static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003158 .templates = nct6775_attributes_pwm_template,
3159 .is_visible = nct6775_pwm_is_visible,
3160 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003161};
3162
3163static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003164cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003165{
3166 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003167
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003168 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3169}
3170
Julia Lawall93d72ac2016-12-22 13:05:23 +01003171static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003172
Guenter Roecka6bd5872012-12-04 03:13:34 -08003173/* Case open detection */
3174
3175static ssize_t
3176clear_caseopen(struct device *dev, struct device_attribute *attr,
3177 const char *buf, size_t count)
3178{
3179 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003180 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3181 unsigned long val;
3182 u8 reg;
3183 int ret;
3184
3185 if (kstrtoul(buf, 10, &val) || val != 0)
3186 return -EINVAL;
3187
3188 mutex_lock(&data->update_lock);
3189
3190 /*
3191 * Use CR registers to clear caseopen status.
3192 * The CR registers are the same for all chips, and not all chips
3193 * support clearing the caseopen status through "regular" registers.
3194 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003195 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003196 if (ret) {
3197 count = ret;
3198 goto error;
3199 }
3200
Guenter Roeckdf612d52013-07-08 13:15:04 -07003201 superio_select(data->sioreg, NCT6775_LD_ACPI);
3202 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003203 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003204 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003205 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003206 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3207 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003208
3209 data->valid = false; /* Force cache refresh */
3210error:
3211 mutex_unlock(&data->update_lock);
3212 return count;
3213}
3214
Guenter Roeckf73cf632013-03-18 09:22:50 -07003215static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3216 clear_caseopen, INTRUSION_ALARM_BASE);
3217static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3218 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003219static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3220 store_beep, INTRUSION_ALARM_BASE);
3221static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3222 store_beep, INTRUSION_ALARM_BASE + 1);
3223static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3224 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003225
3226static umode_t nct6775_other_is_visible(struct kobject *kobj,
3227 struct attribute *attr, int index)
3228{
3229 struct device *dev = container_of(kobj, struct device, kobj);
3230 struct nct6775_data *data = dev_get_drvdata(dev);
3231
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003232 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003233 return 0;
3234
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003235 if (index == 1 || index == 2) {
3236 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003237 return 0;
3238 }
3239
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003240 if (index == 3 || index == 4) {
3241 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003242 return 0;
3243 }
3244
Guenter Roeckf73cf632013-03-18 09:22:50 -07003245 return attr->mode;
3246}
3247
3248/*
3249 * nct6775_other_is_visible uses the index into the following array
3250 * to determine if attributes should be created or not.
3251 * Any change in order or content must be matched.
3252 */
3253static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003254 &dev_attr_cpu0_vid.attr, /* 0 */
3255 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3256 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3257 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3258 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3259 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003260
3261 NULL
3262};
3263
3264static const struct attribute_group nct6775_group_other = {
3265 .attrs = nct6775_attributes_other,
3266 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003267};
3268
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003269static inline void nct6775_init_device(struct nct6775_data *data)
3270{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003271 int i;
3272 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003273
3274 /* Start monitoring if needed */
3275 if (data->REG_CONFIG) {
3276 tmp = nct6775_read_value(data, data->REG_CONFIG);
3277 if (!(tmp & 0x01))
3278 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3279 }
3280
Guenter Roeckaa136e52012-12-04 03:26:05 -08003281 /* Enable temperature sensors if needed */
3282 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003283 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003284 continue;
3285 if (!data->reg_temp_config[i])
3286 continue;
3287 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3288 if (tmp & 0x01)
3289 nct6775_write_value(data, data->reg_temp_config[i],
3290 tmp & 0xfe);
3291 }
3292
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003293 /* Enable VBAT monitoring if needed */
3294 tmp = nct6775_read_value(data, data->REG_VBAT);
3295 if (!(tmp & 0x01))
3296 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003297
3298 diode = nct6775_read_value(data, data->REG_DIODE);
3299
3300 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003301 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003302 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003303 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3304 data->temp_type[i]
3305 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003306 else /* thermistor */
3307 data->temp_type[i] = 4;
3308 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003309}
3310
Guenter Roeckf73cf632013-03-18 09:22:50 -07003311static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003312nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003313{
David Bartley578ab5f2013-06-24 22:28:28 -07003314 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3315 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003316 int sioreg = data->sioreg;
3317 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003318
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003319 /* Store SIO_REG_ENABLE for use during resume */
3320 superio_select(sioreg, NCT6775_LD_HWM);
3321 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3322
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003323 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3324 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003325 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003326
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003327 fan3pin = regval & BIT(6);
3328 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003329
3330 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003331 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003332 fan4min = false;
3333 fan5pin = false;
3334 fan6pin = false;
3335 pwm4pin = false;
3336 pwm5pin = false;
3337 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003338 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003339 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003340 const char *board_vendor, *board_name;
3341
3342 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3343 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3344
3345 if (board_name && board_vendor &&
3346 !strcmp(board_vendor, "ASRock")) {
3347 /*
3348 * Auxiliary fan monitoring is not enabled on ASRock
3349 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3350 * Observed with BIOS version 2.00.
3351 */
3352 if (!strcmp(board_name, "Z77 Pro4-M")) {
3353 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3354 data->sio_reg_enable |= 0xe0;
3355 superio_outb(sioreg, SIO_REG_ENABLE,
3356 data->sio_reg_enable);
3357 }
3358 }
3359 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003360
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003361 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003362 fan3pin = gpok;
3363 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003364 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003365
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003366 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003367 fan4pin = gpok;
3368 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003369 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003370
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003371 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003372 fan5pin = gpok;
3373 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003374 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003375
3376 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003377 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003378 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003379 pwm4pin = false;
3380 pwm5pin = false;
3381 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003382 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003383 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003384 fan3pin = !(regval & 0x80);
3385 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003386
3387 fan4pin = false;
3388 fan4min = false;
3389 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003390 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003391 pwm4pin = false;
3392 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003393 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003394 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003395 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003396
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003397 fan3pin = !(regval & BIT(5));
3398 fan4pin = !(regval & BIT(6));
3399 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003400
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003401 pwm3pin = !(regval & BIT(0));
3402 pwm4pin = !(regval & BIT(1));
3403 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003404
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003405 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003406
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003407 if (data->kind == nct6791 || data->kind == nct6792 ||
3408 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003409 regval = superio_inb(sioreg, 0x2d);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003410 fan6pin = (regval & BIT(1));
3411 pwm6pin = (regval & BIT(0));
David Bartley578ab5f2013-06-24 22:28:28 -07003412 } else { /* NCT6779D */
3413 fan6pin = false;
3414 pwm6pin = false;
3415 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003416 }
3417
David Bartley578ab5f2013-06-24 22:28:28 -07003418 /* fan 1 and 2 (0x03) are always present */
3419 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3420 (fan5pin << 4) | (fan6pin << 5);
3421 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3422 (fan5pin << 4);
3423 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3424 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003425}
3426
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003427static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3428 int *available, int *mask)
3429{
3430 int i;
3431 u8 src;
3432
3433 for (i = 0; i < data->pwm_num && *available; i++) {
3434 int index;
3435
3436 if (!regp[i])
3437 continue;
3438 src = nct6775_read_value(data, regp[i]);
3439 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003440 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003441 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003442 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003443 continue;
3444
3445 index = __ffs(*available);
3446 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003447 *available &= ~BIT(index);
3448 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003449 }
3450}
3451
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003452static int nct6775_probe(struct platform_device *pdev)
3453{
3454 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003455 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003456 struct nct6775_data *data;
3457 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003458 int i, s, err = 0;
3459 int src, mask, available;
3460 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003461 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003462 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003463 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003464 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003465 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003466 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003467 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003468
3469 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3470 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3471 DRVNAME))
3472 return -EBUSY;
3473
3474 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3475 GFP_KERNEL);
3476 if (!data)
3477 return -ENOMEM;
3478
3479 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003480 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003481 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003482 mutex_init(&data->update_lock);
3483 data->name = nct6775_device_names[data->kind];
3484 data->bank = 0xff; /* Force initial bank selection */
3485 platform_set_drvdata(pdev, data);
3486
3487 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003488 case nct6106:
3489 data->in_num = 9;
3490 data->pwm_num = 3;
3491 data->auto_pwm_num = 4;
3492 data->temp_fixed_num = 3;
3493 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003494 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003495
3496 data->fan_from_reg = fan_from_reg13;
3497 data->fan_from_reg_min = fan_from_reg13;
3498
3499 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003500 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003501
3502 data->REG_VBAT = NCT6106_REG_VBAT;
3503 data->REG_DIODE = NCT6106_REG_DIODE;
3504 data->DIODE_MASK = NCT6106_DIODE_MASK;
3505 data->REG_VIN = NCT6106_REG_IN;
3506 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3507 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3508 data->REG_TARGET = NCT6106_REG_TARGET;
3509 data->REG_FAN = NCT6106_REG_FAN;
3510 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3511 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3512 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3513 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3514 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3515 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3516 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3517 data->REG_PWM[0] = NCT6106_REG_PWM;
3518 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3519 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3520 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3521 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3522 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3523 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3524 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3525 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3526 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3527 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3528 data->REG_CRITICAL_TEMP_TOLERANCE
3529 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3530 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3531 data->CRITICAL_PWM_ENABLE_MASK
3532 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3533 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3534 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3535 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3536 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3537 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3538 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3539 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3540 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3541 data->REG_ALARM = NCT6106_REG_ALARM;
3542 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003543 data->REG_BEEP = NCT6106_REG_BEEP;
3544 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003545
3546 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003547 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003548 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003549 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003550 reg_temp_over = NCT6106_REG_TEMP_OVER;
3551 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3552 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3553 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3554 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003555 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3556 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003557
3558 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003559 case nct6775:
3560 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003561 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003562 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003563 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003564 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003565 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003566 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003567
3568 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003569 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003570
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003571 data->fan_from_reg = fan_from_reg16;
3572 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003573 data->target_temp_mask = 0x7f;
3574 data->tolerance_mask = 0x0f;
3575 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003576
Guenter Roeckaa136e52012-12-04 03:26:05 -08003577 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003578 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003579
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003580 data->REG_CONFIG = NCT6775_REG_CONFIG;
3581 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003582 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003583 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003584 data->REG_VIN = NCT6775_REG_IN;
3585 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3586 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003587 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003588 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003589 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003590 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003591 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003592 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003593 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3594 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3595 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003596 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003597 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3598 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3599 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3600 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003601 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003602 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3603 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3604 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003605 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3606 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3607 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3608 data->REG_CRITICAL_TEMP_TOLERANCE
3609 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003610 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3611 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003612 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003613 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3614 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3615 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3616 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003617 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003618 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003619
3620 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003621 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003622 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003623 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003624 reg_temp_over = NCT6775_REG_TEMP_OVER;
3625 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3626 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3627 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3628 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3629
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003630 break;
3631 case nct6776:
3632 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003633 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003634 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003635 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003636 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003637 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003638 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003639
3640 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003641 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003642
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003643 data->fan_from_reg = fan_from_reg13;
3644 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003645 data->target_temp_mask = 0xff;
3646 data->tolerance_mask = 0x07;
3647 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003648
Guenter Roeckaa136e52012-12-04 03:26:05 -08003649 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003650 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003651
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003652 data->REG_CONFIG = NCT6775_REG_CONFIG;
3653 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003654 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003655 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003656 data->REG_VIN = NCT6775_REG_IN;
3657 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3658 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003659 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003660 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003661 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003662 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003663 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003664 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003665 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003666 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3667 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003668 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003669 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003670 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3671 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003672 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3673 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003674 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3675 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3676 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003677 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3678 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3679 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3680 data->REG_CRITICAL_TEMP_TOLERANCE
3681 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003682 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3683 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003684 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003685 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3686 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3687 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3688 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003689 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003690 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003691
3692 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003693 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003694 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003695 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003696 reg_temp_over = NCT6775_REG_TEMP_OVER;
3697 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3698 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3699 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3700 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3701
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003702 break;
3703 case nct6779:
3704 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003705 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003706 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003707 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003708 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003709 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003710 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003711
3712 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003713 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003714
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003715 data->fan_from_reg = fan_from_reg13;
3716 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003717 data->target_temp_mask = 0xff;
3718 data->tolerance_mask = 0x07;
3719 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003720
Guenter Roeckaa136e52012-12-04 03:26:05 -08003721 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003722 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003723
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003724 data->REG_CONFIG = NCT6775_REG_CONFIG;
3725 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003726 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003727 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003728 data->REG_VIN = NCT6779_REG_IN;
3729 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3730 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003731 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003732 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003733 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003734 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003735 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003736 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003737 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003738 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3739 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003740 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003741 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003742 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3743 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003744 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3745 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003746 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3747 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3748 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003749 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3750 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3751 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3752 data->REG_CRITICAL_TEMP_TOLERANCE
3753 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003754 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3755 data->CRITICAL_PWM_ENABLE_MASK
3756 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3757 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003758 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3759 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003760 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003761 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3762 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3763 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3764 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003765 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003766 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003767
3768 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003769 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003770 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003771 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003772 reg_temp_over = NCT6779_REG_TEMP_OVER;
3773 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3774 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3775 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3776 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3777
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003778 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003779 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08003780 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003781 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003782 data->in_num = 15;
3783 data->pwm_num = 6;
3784 data->auto_pwm_num = 4;
3785 data->has_fan_div = false;
3786 data->temp_fixed_num = 6;
3787 data->num_temp_alarms = 2;
3788 data->num_temp_beeps = 2;
3789
3790 data->ALARM_BITS = NCT6791_ALARM_BITS;
3791 data->BEEP_BITS = NCT6779_BEEP_BITS;
3792
3793 data->fan_from_reg = fan_from_reg13;
3794 data->fan_from_reg_min = fan_from_reg13;
3795 data->target_temp_mask = 0xff;
3796 data->tolerance_mask = 0x07;
3797 data->speed_tolerance_limit = 63;
3798
Guenter Roeck50224f42015-10-30 07:52:39 -07003799 switch (data->kind) {
3800 default:
3801 case nct6791:
3802 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003803 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003804 break;
3805 case nct6792:
3806 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003807 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003808 break;
3809 case nct6793:
3810 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003811 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003812 break;
3813 }
David Bartley578ab5f2013-06-24 22:28:28 -07003814
3815 data->REG_CONFIG = NCT6775_REG_CONFIG;
3816 data->REG_VBAT = NCT6775_REG_VBAT;
3817 data->REG_DIODE = NCT6775_REG_DIODE;
3818 data->DIODE_MASK = NCT6775_DIODE_MASK;
3819 data->REG_VIN = NCT6779_REG_IN;
3820 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3821 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3822 data->REG_TARGET = NCT6775_REG_TARGET;
3823 data->REG_FAN = NCT6779_REG_FAN;
3824 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3825 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3826 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3827 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3828 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003829 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3830 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003831 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3832 data->REG_PWM[0] = NCT6775_REG_PWM;
3833 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3834 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003835 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3836 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003837 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3838 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3839 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3840 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3841 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3842 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3843 data->REG_CRITICAL_TEMP_TOLERANCE
3844 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3845 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3846 data->CRITICAL_PWM_ENABLE_MASK
3847 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3848 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3849 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3850 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3851 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003852 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3853 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3854 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3855 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003856 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08003857 if (data->kind == nct6791)
3858 data->REG_BEEP = NCT6776_REG_BEEP;
3859 else
3860 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003861
3862 reg_temp = NCT6779_REG_TEMP;
3863 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08003864 if (data->kind == nct6791) {
3865 reg_temp_mon = NCT6779_REG_TEMP_MON;
3866 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3867 } else {
3868 reg_temp_mon = NCT6792_REG_TEMP_MON;
3869 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3870 }
David Bartley578ab5f2013-06-24 22:28:28 -07003871 reg_temp_over = NCT6779_REG_TEMP_OVER;
3872 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3873 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3874 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3875 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3876
3877 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003878 default:
3879 return -ENODEV;
3880 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003881 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003882 data->have_temp = 0;
3883
3884 /*
3885 * On some boards, not all available temperature sources are monitored,
3886 * even though some of the monitoring registers are unused.
3887 * Get list of unused monitoring registers, then detect if any fan
3888 * controls are configured to use unmonitored temperature sources.
3889 * If so, assign the unmonitored temperature sources to available
3890 * monitoring registers.
3891 */
3892 mask = 0;
3893 available = 0;
3894 for (i = 0; i < num_reg_temp; i++) {
3895 if (reg_temp[i] == 0)
3896 continue;
3897
3898 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003899 if (!src || (mask & BIT(src)))
3900 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003901
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003902 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003903 }
3904
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003905 /*
3906 * Now find unmonitored temperature registers and enable monitoring
3907 * if additional monitoring registers are available.
3908 */
3909 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3910 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3911
Guenter Roeckaa136e52012-12-04 03:26:05 -08003912 mask = 0;
3913 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3914 for (i = 0; i < num_reg_temp; i++) {
3915 if (reg_temp[i] == 0)
3916 continue;
3917
3918 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003919 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003920 continue;
3921
Guenter Roeckcc66b302017-05-17 18:05:06 -07003922 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08003923 dev_info(dev,
3924 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3925 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3926 continue;
3927 }
3928
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003929 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003930
3931 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3932 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003933 data->have_temp |= BIT(src - 1);
3934 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003935 data->reg_temp[0][src - 1] = reg_temp[i];
3936 data->reg_temp[1][src - 1] = reg_temp_over[i];
3937 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003938 if (reg_temp_crit_h && reg_temp_crit_h[i])
3939 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3940 else if (reg_temp_crit[src - 1])
3941 data->reg_temp[3][src - 1]
3942 = reg_temp_crit[src - 1];
3943 if (reg_temp_crit_l && reg_temp_crit_l[i])
3944 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003945 data->reg_temp_config[src - 1] = reg_temp_config[i];
3946 data->temp_src[src - 1] = src;
3947 continue;
3948 }
3949
3950 if (s >= NUM_TEMP)
3951 continue;
3952
3953 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003954 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003955 data->reg_temp[0][s] = reg_temp[i];
3956 data->reg_temp[1][s] = reg_temp_over[i];
3957 data->reg_temp[2][s] = reg_temp_hyst[i];
3958 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003959 if (reg_temp_crit_h && reg_temp_crit_h[i])
3960 data->reg_temp[3][s] = reg_temp_crit_h[i];
3961 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003962 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003963 if (reg_temp_crit_l && reg_temp_crit_l[i])
3964 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003965
3966 data->temp_src[s] = src;
3967 s++;
3968 }
3969
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003970 /*
3971 * Repeat with temperatures used for fan control.
3972 * This set of registers does not support limits.
3973 */
3974 for (i = 0; i < num_reg_temp_mon; i++) {
3975 if (reg_temp_mon[i] == 0)
3976 continue;
3977
3978 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07003979 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003980 continue;
3981
Guenter Roeckcc66b302017-05-17 18:05:06 -07003982 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003983 dev_info(dev,
3984 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3985 src, i, data->REG_TEMP_SEL[i],
3986 reg_temp_mon[i]);
3987 continue;
3988 }
3989
Guenter Roeck7ce41902016-09-11 12:42:52 -07003990 /*
3991 * For virtual temperature sources, the 'virtual' temperature
3992 * for each fan reflects a different temperature, and there
3993 * are no duplicates.
3994 */
3995 if (src != TEMP_SOURCE_VIRTUAL) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003996 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07003997 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003998 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07003999 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004000
4001 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4002 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004003 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004004 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004005 data->have_temp |= BIT(src - 1);
4006 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004007 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4008 data->temp_src[src - 1] = src;
4009 continue;
4010 }
4011
4012 if (s >= NUM_TEMP)
4013 continue;
4014
4015 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004016 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004017 data->reg_temp[0][s] = reg_temp_mon[i];
4018 data->temp_src[s] = src;
4019 s++;
4020 }
4021
Guenter Roeckaa136e52012-12-04 03:26:05 -08004022#ifdef USE_ALTERNATE
4023 /*
4024 * Go through the list of alternate temp registers and enable
4025 * if possible.
4026 * The temperature is already monitored if the respective bit in <mask>
4027 * is set.
4028 */
Guenter Roeckcc66b302017-05-17 18:05:06 -07004029 for (i = 0; i < 32; i++) {
4030 if (!(data->temp_mask & BIT(i + 1)))
4031 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004032 if (!reg_temp_alternate[i])
4033 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004034 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004035 continue;
4036 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004037 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004038 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004039 data->have_temp |= BIT(i);
4040 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004041 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07004042 if (i < num_reg_temp) {
4043 data->reg_temp[1][i] = reg_temp_over[i];
4044 data->reg_temp[2][i] = reg_temp_hyst[i];
4045 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004046 data->temp_src[i] = i + 1;
4047 continue;
4048 }
4049
4050 if (s >= NUM_TEMP) /* Abort if no more space */
4051 break;
4052
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004053 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004054 data->reg_temp[0][s] = reg_temp_alternate[i];
4055 data->temp_src[s] = i + 1;
4056 s++;
4057 }
4058#endif /* USE_ALTERNATE */
4059
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004060 /* Initialize the chip */
4061 nct6775_init_device(data);
4062
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004063 err = superio_enter(sio_data->sioreg);
4064 if (err)
4065 return err;
4066
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004067 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4068 switch (data->kind) {
4069 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004070 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004071 break;
4072 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004073 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004074 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004075 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004076 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004077 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08004078 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004079 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004080 break;
4081 }
4082
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004083 /*
4084 * Read VID value
4085 * We can get the VID input values directly at logical device D 0xe3.
4086 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004087 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004088 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4089 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4090 data->vrm = vid_which_vrm();
4091 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004092
4093 if (fan_debounce) {
4094 u8 tmp;
4095
4096 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4097 tmp = superio_inb(sio_data->sioreg,
4098 NCT6775_REG_CR_FAN_DEBOUNCE);
4099 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004100 case nct6106:
4101 tmp |= 0xe0;
4102 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004103 case nct6775:
4104 tmp |= 0x1e;
4105 break;
4106 case nct6776:
4107 case nct6779:
4108 tmp |= 0x3e;
4109 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004110 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08004111 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004112 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07004113 tmp |= 0x7e;
4114 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004115 }
4116 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4117 tmp);
4118 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4119 data->name);
4120 }
4121
Guenter Roeckdf612d52013-07-08 13:15:04 -07004122 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004123
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004124 superio_exit(sio_data->sioreg);
4125
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004126 /* Read fan clock dividers immediately */
4127 nct6775_init_fan_common(dev, data);
4128
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004129 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004130 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4131 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004132 if (IS_ERR(group))
4133 return PTR_ERR(group);
4134
Axel Lin55bdee62014-07-24 08:59:34 +08004135 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004136
Guenter Roeckf73cf632013-03-18 09:22:50 -07004137 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4138 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004139 if (IS_ERR(group))
4140 return PTR_ERR(group);
4141
Axel Lin55bdee62014-07-24 08:59:34 +08004142 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004143
Guenter Roeckf73cf632013-03-18 09:22:50 -07004144 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4145 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004146 if (IS_ERR(group))
4147 return PTR_ERR(group);
4148
Axel Lin55bdee62014-07-24 08:59:34 +08004149 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004150
Guenter Roeckf73cf632013-03-18 09:22:50 -07004151 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4152 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004153 if (IS_ERR(group))
4154 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004155
Axel Lin55bdee62014-07-24 08:59:34 +08004156 data->groups[num_attr_groups++] = group;
4157 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004158
Guenter Roecka150d952013-07-11 22:55:22 -07004159 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4160 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004161 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004162}
4163
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004164static void nct6791_enable_io_mapping(int sioaddr)
4165{
4166 int val;
4167
4168 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4169 if (val & 0x10) {
4170 pr_info("Enabling hardware monitor logical device mappings.\n");
4171 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4172 val & ~0x10);
4173 }
4174}
4175
Guenter Roeck48e93182015-02-07 08:48:49 -08004176static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004177{
4178 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004179
4180 mutex_lock(&data->update_lock);
4181 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004182 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004183 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4184 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4185 }
4186 mutex_unlock(&data->update_lock);
4187
4188 return 0;
4189}
4190
Guenter Roeck48e93182015-02-07 08:48:49 -08004191static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004192{
4193 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004194 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004195 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004196 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004197
4198 mutex_lock(&data->update_lock);
4199 data->bank = 0xff; /* Force initial bank selection */
4200
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004201 err = superio_enter(sioreg);
4202 if (err)
4203 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004204
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004205 superio_select(sioreg, NCT6775_LD_HWM);
4206 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4207 if (reg != data->sio_reg_enable)
4208 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4209
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004210 if (data->kind == nct6791 || data->kind == nct6792 ||
4211 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004212 nct6791_enable_io_mapping(sioreg);
4213
4214 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004215
Guenter Roeck84d19d92012-12-04 08:01:39 -08004216 /* Restore limits */
4217 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004218 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004219 continue;
4220
4221 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4222 data->in[i][1]);
4223 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4224 data->in[i][2]);
4225 }
4226
Guenter Roeckc409fd42013-04-09 05:04:00 -07004227 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004228 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004229 continue;
4230
4231 nct6775_write_value(data, data->REG_FAN_MIN[i],
4232 data->fan_min[i]);
4233 }
4234
4235 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004236 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004237 continue;
4238
Guenter Roeckc409fd42013-04-09 05:04:00 -07004239 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004240 if (data->reg_temp[j][i])
4241 nct6775_write_temp(data, data->reg_temp[j][i],
4242 data->temp[j][i]);
4243 }
4244
4245 /* Restore other settings */
4246 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004247 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004248 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4249 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4250 }
4251
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004252abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004253 /* Force re-reading all values */
4254 data->valid = false;
4255 mutex_unlock(&data->update_lock);
4256
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004257 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004258}
4259
Guenter Roeck48e93182015-02-07 08:48:49 -08004260static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004261
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004262static struct platform_driver nct6775_driver = {
4263 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004264 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004265 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004266 },
4267 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004268};
4269
4270/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004271static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004272{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004273 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004274 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004275 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004276
4277 err = superio_enter(sioaddr);
4278 if (err)
4279 return err;
4280
Guenter Roeckfc72af32016-08-03 22:07:18 -07004281 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4282 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4283 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004284 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004285
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004286 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004287 case SIO_NCT6106_ID:
4288 sio_data->kind = nct6106;
4289 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004290 case SIO_NCT6775_ID:
4291 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004292 break;
4293 case SIO_NCT6776_ID:
4294 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004295 break;
4296 case SIO_NCT6779_ID:
4297 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004298 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004299 case SIO_NCT6791_ID:
4300 sio_data->kind = nct6791;
4301 break;
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08004302 case SIO_NCT6792_ID:
4303 sio_data->kind = nct6792;
4304 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004305 case SIO_NCT6793_ID:
4306 sio_data->kind = nct6793;
4307 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004308 default:
4309 if (val != 0xffff)
4310 pr_debug("unsupported chip ID: 0x%04x\n", val);
4311 superio_exit(sioaddr);
4312 return -ENODEV;
4313 }
4314
4315 /* We have a known chip, find the HWM I/O address */
4316 superio_select(sioaddr, NCT6775_LD_HWM);
4317 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4318 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004319 addr = val & IOREGION_ALIGNMENT;
4320 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004321 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4322 superio_exit(sioaddr);
4323 return -ENODEV;
4324 }
4325
4326 /* Activate logical device if needed */
4327 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4328 if (!(val & 0x01)) {
4329 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4330 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4331 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004332
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004333 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4334 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004335 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004336
4337 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004338 pr_info("Found %s or compatible chip at %#x:%#x\n",
4339 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004340 sio_data->sioreg = sioaddr;
4341
Guenter Roeck698a7c22013-04-05 07:35:25 -07004342 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004343}
4344
4345/*
4346 * when Super-I/O functions move to a separate file, the Super-I/O
4347 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004348 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004349 * must keep track of the device
4350 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004351static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004352
4353static int __init sensors_nct6775_init(void)
4354{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004355 int i, err;
4356 bool found = false;
4357 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004358 struct resource res;
4359 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004360 int sioaddr[2] = { 0x2e, 0x4e };
4361
4362 err = platform_driver_register(&nct6775_driver);
4363 if (err)
4364 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004365
4366 /*
4367 * initialize sio_data->kind and sio_data->sioreg.
4368 *
4369 * when Super-I/O functions move to a separate file, the Super-I/O
4370 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4371 * nct6775 hardware monitor, and call probe()
4372 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004373 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4374 address = nct6775_find(sioaddr[i], &sio_data);
4375 if (address <= 0)
4376 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004377
Guenter Roeck698a7c22013-04-05 07:35:25 -07004378 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004379
Guenter Roeck698a7c22013-04-05 07:35:25 -07004380 pdev[i] = platform_device_alloc(DRVNAME, address);
4381 if (!pdev[i]) {
4382 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004383 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004384 }
4385
4386 err = platform_device_add_data(pdev[i], &sio_data,
4387 sizeof(struct nct6775_sio_data));
4388 if (err)
4389 goto exit_device_put;
4390
4391 memset(&res, 0, sizeof(res));
4392 res.name = DRVNAME;
4393 res.start = address + IOREGION_OFFSET;
4394 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4395 res.flags = IORESOURCE_IO;
4396
4397 err = acpi_check_resource_conflict(&res);
4398 if (err) {
4399 platform_device_put(pdev[i]);
4400 pdev[i] = NULL;
4401 continue;
4402 }
4403
4404 err = platform_device_add_resources(pdev[i], &res, 1);
4405 if (err)
4406 goto exit_device_put;
4407
4408 /* platform_device_add calls probe() */
4409 err = platform_device_add(pdev[i]);
4410 if (err)
4411 goto exit_device_put;
4412 }
4413 if (!found) {
4414 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004415 goto exit_unregister;
4416 }
4417
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004418 return 0;
4419
4420exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004421 platform_device_put(pdev[i]);
4422exit_device_unregister:
4423 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004424 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004425 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004426 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004427exit_unregister:
4428 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004429 return err;
4430}
4431
4432static void __exit sensors_nct6775_exit(void)
4433{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004434 int i;
4435
4436 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4437 if (pdev[i])
4438 platform_device_unregister(pdev[i]);
4439 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004440 platform_driver_unregister(&nct6775_driver);
4441}
4442
4443MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004444MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004445MODULE_LICENSE("GPL");
4446
4447module_init(sensors_nct6775_init);
4448module_exit(sensors_nct6775_exit);