blob: d506d8e3bb2ce1a917c635d1458cf2ae125f065d [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
364static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
365 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
366
367static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
368 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
369 0xa07 };
370
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700371/* NCT6776 specific data */
372
Guenter Roeck728d2942015-08-31 16:13:47 -0700373/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
374#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
375#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
376
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700377static const s8 NCT6776_ALARM_BITS[] = {
378 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
379 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
380 -1, /* unused */
381 6, 7, 11, 10, 23, /* fan1..fan5 */
382 -1, -1, -1, /* unused */
383 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
384 12, 9 }; /* intrusion0, intrusion1 */
385
Guenter Roeck30846992013-06-24 22:21:59 -0700386static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
387
388static const s8 NCT6776_BEEP_BITS[] = {
389 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
390 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
391 24, /* global beep enable */
392 25, 26, 27, 28, 29, /* fan1..fan5 */
393 -1, -1, -1, /* unused */
394 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
395 30, 31 }; /* intrusion0, intrusion1 */
396
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800397static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700398 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800399
David Bartley578ab5f2013-06-24 22:28:28 -0700400static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
401static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800402
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800403static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800404static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800405
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800406static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700407 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800408
Guenter Roeckaa136e52012-12-04 03:26:05 -0800409static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
410 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
411
412static const char *const nct6776_temp_label[] = {
413 "",
414 "SYSTIN",
415 "CPUTIN",
416 "AUXTIN",
417 "SMBUSMASTER 0",
418 "SMBUSMASTER 1",
419 "SMBUSMASTER 2",
420 "SMBUSMASTER 3",
421 "SMBUSMASTER 4",
422 "SMBUSMASTER 5",
423 "SMBUSMASTER 6",
424 "SMBUSMASTER 7",
425 "PECI Agent 0",
426 "PECI Agent 1",
427 "PCH_CHIP_CPU_MAX_TEMP",
428 "PCH_CHIP_TEMP",
429 "PCH_CPU_TEMP",
430 "PCH_MCH_TEMP",
431 "PCH_DIM0_TEMP",
432 "PCH_DIM1_TEMP",
433 "PCH_DIM2_TEMP",
434 "PCH_DIM3_TEMP",
435 "BYTE_TEMP"
436};
437
438static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
439 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
440
441static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
442 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
443
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700444/* NCT6779 specific data */
445
446static const u16 NCT6779_REG_IN[] = {
447 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
448 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
449
450static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
451 0x459, 0x45A, 0x45B, 0x568 };
452
453static const s8 NCT6779_ALARM_BITS[] = {
454 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
455 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
456 -1, /* unused */
457 6, 7, 11, 10, 23, /* fan1..fan5 */
458 -1, -1, -1, /* unused */
459 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
460 12, 9 }; /* intrusion0, intrusion1 */
461
Guenter Roeck30846992013-06-24 22:21:59 -0700462static const s8 NCT6779_BEEP_BITS[] = {
463 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
464 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
465 24, /* global beep enable */
466 25, 26, 27, 28, 29, /* fan1..fan5 */
467 -1, -1, -1, /* unused */
468 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
469 30, 31 }; /* intrusion0, intrusion1 */
470
David Bartley578ab5f2013-06-24 22:28:28 -0700471static const u16 NCT6779_REG_FAN[] = {
472 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800473static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700474 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800475
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800476static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700477 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700478#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800479static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700480 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800481
Guenter Roeckaa136e52012-12-04 03:26:05 -0800482static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800483static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800484static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
485 0x18, 0x152 };
486static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
487 0x3a, 0x153 };
488static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
489 0x39, 0x155 };
490
491static const u16 NCT6779_REG_TEMP_OFFSET[] = {
492 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
493
494static const char *const nct6779_temp_label[] = {
495 "",
496 "SYSTIN",
497 "CPUTIN",
498 "AUXTIN0",
499 "AUXTIN1",
500 "AUXTIN2",
501 "AUXTIN3",
502 "",
503 "SMBUSMASTER 0",
504 "SMBUSMASTER 1",
505 "SMBUSMASTER 2",
506 "SMBUSMASTER 3",
507 "SMBUSMASTER 4",
508 "SMBUSMASTER 5",
509 "SMBUSMASTER 6",
510 "SMBUSMASTER 7",
511 "PECI Agent 0",
512 "PECI Agent 1",
513 "PCH_CHIP_CPU_MAX_TEMP",
514 "PCH_CHIP_TEMP",
515 "PCH_CPU_TEMP",
516 "PCH_MCH_TEMP",
517 "PCH_DIM0_TEMP",
518 "PCH_DIM1_TEMP",
519 "PCH_DIM2_TEMP",
520 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700521 "BYTE_TEMP",
522 "",
523 "",
524 "",
525 "",
526 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800527};
528
Guenter Roeck9a383712015-08-29 15:29:25 -0700529#define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5)
530#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label)
531
532static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800533 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
534 0, 0, 0, 0, 0, 0, 0, 0,
535 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
536 0x408, 0 };
537
Guenter Roeck9a383712015-08-29 15:29:25 -0700538static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800539 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
540
David Bartley578ab5f2013-06-24 22:28:28 -0700541/* NCT6791 specific data */
542
543#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
544
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800545static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
546static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
547static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
548static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
549static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
550static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
551
David Bartley578ab5f2013-06-24 22:28:28 -0700552static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
553 0x459, 0x45A, 0x45B, 0x568, 0x45D };
554
555static const s8 NCT6791_ALARM_BITS[] = {
556 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
557 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
558 -1, /* unused */
559 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
560 -1, -1, /* unused */
561 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
562 12, 9 }; /* intrusion0, intrusion1 */
563
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700564/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb93f2014-11-16 09:50:04 -0800565
566static const u16 NCT6792_REG_TEMP_MON[] = {
567 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
568static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
569 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700570
Guenter Roeck50224f42015-10-30 07:52:39 -0700571static const char *const nct6792_temp_label[] = {
572 "",
573 "SYSTIN",
574 "CPUTIN",
575 "AUXTIN0",
576 "AUXTIN1",
577 "AUXTIN2",
578 "AUXTIN3",
579 "",
580 "SMBUSMASTER 0",
581 "SMBUSMASTER 1",
582 "SMBUSMASTER 2",
583 "SMBUSMASTER 3",
584 "SMBUSMASTER 4",
585 "SMBUSMASTER 5",
586 "SMBUSMASTER 6",
587 "SMBUSMASTER 7",
588 "PECI Agent 0",
589 "PECI Agent 1",
590 "PCH_CHIP_CPU_MAX_TEMP",
591 "PCH_CHIP_TEMP",
592 "PCH_CPU_TEMP",
593 "PCH_MCH_TEMP",
594 "PCH_DIM0_TEMP",
595 "PCH_DIM1_TEMP",
596 "PCH_DIM2_TEMP",
597 "PCH_DIM3_TEMP",
598 "BYTE_TEMP",
599 "PECI Agent 0 Calibration",
600 "PECI Agent 1 Calibration",
601 "",
602 "",
603 "Virtual_TEMP"
604};
605
606static const char *const nct6793_temp_label[] = {
607 "",
608 "SYSTIN",
609 "CPUTIN",
610 "AUXTIN0",
611 "AUXTIN1",
612 "AUXTIN2",
613 "AUXTIN3",
614 "",
615 "SMBUSMASTER 0",
616 "SMBUSMASTER 1",
617 "",
618 "",
619 "",
620 "",
621 "",
622 "",
623 "PECI Agent 0",
624 "PECI Agent 1",
625 "PCH_CHIP_CPU_MAX_TEMP",
626 "PCH_CHIP_TEMP",
627 "PCH_CPU_TEMP",
628 "PCH_MCH_TEMP",
629 "Agent0 Dimm0 ",
630 "Agent0 Dimm1",
631 "Agent1 Dimm0",
632 "Agent1 Dimm1",
633 "BYTE_TEMP0",
634 "BYTE_TEMP1",
635 "PECI Agent 0 Calibration",
636 "PECI Agent 1 Calibration",
637 "",
638 "Virtual_TEMP"
639};
640
Guenter Roeck6c009502012-07-01 08:23:15 -0700641/* NCT6102D/NCT6106D specific data */
642
643#define NCT6106_REG_VBAT 0x318
644#define NCT6106_REG_DIODE 0x319
645#define NCT6106_DIODE_MASK 0x01
646
647static const u16 NCT6106_REG_IN_MAX[] = {
648 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
649static const u16 NCT6106_REG_IN_MIN[] = {
650 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
651static const u16 NCT6106_REG_IN[] = {
652 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
653
654static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800655static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700656static const u16 NCT6106_REG_TEMP_HYST[] = {
657 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
658static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700659 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
660static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
661 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
662static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
663 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700664static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
665static const u16 NCT6106_REG_TEMP_CONFIG[] = {
666 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
667
668static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
669static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
670static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
671static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
672
673static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
674static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
675static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
676static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
677static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
678static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
679static const u16 NCT6106_REG_TEMP_SOURCE[] = {
680 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
681
682static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
683static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
684 0x11b, 0x12b, 0x13b };
685
686static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
687#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
688static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
689
690static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
691static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
692static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
693static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
694static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
695static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
696
697static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
698
699static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
700static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
701static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
702static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
703static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
704static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
705
706static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
707static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
708
709static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
710 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
711
712static const s8 NCT6106_ALARM_BITS[] = {
713 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
714 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
715 -1, /* unused */
716 32, 33, 34, -1, -1, /* fan1..fan5 */
717 -1, -1, -1, /* unused */
718 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
719 48, -1 /* intrusion0, intrusion1 */
720};
721
Guenter Roeck30846992013-06-24 22:21:59 -0700722static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
723 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
724
725static const s8 NCT6106_BEEP_BITS[] = {
726 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
727 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
728 32, /* global beep enable */
729 24, 25, 26, 27, 28, /* fan1..fan5 */
730 -1, -1, -1, /* unused */
731 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
732 34, -1 /* intrusion0, intrusion1 */
733};
734
Guenter Roeck6c009502012-07-01 08:23:15 -0700735static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
736 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
737
738static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
739 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
740
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800741static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
742{
743 if (mode == 0 && pwm == 255)
744 return off;
745 return mode + 1;
746}
747
748static int pwm_enable_to_reg(enum pwm_enable mode)
749{
750 if (mode == off)
751 return 0;
752 return mode - 1;
753}
754
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700755/*
756 * Conversions
757 */
758
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800759/* 1 is DC mode, output in ms */
760static unsigned int step_time_from_reg(u8 reg, u8 mode)
761{
762 return mode ? 400 * reg : 100 * reg;
763}
764
765static u8 step_time_to_reg(unsigned int msec, u8 mode)
766{
767 return clamp_val((mode ? (msec + 200) / 400 :
768 (msec + 50) / 100), 1, 255);
769}
770
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800771static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
772{
773 if (reg == 0 || reg == 255)
774 return 0;
775 return 1350000U / (reg << divreg);
776}
777
778static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
779{
780 if ((reg & 0xff1f) == 0xff1f)
781 return 0;
782
783 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
784
785 if (reg == 0)
786 return 0;
787
788 return 1350000U / reg;
789}
790
791static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
792{
793 if (reg == 0 || reg == 0xffff)
794 return 0;
795
796 /*
797 * Even though the registers are 16 bit wide, the fan divisor
798 * still applies.
799 */
800 return 1350000U / (reg << divreg);
801}
802
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800803static u16 fan_to_reg(u32 fan, unsigned int divreg)
804{
805 if (!fan)
806 return 0;
807
808 return (1350000U / fan) >> divreg;
809}
810
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800811static inline unsigned int
812div_from_reg(u8 reg)
813{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700814 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800815}
816
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700817/*
818 * Some of the voltage inputs have internal scaling, the tables below
819 * contain 8 (the ADC LSB in mV) * scaling factor * 100
820 */
821static const u16 scale_in[15] = {
822 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
823 800, 800
824};
825
826static inline long in_from_reg(u8 reg, u8 nr)
827{
828 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
829}
830
831static inline u8 in_to_reg(u32 val, u8 nr)
832{
833 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
834}
835
836/*
837 * Data structures and manipulation thereof
838 */
839
840struct nct6775_data {
841 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700842 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700843 enum kinds kind;
844 const char *name;
845
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700846 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700847
Guenter Roeckb7a61352013-04-02 22:14:06 -0700848 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
849 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800850 */
851 u8 temp_src[NUM_TEMP];
852 u16 reg_temp_config[NUM_TEMP];
853 const char * const *temp_label;
854 int temp_label_num;
855
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700856 u16 REG_CONFIG;
857 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800858 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700859 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700860
861 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700862 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700863
864 const u16 *REG_VIN;
865 const u16 *REG_IN_MINMAX[2];
866
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800867 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800868 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800869 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800870 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800871 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700872 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800873 const u16 *REG_FAN_TIME[3];
874
875 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800876
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800877 const u8 *REG_PWM_MODE;
878 const u8 *PWM_MODE_MASK;
879
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800880 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
881 * [3]=pwm_max, [4]=pwm_step,
882 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800883 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800884 const u16 *REG_PWM_READ;
885
Guenter Roeck6c009502012-07-01 08:23:15 -0700886 const u16 *REG_CRITICAL_PWM_ENABLE;
887 u8 CRITICAL_PWM_ENABLE_MASK;
888 const u16 *REG_CRITICAL_PWM;
889
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800890 const u16 *REG_AUTO_TEMP;
891 const u16 *REG_AUTO_PWM;
892
893 const u16 *REG_CRITICAL_TEMP;
894 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
895
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800896 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800897 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800898 const u16 *REG_WEIGHT_TEMP_SEL;
899 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
900
Guenter Roeckaa136e52012-12-04 03:26:05 -0800901 const u16 *REG_TEMP_OFFSET;
902
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700903 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700904 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700905
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800906 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
907 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
908
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700909 struct mutex update_lock;
910 bool valid; /* true if following fields are valid */
911 unsigned long last_updated; /* In jiffies */
912
913 /* Register values */
914 u8 bank; /* current register bank */
915 u8 in_num; /* number of in inputs we have */
916 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700917 unsigned int rpm[NUM_FAN];
918 u16 fan_min[NUM_FAN];
919 u8 fan_pulses[NUM_FAN];
920 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800921 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800922 u8 has_fan; /* some fan inputs can be disabled */
923 u8 has_fan_min; /* some fans don't have min register */
924 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700925
Guenter Roeck6c009502012-07-01 08:23:15 -0700926 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700927 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800928 u8 temp_fixed_num; /* 3 or 6 */
929 u8 temp_type[NUM_TEMP_FIXED];
930 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300931 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
932 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700933 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700934 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700935
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800936 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700937 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
938 * 0->PWM variable duty cycle
939 */
940 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800941 /* 0->off
942 * 1->manual
943 * 2->thermal cruise mode (also called SmartFan I)
944 * 3->fan speed cruise mode
945 * 4->SmartFan III
946 * 5->enhanced variable thermal cruise (SmartFan IV)
947 */
David Bartley578ab5f2013-06-24 22:28:28 -0700948 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
949 * [3]=pwm_max, [4]=pwm_step,
950 * [5]=weight_duty_step, [6]=weight_duty_base
951 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800952
David Bartley578ab5f2013-06-24 22:28:28 -0700953 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800954 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700955 u32 target_speed[NUM_FAN];
956 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800957 u8 speed_tolerance_limit;
958
David Bartley578ab5f2013-06-24 22:28:28 -0700959 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800960 u8 tolerance_mask;
961
David Bartley578ab5f2013-06-24 22:28:28 -0700962 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800963
964 /* Automatic fan speed control registers */
965 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700966 u8 auto_pwm[NUM_FAN][7];
967 u8 auto_temp[NUM_FAN][7];
968 u8 pwm_temp_sel[NUM_FAN];
969 u8 pwm_weight_temp_sel[NUM_FAN];
970 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
971 * 2->temp_base
972 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800973
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700974 u8 vid;
975 u8 vrm;
976
Guenter Roeckf73cf632013-03-18 09:22:50 -0700977 bool have_vid;
978
Guenter Roeckaa136e52012-12-04 03:26:05 -0800979 u16 have_temp;
980 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700981 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800982
Guenter Roeck84d19d92012-12-04 08:01:39 -0800983 /* Remember extra register values over suspend/resume */
984 u8 vbat;
985 u8 fandiv1;
986 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800987 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700988};
989
990struct nct6775_sio_data {
991 int sioreg;
992 enum kinds kind;
993};
994
Guenter Roeckf73cf632013-03-18 09:22:50 -0700995struct sensor_device_template {
996 struct device_attribute dev_attr;
997 union {
998 struct {
999 u8 nr;
1000 u8 index;
1001 } s;
1002 int index;
1003 } u;
1004 bool s2; /* true if both index and nr are used */
1005};
1006
1007struct sensor_device_attr_u {
1008 union {
1009 struct sensor_device_attribute a1;
1010 struct sensor_device_attribute_2 a2;
1011 } u;
1012 char name[32];
1013};
1014
1015#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1016 .attr = {.name = _template, .mode = _mode }, \
1017 .show = _show, \
1018 .store = _store, \
1019}
1020
1021#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1022 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1023 .u.index = _index, \
1024 .s2 = false }
1025
1026#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1027 _nr, _index) \
1028 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1029 .u.s.index = _index, \
1030 .u.s.nr = _nr, \
1031 .s2 = true }
1032
1033#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1034static struct sensor_device_template sensor_dev_template_##_name \
1035 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1036 _index)
1037
1038#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1039 _nr, _index) \
1040static struct sensor_device_template sensor_dev_template_##_name \
1041 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1042 _nr, _index)
1043
1044struct sensor_template_group {
1045 struct sensor_device_template **templates;
1046 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1047 int base;
1048};
1049
1050static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001051nct6775_create_attr_group(struct device *dev,
1052 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001053 int repeat)
1054{
1055 struct attribute_group *group;
1056 struct sensor_device_attr_u *su;
1057 struct sensor_device_attribute *a;
1058 struct sensor_device_attribute_2 *a2;
1059 struct attribute **attrs;
1060 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001061 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001062
1063 if (repeat <= 0)
1064 return ERR_PTR(-EINVAL);
1065
1066 t = tg->templates;
1067 for (count = 0; *t; t++, count++)
1068 ;
1069
1070 if (count == 0)
1071 return ERR_PTR(-EINVAL);
1072
1073 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1074 if (group == NULL)
1075 return ERR_PTR(-ENOMEM);
1076
1077 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1078 GFP_KERNEL);
1079 if (attrs == NULL)
1080 return ERR_PTR(-ENOMEM);
1081
1082 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1083 GFP_KERNEL);
1084 if (su == NULL)
1085 return ERR_PTR(-ENOMEM);
1086
1087 group->attrs = attrs;
1088 group->is_visible = tg->is_visible;
1089
1090 for (i = 0; i < repeat; i++) {
1091 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001092 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001093 snprintf(su->name, sizeof(su->name),
1094 (*t)->dev_attr.attr.name, tg->base + i);
1095 if ((*t)->s2) {
1096 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001097 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001098 a2->dev_attr.attr.name = su->name;
1099 a2->nr = (*t)->u.s.nr + i;
1100 a2->index = (*t)->u.s.index;
1101 a2->dev_attr.attr.mode =
1102 (*t)->dev_attr.attr.mode;
1103 a2->dev_attr.show = (*t)->dev_attr.show;
1104 a2->dev_attr.store = (*t)->dev_attr.store;
1105 *attrs = &a2->dev_attr.attr;
1106 } else {
1107 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001108 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001109 a->dev_attr.attr.name = su->name;
1110 a->index = (*t)->u.index + i;
1111 a->dev_attr.attr.mode =
1112 (*t)->dev_attr.attr.mode;
1113 a->dev_attr.show = (*t)->dev_attr.show;
1114 a->dev_attr.store = (*t)->dev_attr.store;
1115 *attrs = &a->dev_attr.attr;
1116 }
1117 attrs++;
1118 su++;
1119 t++;
1120 }
1121 }
1122
Guenter Roeckf73cf632013-03-18 09:22:50 -07001123 return group;
1124}
1125
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001126static bool is_word_sized(struct nct6775_data *data, u16 reg)
1127{
1128 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001129 case nct6106:
1130 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1131 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1132 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001133 case nct6775:
1134 return (((reg & 0xff00) == 0x100 ||
1135 (reg & 0xff00) == 0x200) &&
1136 ((reg & 0x00ff) == 0x50 ||
1137 (reg & 0x00ff) == 0x53 ||
1138 (reg & 0x00ff) == 0x55)) ||
1139 (reg & 0xfff0) == 0x630 ||
1140 reg == 0x640 || reg == 0x642 ||
1141 reg == 0x662 ||
1142 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1143 reg == 0x73 || reg == 0x75 || reg == 0x77;
1144 case nct6776:
1145 return (((reg & 0xff00) == 0x100 ||
1146 (reg & 0xff00) == 0x200) &&
1147 ((reg & 0x00ff) == 0x50 ||
1148 (reg & 0x00ff) == 0x53 ||
1149 (reg & 0x00ff) == 0x55)) ||
1150 (reg & 0xfff0) == 0x630 ||
1151 reg == 0x402 ||
1152 reg == 0x640 || reg == 0x642 ||
1153 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1154 reg == 0x73 || reg == 0x75 || reg == 0x77;
1155 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001156 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08001157 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001158 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001159 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001160 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001161 reg == 0x402 ||
1162 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1163 reg == 0x640 || reg == 0x642 ||
1164 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08001165 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001166 }
1167 return false;
1168}
1169
1170/*
1171 * On older chips, only registers 0x50-0x5f are banked.
1172 * On more recent chips, all registers are banked.
1173 * Assume that is the case and set the bank number for each access.
1174 * Cache the bank number so it only needs to be set if it changes.
1175 */
1176static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1177{
1178 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001179
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001180 if (data->bank != bank) {
1181 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1182 outb_p(bank, data->addr + DATA_REG_OFFSET);
1183 data->bank = bank;
1184 }
1185}
1186
1187static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1188{
1189 int res, word_sized = is_word_sized(data, reg);
1190
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001191 nct6775_set_bank(data, reg);
1192 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1193 res = inb_p(data->addr + DATA_REG_OFFSET);
1194 if (word_sized) {
1195 outb_p((reg & 0xff) + 1,
1196 data->addr + ADDR_REG_OFFSET);
1197 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1198 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001199 return res;
1200}
1201
1202static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1203{
1204 int word_sized = is_word_sized(data, reg);
1205
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001206 nct6775_set_bank(data, reg);
1207 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1208 if (word_sized) {
1209 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1210 outb_p((reg & 0xff) + 1,
1211 data->addr + ADDR_REG_OFFSET);
1212 }
1213 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001214 return 0;
1215}
1216
Guenter Roeckaa136e52012-12-04 03:26:05 -08001217/* We left-align 8-bit temperature values to make the code simpler */
1218static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1219{
1220 u16 res;
1221
1222 res = nct6775_read_value(data, reg);
1223 if (!is_word_sized(data, reg))
1224 res <<= 8;
1225
1226 return res;
1227}
1228
1229static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1230{
1231 if (!is_word_sized(data, reg))
1232 value >>= 8;
1233 return nct6775_write_value(data, reg, value);
1234}
1235
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001236/* This function assumes that the caller holds data->update_lock */
1237static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1238{
1239 u8 reg;
1240
1241 switch (nr) {
1242 case 0:
1243 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1244 | (data->fan_div[0] & 0x7);
1245 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1246 break;
1247 case 1:
1248 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1249 | ((data->fan_div[1] << 4) & 0x70);
1250 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1251 break;
1252 case 2:
1253 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1254 | (data->fan_div[2] & 0x7);
1255 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1256 break;
1257 case 3:
1258 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1259 | ((data->fan_div[3] << 4) & 0x70);
1260 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1261 break;
1262 }
1263}
1264
1265static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1266{
1267 if (data->kind == nct6775)
1268 nct6775_write_fan_div(data, nr);
1269}
1270
1271static void nct6775_update_fan_div(struct nct6775_data *data)
1272{
1273 u8 i;
1274
1275 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1276 data->fan_div[0] = i & 0x7;
1277 data->fan_div[1] = (i & 0x70) >> 4;
1278 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1279 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001280 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001281 data->fan_div[3] = (i & 0x70) >> 4;
1282}
1283
1284static void nct6775_update_fan_div_common(struct nct6775_data *data)
1285{
1286 if (data->kind == nct6775)
1287 nct6775_update_fan_div(data);
1288}
1289
1290static void nct6775_init_fan_div(struct nct6775_data *data)
1291{
1292 int i;
1293
1294 nct6775_update_fan_div_common(data);
1295 /*
1296 * For all fans, start with highest divider value if the divider
1297 * register is not initialized. This ensures that we get a
1298 * reading from the fan count register, even if it is not optimal.
1299 * We'll compute a better divider later on.
1300 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001301 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001302 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001303 continue;
1304 if (data->fan_div[i] == 0) {
1305 data->fan_div[i] = 7;
1306 nct6775_write_fan_div_common(data, i);
1307 }
1308 }
1309}
1310
1311static void nct6775_init_fan_common(struct device *dev,
1312 struct nct6775_data *data)
1313{
1314 int i;
1315 u8 reg;
1316
1317 if (data->has_fan_div)
1318 nct6775_init_fan_div(data);
1319
1320 /*
1321 * If fan_min is not set (0), set it to 0xff to disable it. This
1322 * prevents the unnecessary warning when fanX_min is reported as 0.
1323 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001324 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001325 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001326 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1327 if (!reg)
1328 nct6775_write_value(data, data->REG_FAN_MIN[i],
1329 data->has_fan_div ? 0xff
1330 : 0xff1f);
1331 }
1332 }
1333}
1334
1335static void nct6775_select_fan_div(struct device *dev,
1336 struct nct6775_data *data, int nr, u16 reg)
1337{
1338 u8 fan_div = data->fan_div[nr];
1339 u16 fan_min;
1340
1341 if (!data->has_fan_div)
1342 return;
1343
1344 /*
1345 * If we failed to measure the fan speed, or the reported value is not
1346 * in the optimal range, and the clock divider can be modified,
1347 * let's try that for next time.
1348 */
1349 if (reg == 0x00 && fan_div < 0x07)
1350 fan_div++;
1351 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1352 fan_div--;
1353
1354 if (fan_div != data->fan_div[nr]) {
1355 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1356 nr + 1, div_from_reg(data->fan_div[nr]),
1357 div_from_reg(fan_div));
1358
1359 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001360 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001361 fan_min = data->fan_min[nr];
1362 if (fan_div > data->fan_div[nr]) {
1363 if (fan_min != 255 && fan_min > 1)
1364 fan_min >>= 1;
1365 } else {
1366 if (fan_min != 255) {
1367 fan_min <<= 1;
1368 if (fan_min > 254)
1369 fan_min = 254;
1370 }
1371 }
1372 if (fan_min != data->fan_min[nr]) {
1373 data->fan_min[nr] = fan_min;
1374 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1375 fan_min);
1376 }
1377 }
1378 data->fan_div[nr] = fan_div;
1379 nct6775_write_fan_div_common(data, nr);
1380 }
1381}
1382
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001383static void nct6775_update_pwm(struct device *dev)
1384{
1385 struct nct6775_data *data = dev_get_drvdata(dev);
1386 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001387 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001388 bool duty_is_dc;
1389
1390 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001391 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001392 continue;
1393
1394 duty_is_dc = data->REG_PWM_MODE[i] &&
1395 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1396 & data->PWM_MODE_MASK[i]);
1397 data->pwm_mode[i] = duty_is_dc;
1398
1399 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1400 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1401 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1402 data->pwm[j][i]
1403 = nct6775_read_value(data,
1404 data->REG_PWM[j][i]);
1405 }
1406 }
1407
1408 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1409 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001410
1411 if (!data->temp_tolerance[0][i] ||
1412 data->pwm_enable[i] != speed_cruise)
1413 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1414 if (!data->target_speed_tolerance[i] ||
1415 data->pwm_enable[i] == speed_cruise) {
1416 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001417
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001418 if (data->REG_TOLERANCE_H) {
1419 t |= (nct6775_read_value(data,
1420 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1421 }
1422 data->target_speed_tolerance[i] = t;
1423 }
1424
1425 data->temp_tolerance[1][i] =
1426 nct6775_read_value(data,
1427 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1428
1429 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1430 data->pwm_temp_sel[i] = reg & 0x1f;
1431 /* If fan can stop, report floor as 0 */
1432 if (reg & 0x80)
1433 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001434
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001435 if (!data->REG_WEIGHT_TEMP_SEL[i])
1436 continue;
1437
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001438 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1439 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1440 /* If weight is disabled, report weight source as 0 */
1441 if (j == 1 && !(reg & 0x80))
1442 data->pwm_weight_temp_sel[i] = 0;
1443
1444 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001445 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001446 data->weight_temp[j][i]
1447 = nct6775_read_value(data,
1448 data->REG_WEIGHT_TEMP[j][i]);
1449 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001450 }
1451}
1452
1453static void nct6775_update_pwm_limits(struct device *dev)
1454{
1455 struct nct6775_data *data = dev_get_drvdata(dev);
1456 int i, j;
1457 u8 reg;
1458 u16 reg_t;
1459
1460 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001461 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001462 continue;
1463
Guenter Roeckc409fd42013-04-09 05:04:00 -07001464 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001465 data->fan_time[j][i] =
1466 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1467 }
1468
1469 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1470 /* Update only in matching mode or if never updated */
1471 if (!data->target_temp[i] ||
1472 data->pwm_enable[i] == thermal_cruise)
1473 data->target_temp[i] = reg_t & data->target_temp_mask;
1474 if (!data->target_speed[i] ||
1475 data->pwm_enable[i] == speed_cruise) {
1476 if (data->REG_TOLERANCE_H) {
1477 reg_t |= (nct6775_read_value(data,
1478 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1479 }
1480 data->target_speed[i] = reg_t;
1481 }
1482
1483 for (j = 0; j < data->auto_pwm_num; j++) {
1484 data->auto_pwm[i][j] =
1485 nct6775_read_value(data,
1486 NCT6775_AUTO_PWM(data, i, j));
1487 data->auto_temp[i][j] =
1488 nct6775_read_value(data,
1489 NCT6775_AUTO_TEMP(data, i, j));
1490 }
1491
1492 /* critical auto_pwm temperature data */
1493 data->auto_temp[i][data->auto_pwm_num] =
1494 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1495
1496 switch (data->kind) {
1497 case nct6775:
1498 reg = nct6775_read_value(data,
1499 NCT6775_REG_CRITICAL_ENAB[i]);
1500 data->auto_pwm[i][data->auto_pwm_num] =
1501 (reg & 0x02) ? 0xff : 0x00;
1502 break;
1503 case nct6776:
1504 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1505 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001506 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001507 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001508 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08001509 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001510 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001511 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001512 data->REG_CRITICAL_PWM_ENABLE[i]);
1513 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1514 reg = nct6775_read_value(data,
1515 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001516 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001517 reg = 0xff;
1518 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001519 break;
1520 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001521 }
1522}
1523
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001524static struct nct6775_data *nct6775_update_device(struct device *dev)
1525{
1526 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001527 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001528
1529 mutex_lock(&data->update_lock);
1530
Guenter Roeck6445e662013-04-21 09:13:28 -07001531 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001532 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001533 /* Fan clock dividers */
1534 nct6775_update_fan_div_common(data);
1535
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001536 /* Measured voltages and limits */
1537 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001538 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001539 continue;
1540
1541 data->in[i][0] = nct6775_read_value(data,
1542 data->REG_VIN[i]);
1543 data->in[i][1] = nct6775_read_value(data,
1544 data->REG_IN_MINMAX[0][i]);
1545 data->in[i][2] = nct6775_read_value(data,
1546 data->REG_IN_MINMAX[1][i]);
1547 }
1548
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001549 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001550 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001551 u16 reg;
1552
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001553 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001554 continue;
1555
1556 reg = nct6775_read_value(data, data->REG_FAN[i]);
1557 data->rpm[i] = data->fan_from_reg(reg,
1558 data->fan_div[i]);
1559
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001560 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001561 data->fan_min[i] = nct6775_read_value(data,
1562 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001563 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001564 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1565 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001566
1567 nct6775_select_fan_div(dev, data, i, reg);
1568 }
1569
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001570 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001571 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001572
Guenter Roeckaa136e52012-12-04 03:26:05 -08001573 /* Measured temperatures and limits */
1574 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001575 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001576 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001577 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001578 if (data->reg_temp[j][i])
1579 data->temp[j][i]
1580 = nct6775_read_temp(data,
1581 data->reg_temp[j][i]);
1582 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001583 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001584 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001585 continue;
1586 data->temp_offset[i]
1587 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1588 }
1589
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001590 data->alarms = 0;
1591 for (i = 0; i < NUM_REG_ALARM; i++) {
1592 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001593
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001594 if (!data->REG_ALARM[i])
1595 continue;
1596 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1597 data->alarms |= ((u64)alarm) << (i << 3);
1598 }
1599
Guenter Roeck30846992013-06-24 22:21:59 -07001600 data->beeps = 0;
1601 for (i = 0; i < NUM_REG_BEEP; i++) {
1602 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001603
Guenter Roeck30846992013-06-24 22:21:59 -07001604 if (!data->REG_BEEP[i])
1605 continue;
1606 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1607 data->beeps |= ((u64)beep) << (i << 3);
1608 }
1609
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001610 data->last_updated = jiffies;
1611 data->valid = true;
1612 }
1613
1614 mutex_unlock(&data->update_lock);
1615 return data;
1616}
1617
1618/*
1619 * Sysfs callback functions
1620 */
1621static ssize_t
1622show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1623{
1624 struct nct6775_data *data = nct6775_update_device(dev);
1625 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001626 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001627 int nr = sattr->nr;
1628
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001629 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1630}
1631
1632static ssize_t
1633store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1634 size_t count)
1635{
1636 struct nct6775_data *data = dev_get_drvdata(dev);
1637 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001638 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001639 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001640 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001641 int err;
1642
1643 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001644 if (err < 0)
1645 return err;
1646 mutex_lock(&data->update_lock);
1647 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001648 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001649 data->in[nr][index]);
1650 mutex_unlock(&data->update_lock);
1651 return count;
1652}
1653
1654static ssize_t
1655show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1656{
1657 struct nct6775_data *data = nct6775_update_device(dev);
1658 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1659 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001660
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001661 return sprintf(buf, "%u\n",
1662 (unsigned int)((data->alarms >> nr) & 0x01));
1663}
1664
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001665static int find_temp_source(struct nct6775_data *data, int index, int count)
1666{
1667 int source = data->temp_src[index];
1668 int nr;
1669
1670 for (nr = 0; nr < count; nr++) {
1671 int src;
1672
1673 src = nct6775_read_value(data,
1674 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1675 if (src == source)
1676 return nr;
1677 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001678 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001679}
1680
1681static ssize_t
1682show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1683{
1684 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1685 struct nct6775_data *data = nct6775_update_device(dev);
1686 unsigned int alarm = 0;
1687 int nr;
1688
1689 /*
1690 * For temperatures, there is no fixed mapping from registers to alarm
1691 * bits. Alarm bits are determined by the temperature source mapping.
1692 */
1693 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1694 if (nr >= 0) {
1695 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001696
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001697 alarm = (data->alarms >> bit) & 0x01;
1698 }
1699 return sprintf(buf, "%u\n", alarm);
1700}
1701
Guenter Roeck30846992013-06-24 22:21:59 -07001702static ssize_t
1703show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1704{
1705 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1706 struct nct6775_data *data = nct6775_update_device(dev);
1707 int nr = data->BEEP_BITS[sattr->index];
1708
1709 return sprintf(buf, "%u\n",
1710 (unsigned int)((data->beeps >> nr) & 0x01));
1711}
1712
1713static ssize_t
1714store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1715 size_t count)
1716{
1717 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1718 struct nct6775_data *data = dev_get_drvdata(dev);
1719 int nr = data->BEEP_BITS[sattr->index];
1720 int regindex = nr >> 3;
1721 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001722 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001723
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001724 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001725 if (err < 0)
1726 return err;
1727 if (val > 1)
1728 return -EINVAL;
1729
1730 mutex_lock(&data->update_lock);
1731 if (val)
1732 data->beeps |= (1ULL << nr);
1733 else
1734 data->beeps &= ~(1ULL << nr);
1735 nct6775_write_value(data, data->REG_BEEP[regindex],
1736 (data->beeps >> (regindex << 3)) & 0xff);
1737 mutex_unlock(&data->update_lock);
1738 return count;
1739}
1740
1741static ssize_t
1742show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1743{
1744 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1745 struct nct6775_data *data = nct6775_update_device(dev);
1746 unsigned int beep = 0;
1747 int nr;
1748
1749 /*
1750 * For temperatures, there is no fixed mapping from registers to beep
1751 * enable bits. Beep enable bits are determined by the temperature
1752 * source mapping.
1753 */
1754 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1755 if (nr >= 0) {
1756 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001757
Guenter Roeck30846992013-06-24 22:21:59 -07001758 beep = (data->beeps >> bit) & 0x01;
1759 }
1760 return sprintf(buf, "%u\n", beep);
1761}
1762
1763static ssize_t
1764store_temp_beep(struct device *dev, struct device_attribute *attr,
1765 const char *buf, size_t count)
1766{
1767 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1768 struct nct6775_data *data = dev_get_drvdata(dev);
1769 int nr, bit, regindex;
1770 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001771 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001772
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001773 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001774 if (err < 0)
1775 return err;
1776 if (val > 1)
1777 return -EINVAL;
1778
1779 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1780 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001781 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001782
1783 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1784 regindex = bit >> 3;
1785
1786 mutex_lock(&data->update_lock);
1787 if (val)
1788 data->beeps |= (1ULL << bit);
1789 else
1790 data->beeps &= ~(1ULL << bit);
1791 nct6775_write_value(data, data->REG_BEEP[regindex],
1792 (data->beeps >> (regindex << 3)) & 0xff);
1793 mutex_unlock(&data->update_lock);
1794
1795 return count;
1796}
1797
Guenter Roeckf73cf632013-03-18 09:22:50 -07001798static umode_t nct6775_in_is_visible(struct kobject *kobj,
1799 struct attribute *attr, int index)
1800{
1801 struct device *dev = container_of(kobj, struct device, kobj);
1802 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001803 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001804
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001805 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001806 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001807
Guenter Roeckf73cf632013-03-18 09:22:50 -07001808 return attr->mode;
1809}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001810
Guenter Roeckf73cf632013-03-18 09:22:50 -07001811SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1812SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001813SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1814 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001815SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1816 store_in_reg, 0, 1);
1817SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1818 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001819
Guenter Roeckf73cf632013-03-18 09:22:50 -07001820/*
1821 * nct6775_in_is_visible uses the index into the following array
1822 * to determine if attributes should be created or not.
1823 * Any change in order or content must be matched.
1824 */
1825static struct sensor_device_template *nct6775_attributes_in_template[] = {
1826 &sensor_dev_template_in_input,
1827 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001828 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001829 &sensor_dev_template_in_min,
1830 &sensor_dev_template_in_max,
1831 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001832};
1833
Julia Lawallc60fdf82015-12-12 17:36:39 +01001834static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001835 .templates = nct6775_attributes_in_template,
1836 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001837};
1838
1839static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001840show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1841{
1842 struct nct6775_data *data = nct6775_update_device(dev);
1843 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1844 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001845
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001846 return sprintf(buf, "%d\n", data->rpm[nr]);
1847}
1848
1849static ssize_t
1850show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1851{
1852 struct nct6775_data *data = nct6775_update_device(dev);
1853 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1854 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001855
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001856 return sprintf(buf, "%d\n",
1857 data->fan_from_reg_min(data->fan_min[nr],
1858 data->fan_div[nr]));
1859}
1860
1861static ssize_t
1862show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1863{
1864 struct nct6775_data *data = nct6775_update_device(dev);
1865 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1866 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001867
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001868 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1869}
1870
1871static ssize_t
1872store_fan_min(struct device *dev, struct device_attribute *attr,
1873 const char *buf, size_t count)
1874{
1875 struct nct6775_data *data = dev_get_drvdata(dev);
1876 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1877 int nr = sattr->index;
1878 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001879 unsigned int reg;
1880 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001881 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001882
1883 err = kstrtoul(buf, 10, &val);
1884 if (err < 0)
1885 return err;
1886
1887 mutex_lock(&data->update_lock);
1888 if (!data->has_fan_div) {
1889 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1890 if (!val) {
1891 val = 0xff1f;
1892 } else {
1893 if (val > 1350000U)
1894 val = 135000U;
1895 val = 1350000U / val;
1896 val = (val & 0x1f) | ((val << 3) & 0xff00);
1897 }
1898 data->fan_min[nr] = val;
1899 goto write_min; /* Leave fan divider alone */
1900 }
1901 if (!val) {
1902 /* No min limit, alarm disabled */
1903 data->fan_min[nr] = 255;
1904 new_div = data->fan_div[nr]; /* No change */
1905 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1906 goto write_div;
1907 }
1908 reg = 1350000U / val;
1909 if (reg >= 128 * 255) {
1910 /*
1911 * Speed below this value cannot possibly be represented,
1912 * even with the highest divider (128)
1913 */
1914 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001915 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001916 dev_warn(dev,
1917 "fan%u low limit %lu below minimum %u, set to minimum\n",
1918 nr + 1, val, data->fan_from_reg_min(254, 7));
1919 } else if (!reg) {
1920 /*
1921 * Speed above this value cannot possibly be represented,
1922 * even with the lowest divider (1)
1923 */
1924 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001925 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001926 dev_warn(dev,
1927 "fan%u low limit %lu above maximum %u, set to maximum\n",
1928 nr + 1, val, data->fan_from_reg_min(1, 0));
1929 } else {
1930 /*
1931 * Automatically pick the best divider, i.e. the one such
1932 * that the min limit will correspond to a register value
1933 * in the 96..192 range
1934 */
1935 new_div = 0;
1936 while (reg > 192 && new_div < 7) {
1937 reg >>= 1;
1938 new_div++;
1939 }
1940 data->fan_min[nr] = reg;
1941 }
1942
1943write_div:
1944 /*
1945 * Write both the fan clock divider (if it changed) and the new
1946 * fan min (unconditionally)
1947 */
1948 if (new_div != data->fan_div[nr]) {
1949 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1950 nr + 1, div_from_reg(data->fan_div[nr]),
1951 div_from_reg(new_div));
1952 data->fan_div[nr] = new_div;
1953 nct6775_write_fan_div_common(data, nr);
1954 /* Give the chip time to sample a new speed value */
1955 data->last_updated = jiffies;
1956 }
1957
1958write_min:
1959 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1960 mutex_unlock(&data->update_lock);
1961
1962 return count;
1963}
1964
Guenter Roeck5c25d952012-12-11 07:29:06 -08001965static ssize_t
1966show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1967{
1968 struct nct6775_data *data = nct6775_update_device(dev);
1969 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1970 int p = data->fan_pulses[sattr->index];
1971
1972 return sprintf(buf, "%d\n", p ? : 4);
1973}
1974
1975static ssize_t
1976store_fan_pulses(struct device *dev, struct device_attribute *attr,
1977 const char *buf, size_t count)
1978{
1979 struct nct6775_data *data = dev_get_drvdata(dev);
1980 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1981 int nr = sattr->index;
1982 unsigned long val;
1983 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001984 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001985
1986 err = kstrtoul(buf, 10, &val);
1987 if (err < 0)
1988 return err;
1989
1990 if (val > 4)
1991 return -EINVAL;
1992
1993 mutex_lock(&data->update_lock);
1994 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001995 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1996 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1997 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1998 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001999 mutex_unlock(&data->update_lock);
2000
2001 return count;
2002}
2003
Guenter Roeckf73cf632013-03-18 09:22:50 -07002004static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2005 struct attribute *attr, int index)
2006{
2007 struct device *dev = container_of(kobj, struct device, kobj);
2008 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002009 int fan = index / 6; /* fan index */
2010 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002011
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002012 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002013 return 0;
2014
2015 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2016 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002017 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002018 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002019 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002020 return 0;
2021 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002022 return 0;
2023
2024 return attr->mode;
2025}
2026
2027SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2028SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2029 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002030SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2031 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002032SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2033 store_fan_pulses, 0);
2034SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2035 store_fan_min, 0);
2036SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2037
2038/*
2039 * nct6775_fan_is_visible uses the index into the following array
2040 * to determine if attributes should be created or not.
2041 * Any change in order or content must be matched.
2042 */
2043static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2044 &sensor_dev_template_fan_input,
2045 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002046 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002047 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002048 &sensor_dev_template_fan_min, /* 4 */
2049 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002050 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002051};
2052
Julia Lawallc60fdf82015-12-12 17:36:39 +01002053static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002054 .templates = nct6775_attributes_fan_template,
2055 .is_visible = nct6775_fan_is_visible,
2056 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002057};
2058
2059static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002060show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2061{
2062 struct nct6775_data *data = nct6775_update_device(dev);
2063 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2064 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002065
Guenter Roeckaa136e52012-12-04 03:26:05 -08002066 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2067}
2068
2069static ssize_t
2070show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2071{
2072 struct nct6775_data *data = nct6775_update_device(dev);
2073 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2074 int nr = sattr->nr;
2075 int index = sattr->index;
2076
2077 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2078}
2079
2080static ssize_t
2081store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2082 size_t count)
2083{
2084 struct nct6775_data *data = dev_get_drvdata(dev);
2085 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2086 int nr = sattr->nr;
2087 int index = sattr->index;
2088 int err;
2089 long val;
2090
2091 err = kstrtol(buf, 10, &val);
2092 if (err < 0)
2093 return err;
2094
2095 mutex_lock(&data->update_lock);
2096 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2097 nct6775_write_temp(data, data->reg_temp[index][nr],
2098 data->temp[index][nr]);
2099 mutex_unlock(&data->update_lock);
2100 return count;
2101}
2102
2103static ssize_t
2104show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2105{
2106 struct nct6775_data *data = nct6775_update_device(dev);
2107 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2108
2109 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2110}
2111
2112static ssize_t
2113store_temp_offset(struct device *dev, struct device_attribute *attr,
2114 const char *buf, size_t count)
2115{
2116 struct nct6775_data *data = dev_get_drvdata(dev);
2117 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2118 int nr = sattr->index;
2119 long val;
2120 int err;
2121
2122 err = kstrtol(buf, 10, &val);
2123 if (err < 0)
2124 return err;
2125
2126 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2127
2128 mutex_lock(&data->update_lock);
2129 data->temp_offset[nr] = val;
2130 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2131 mutex_unlock(&data->update_lock);
2132
2133 return count;
2134}
2135
2136static ssize_t
2137show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2138{
2139 struct nct6775_data *data = nct6775_update_device(dev);
2140 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2141 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002142
Guenter Roeckaa136e52012-12-04 03:26:05 -08002143 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2144}
2145
2146static ssize_t
2147store_temp_type(struct device *dev, struct device_attribute *attr,
2148 const char *buf, size_t count)
2149{
2150 struct nct6775_data *data = nct6775_update_device(dev);
2151 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2152 int nr = sattr->index;
2153 unsigned long val;
2154 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002155 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002156
2157 err = kstrtoul(buf, 10, &val);
2158 if (err < 0)
2159 return err;
2160
2161 if (val != 1 && val != 3 && val != 4)
2162 return -EINVAL;
2163
2164 mutex_lock(&data->update_lock);
2165
2166 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002167 vbit = 0x02 << nr;
2168 dbit = data->DIODE_MASK << nr;
2169 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2170 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002171 switch (val) {
2172 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002173 vbat |= vbit;
2174 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002175 break;
2176 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002177 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002178 break;
2179 case 4: /* thermistor */
2180 break;
2181 }
2182 nct6775_write_value(data, data->REG_VBAT, vbat);
2183 nct6775_write_value(data, data->REG_DIODE, diode);
2184
2185 mutex_unlock(&data->update_lock);
2186 return count;
2187}
2188
Guenter Roeckf73cf632013-03-18 09:22:50 -07002189static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2190 struct attribute *attr, int index)
2191{
2192 struct device *dev = container_of(kobj, struct device, kobj);
2193 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002194 int temp = index / 10; /* temp index */
2195 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002196
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002197 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002198 return 0;
2199
2200 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2201 return 0; /* alarm */
2202
Guenter Roeck30846992013-06-24 22:21:59 -07002203 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2204 return 0; /* beep */
2205
2206 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002207 return 0;
2208
Guenter Roeck30846992013-06-24 22:21:59 -07002209 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002210 return 0;
2211
Guenter Roeck30846992013-06-24 22:21:59 -07002212 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002213 return 0;
2214
Guenter Roeck30846992013-06-24 22:21:59 -07002215 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002216 return 0;
2217
2218 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002219 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002220 return 0;
2221
2222 return attr->mode;
2223}
2224
2225SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2226SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2227SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2228 store_temp, 0, 1);
2229SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2230 show_temp, store_temp, 0, 2);
2231SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2232 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002233SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2234 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002235SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2236 show_temp_offset, store_temp_offset, 0);
2237SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2238 store_temp_type, 0);
2239SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002240SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2241 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002242
2243/*
2244 * nct6775_temp_is_visible uses the index into the following array
2245 * to determine if attributes should be created or not.
2246 * Any change in order or content must be matched.
2247 */
2248static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2249 &sensor_dev_template_temp_input,
2250 &sensor_dev_template_temp_label,
2251 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002252 &sensor_dev_template_temp_beep, /* 3 */
2253 &sensor_dev_template_temp_max, /* 4 */
2254 &sensor_dev_template_temp_max_hyst, /* 5 */
2255 &sensor_dev_template_temp_crit, /* 6 */
2256 &sensor_dev_template_temp_lcrit, /* 7 */
2257 &sensor_dev_template_temp_offset, /* 8 */
2258 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002259 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002260};
2261
Julia Lawallc60fdf82015-12-12 17:36:39 +01002262static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002263 .templates = nct6775_attributes_temp_template,
2264 .is_visible = nct6775_temp_is_visible,
2265 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002266};
2267
Guenter Roeckaa136e52012-12-04 03:26:05 -08002268static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002269show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2270{
2271 struct nct6775_data *data = nct6775_update_device(dev);
2272 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2273
2274 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2275}
2276
2277static ssize_t
2278store_pwm_mode(struct device *dev, struct device_attribute *attr,
2279 const char *buf, size_t count)
2280{
2281 struct nct6775_data *data = dev_get_drvdata(dev);
2282 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2283 int nr = sattr->index;
2284 unsigned long val;
2285 int err;
2286 u8 reg;
2287
2288 err = kstrtoul(buf, 10, &val);
2289 if (err < 0)
2290 return err;
2291
2292 if (val > 1)
2293 return -EINVAL;
2294
2295 /* Setting DC mode is not supported for all chips/channels */
2296 if (data->REG_PWM_MODE[nr] == 0) {
2297 if (val)
2298 return -EINVAL;
2299 return count;
2300 }
2301
2302 mutex_lock(&data->update_lock);
2303 data->pwm_mode[nr] = val;
2304 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2305 reg &= ~data->PWM_MODE_MASK[nr];
2306 if (val)
2307 reg |= data->PWM_MODE_MASK[nr];
2308 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2309 mutex_unlock(&data->update_lock);
2310 return count;
2311}
2312
2313static ssize_t
2314show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2315{
2316 struct nct6775_data *data = nct6775_update_device(dev);
2317 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2318 int nr = sattr->nr;
2319 int index = sattr->index;
2320 int pwm;
2321
2322 /*
2323 * For automatic fan control modes, show current pwm readings.
2324 * Otherwise, show the configured value.
2325 */
2326 if (index == 0 && data->pwm_enable[nr] > manual)
2327 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2328 else
2329 pwm = data->pwm[index][nr];
2330
2331 return sprintf(buf, "%d\n", pwm);
2332}
2333
2334static ssize_t
2335store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2336 size_t count)
2337{
2338 struct nct6775_data *data = dev_get_drvdata(dev);
2339 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2340 int nr = sattr->nr;
2341 int index = sattr->index;
2342 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002343 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2344 int maxval[7]
2345 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002346 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002347 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002348
2349 err = kstrtoul(buf, 10, &val);
2350 if (err < 0)
2351 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002352 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002353
2354 mutex_lock(&data->update_lock);
2355 data->pwm[index][nr] = val;
2356 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002357 if (index == 2) { /* floor: disable if val == 0 */
2358 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2359 reg &= 0x7f;
2360 if (val)
2361 reg |= 0x80;
2362 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2363 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002364 mutex_unlock(&data->update_lock);
2365 return count;
2366}
2367
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002368/* Returns 0 if OK, -EINVAL otherwise */
2369static int check_trip_points(struct nct6775_data *data, int nr)
2370{
2371 int i;
2372
2373 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2374 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2375 return -EINVAL;
2376 }
2377 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2378 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2379 return -EINVAL;
2380 }
2381 /* validate critical temperature and pwm if enabled (pwm > 0) */
2382 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2383 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2384 data->auto_temp[nr][data->auto_pwm_num] ||
2385 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2386 data->auto_pwm[nr][data->auto_pwm_num])
2387 return -EINVAL;
2388 }
2389 return 0;
2390}
2391
2392static void pwm_update_registers(struct nct6775_data *data, int nr)
2393{
2394 u8 reg;
2395
2396 switch (data->pwm_enable[nr]) {
2397 case off:
2398 case manual:
2399 break;
2400 case speed_cruise:
2401 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2402 reg = (reg & ~data->tolerance_mask) |
2403 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2404 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2405 nct6775_write_value(data, data->REG_TARGET[nr],
2406 data->target_speed[nr] & 0xff);
2407 if (data->REG_TOLERANCE_H) {
2408 reg = (data->target_speed[nr] >> 8) & 0x0f;
2409 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2410 nct6775_write_value(data,
2411 data->REG_TOLERANCE_H[nr],
2412 reg);
2413 }
2414 break;
2415 case thermal_cruise:
2416 nct6775_write_value(data, data->REG_TARGET[nr],
2417 data->target_temp[nr]);
2418 /* intentional */
2419 default:
2420 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2421 reg = (reg & ~data->tolerance_mask) |
2422 data->temp_tolerance[0][nr];
2423 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2424 break;
2425 }
2426}
2427
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002428static ssize_t
2429show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2430{
2431 struct nct6775_data *data = nct6775_update_device(dev);
2432 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2433
2434 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2435}
2436
2437static ssize_t
2438store_pwm_enable(struct device *dev, struct device_attribute *attr,
2439 const char *buf, size_t count)
2440{
2441 struct nct6775_data *data = dev_get_drvdata(dev);
2442 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2443 int nr = sattr->index;
2444 unsigned long val;
2445 int err;
2446 u16 reg;
2447
2448 err = kstrtoul(buf, 10, &val);
2449 if (err < 0)
2450 return err;
2451
2452 if (val > sf4)
2453 return -EINVAL;
2454
2455 if (val == sf3 && data->kind != nct6775)
2456 return -EINVAL;
2457
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002458 if (val == sf4 && check_trip_points(data, nr)) {
2459 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2460 dev_err(dev, "Adjust trip points and try again\n");
2461 return -EINVAL;
2462 }
2463
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002464 mutex_lock(&data->update_lock);
2465 data->pwm_enable[nr] = val;
2466 if (val == off) {
2467 /*
2468 * turn off pwm control: select manual mode, set pwm to maximum
2469 */
2470 data->pwm[0][nr] = 255;
2471 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2472 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002473 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002474 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2475 reg &= 0x0f;
2476 reg |= pwm_enable_to_reg(val) << 4;
2477 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2478 mutex_unlock(&data->update_lock);
2479 return count;
2480}
2481
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002482static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002483show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002484{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002485 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002486
2487 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002488 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002489 continue;
2490 if (src == data->temp_src[i]) {
2491 sel = i + 1;
2492 break;
2493 }
2494 }
2495
2496 return sprintf(buf, "%d\n", sel);
2497}
2498
2499static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002500show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2501{
2502 struct nct6775_data *data = nct6775_update_device(dev);
2503 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2504 int index = sattr->index;
2505
2506 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2507}
2508
2509static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002510store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2511 const char *buf, size_t count)
2512{
2513 struct nct6775_data *data = nct6775_update_device(dev);
2514 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2515 int nr = sattr->index;
2516 unsigned long val;
2517 int err, reg, src;
2518
2519 err = kstrtoul(buf, 10, &val);
2520 if (err < 0)
2521 return err;
2522 if (val == 0 || val > NUM_TEMP)
2523 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002524 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002525 return -EINVAL;
2526
2527 mutex_lock(&data->update_lock);
2528 src = data->temp_src[val - 1];
2529 data->pwm_temp_sel[nr] = src;
2530 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2531 reg &= 0xe0;
2532 reg |= src;
2533 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2534 mutex_unlock(&data->update_lock);
2535
2536 return count;
2537}
2538
2539static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002540show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2541 char *buf)
2542{
2543 struct nct6775_data *data = nct6775_update_device(dev);
2544 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2545 int index = sattr->index;
2546
2547 return show_pwm_temp_sel_common(data, buf,
2548 data->pwm_weight_temp_sel[index]);
2549}
2550
2551static ssize_t
2552store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2553 const char *buf, size_t count)
2554{
2555 struct nct6775_data *data = nct6775_update_device(dev);
2556 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2557 int nr = sattr->index;
2558 unsigned long val;
2559 int err, reg, src;
2560
2561 err = kstrtoul(buf, 10, &val);
2562 if (err < 0)
2563 return err;
2564 if (val > NUM_TEMP)
2565 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002566 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002567 !data->temp_src[val - 1]))
2568 return -EINVAL;
2569
2570 mutex_lock(&data->update_lock);
2571 if (val) {
2572 src = data->temp_src[val - 1];
2573 data->pwm_weight_temp_sel[nr] = src;
2574 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2575 reg &= 0xe0;
2576 reg |= (src | 0x80);
2577 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2578 } else {
2579 data->pwm_weight_temp_sel[nr] = 0;
2580 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2581 reg &= 0x7f;
2582 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2583 }
2584 mutex_unlock(&data->update_lock);
2585
2586 return count;
2587}
2588
2589static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002590show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2591{
2592 struct nct6775_data *data = nct6775_update_device(dev);
2593 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2594
2595 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2596}
2597
2598static ssize_t
2599store_target_temp(struct device *dev, struct device_attribute *attr,
2600 const char *buf, size_t count)
2601{
2602 struct nct6775_data *data = dev_get_drvdata(dev);
2603 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2604 int nr = sattr->index;
2605 unsigned long val;
2606 int err;
2607
2608 err = kstrtoul(buf, 10, &val);
2609 if (err < 0)
2610 return err;
2611
2612 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2613 data->target_temp_mask);
2614
2615 mutex_lock(&data->update_lock);
2616 data->target_temp[nr] = val;
2617 pwm_update_registers(data, nr);
2618 mutex_unlock(&data->update_lock);
2619 return count;
2620}
2621
2622static ssize_t
2623show_target_speed(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 int nr = sattr->index;
2628
2629 return sprintf(buf, "%d\n",
2630 fan_from_reg16(data->target_speed[nr],
2631 data->fan_div[nr]));
2632}
2633
2634static ssize_t
2635store_target_speed(struct device *dev, struct device_attribute *attr,
2636 const char *buf, size_t count)
2637{
2638 struct nct6775_data *data = dev_get_drvdata(dev);
2639 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2640 int nr = sattr->index;
2641 unsigned long val;
2642 int err;
2643 u16 speed;
2644
2645 err = kstrtoul(buf, 10, &val);
2646 if (err < 0)
2647 return err;
2648
2649 val = clamp_val(val, 0, 1350000U);
2650 speed = fan_to_reg(val, data->fan_div[nr]);
2651
2652 mutex_lock(&data->update_lock);
2653 data->target_speed[nr] = speed;
2654 pwm_update_registers(data, nr);
2655 mutex_unlock(&data->update_lock);
2656 return count;
2657}
2658
2659static ssize_t
2660show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2661 char *buf)
2662{
2663 struct nct6775_data *data = nct6775_update_device(dev);
2664 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2665 int nr = sattr->nr;
2666 int index = sattr->index;
2667
2668 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2669}
2670
2671static ssize_t
2672store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2673 const char *buf, size_t count)
2674{
2675 struct nct6775_data *data = dev_get_drvdata(dev);
2676 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2677 int nr = sattr->nr;
2678 int index = sattr->index;
2679 unsigned long val;
2680 int err;
2681
2682 err = kstrtoul(buf, 10, &val);
2683 if (err < 0)
2684 return err;
2685
2686 /* Limit tolerance as needed */
2687 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2688
2689 mutex_lock(&data->update_lock);
2690 data->temp_tolerance[index][nr] = val;
2691 if (index)
2692 pwm_update_registers(data, nr);
2693 else
2694 nct6775_write_value(data,
2695 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2696 val);
2697 mutex_unlock(&data->update_lock);
2698 return count;
2699}
2700
2701/*
2702 * Fan speed tolerance is a tricky beast, since the associated register is
2703 * a tick counter, but the value is reported and configured as rpm.
2704 * Compute resulting low and high rpm values and report the difference.
2705 */
2706static ssize_t
2707show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2708 char *buf)
2709{
2710 struct nct6775_data *data = nct6775_update_device(dev);
2711 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2712 int nr = sattr->index;
2713 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2714 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2715 int tolerance;
2716
2717 if (low <= 0)
2718 low = 1;
2719 if (high > 0xffff)
2720 high = 0xffff;
2721 if (high < low)
2722 high = low;
2723
2724 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2725 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2726
2727 return sprintf(buf, "%d\n", tolerance);
2728}
2729
2730static ssize_t
2731store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2732 const char *buf, size_t count)
2733{
2734 struct nct6775_data *data = dev_get_drvdata(dev);
2735 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2736 int nr = sattr->index;
2737 unsigned long val;
2738 int err;
2739 int low, high;
2740
2741 err = kstrtoul(buf, 10, &val);
2742 if (err < 0)
2743 return err;
2744
2745 high = fan_from_reg16(data->target_speed[nr],
2746 data->fan_div[nr]) + val;
2747 low = fan_from_reg16(data->target_speed[nr],
2748 data->fan_div[nr]) - val;
2749 if (low <= 0)
2750 low = 1;
2751 if (high < low)
2752 high = low;
2753
2754 val = (fan_to_reg(low, data->fan_div[nr]) -
2755 fan_to_reg(high, data->fan_div[nr])) / 2;
2756
2757 /* Limit tolerance as needed */
2758 val = clamp_val(val, 0, data->speed_tolerance_limit);
2759
2760 mutex_lock(&data->update_lock);
2761 data->target_speed_tolerance[nr] = val;
2762 pwm_update_registers(data, nr);
2763 mutex_unlock(&data->update_lock);
2764 return count;
2765}
2766
Guenter Roeckf73cf632013-03-18 09:22:50 -07002767SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2768SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2769 store_pwm_mode, 0);
2770SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2771 store_pwm_enable, 0);
2772SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2773 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2774SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2775 show_target_temp, store_target_temp, 0);
2776SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2777 show_target_speed, store_target_speed, 0);
2778SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2779 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002780
2781/* Smart Fan registers */
2782
2783static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002784show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2785{
2786 struct nct6775_data *data = nct6775_update_device(dev);
2787 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2788 int nr = sattr->nr;
2789 int index = sattr->index;
2790
2791 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2792}
2793
2794static ssize_t
2795store_weight_temp(struct device *dev, struct device_attribute *attr,
2796 const char *buf, size_t count)
2797{
2798 struct nct6775_data *data = dev_get_drvdata(dev);
2799 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2800 int nr = sattr->nr;
2801 int index = sattr->index;
2802 unsigned long val;
2803 int err;
2804
2805 err = kstrtoul(buf, 10, &val);
2806 if (err < 0)
2807 return err;
2808
2809 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2810
2811 mutex_lock(&data->update_lock);
2812 data->weight_temp[index][nr] = val;
2813 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2814 mutex_unlock(&data->update_lock);
2815 return count;
2816}
2817
Guenter Roeckf73cf632013-03-18 09:22:50 -07002818SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2819 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2820SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2821 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2822SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2823 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2824SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2825 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2826SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2827 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2828SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2829 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002830
2831static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002832show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2833{
2834 struct nct6775_data *data = nct6775_update_device(dev);
2835 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2836 int nr = sattr->nr;
2837 int index = sattr->index;
2838
2839 return sprintf(buf, "%d\n",
2840 step_time_from_reg(data->fan_time[index][nr],
2841 data->pwm_mode[nr]));
2842}
2843
2844static ssize_t
2845store_fan_time(struct device *dev, struct device_attribute *attr,
2846 const char *buf, size_t count)
2847{
2848 struct nct6775_data *data = dev_get_drvdata(dev);
2849 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2850 int nr = sattr->nr;
2851 int index = sattr->index;
2852 unsigned long val;
2853 int err;
2854
2855 err = kstrtoul(buf, 10, &val);
2856 if (err < 0)
2857 return err;
2858
2859 val = step_time_to_reg(val, data->pwm_mode[nr]);
2860 mutex_lock(&data->update_lock);
2861 data->fan_time[index][nr] = val;
2862 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2863 mutex_unlock(&data->update_lock);
2864 return count;
2865}
2866
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002867static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002868show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2869{
2870 struct nct6775_data *data = nct6775_update_device(dev);
2871 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2872
2873 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2874}
2875
2876static ssize_t
2877store_auto_pwm(struct device *dev, struct device_attribute *attr,
2878 const char *buf, size_t count)
2879{
2880 struct nct6775_data *data = dev_get_drvdata(dev);
2881 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2882 int nr = sattr->nr;
2883 int point = sattr->index;
2884 unsigned long val;
2885 int err;
2886 u8 reg;
2887
2888 err = kstrtoul(buf, 10, &val);
2889 if (err < 0)
2890 return err;
2891 if (val > 255)
2892 return -EINVAL;
2893
2894 if (point == data->auto_pwm_num) {
2895 if (data->kind != nct6775 && !val)
2896 return -EINVAL;
2897 if (data->kind != nct6779 && val)
2898 val = 0xff;
2899 }
2900
2901 mutex_lock(&data->update_lock);
2902 data->auto_pwm[nr][point] = val;
2903 if (point < data->auto_pwm_num) {
2904 nct6775_write_value(data,
2905 NCT6775_AUTO_PWM(data, nr, point),
2906 data->auto_pwm[nr][point]);
2907 } else {
2908 switch (data->kind) {
2909 case nct6775:
2910 /* disable if needed (pwm == 0) */
2911 reg = nct6775_read_value(data,
2912 NCT6775_REG_CRITICAL_ENAB[nr]);
2913 if (val)
2914 reg |= 0x02;
2915 else
2916 reg &= ~0x02;
2917 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2918 reg);
2919 break;
2920 case nct6776:
2921 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002922 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002923 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002924 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08002925 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002926 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002927 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002928 val);
2929 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002930 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002931 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002932 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002933 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002934 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002935 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002936 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002937 reg);
2938 break;
2939 }
2940 }
2941 mutex_unlock(&data->update_lock);
2942 return count;
2943}
2944
2945static ssize_t
2946show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2947{
2948 struct nct6775_data *data = nct6775_update_device(dev);
2949 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2950 int nr = sattr->nr;
2951 int point = sattr->index;
2952
2953 /*
2954 * We don't know for sure if the temperature is signed or unsigned.
2955 * Assume it is unsigned.
2956 */
2957 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2958}
2959
2960static ssize_t
2961store_auto_temp(struct device *dev, struct device_attribute *attr,
2962 const char *buf, size_t count)
2963{
2964 struct nct6775_data *data = dev_get_drvdata(dev);
2965 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2966 int nr = sattr->nr;
2967 int point = sattr->index;
2968 unsigned long val;
2969 int err;
2970
2971 err = kstrtoul(buf, 10, &val);
2972 if (err)
2973 return err;
2974 if (val > 255000)
2975 return -EINVAL;
2976
2977 mutex_lock(&data->update_lock);
2978 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2979 if (point < data->auto_pwm_num) {
2980 nct6775_write_value(data,
2981 NCT6775_AUTO_TEMP(data, nr, point),
2982 data->auto_temp[nr][point]);
2983 } else {
2984 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2985 data->auto_temp[nr][point]);
2986 }
2987 mutex_unlock(&data->update_lock);
2988 return count;
2989}
2990
Guenter Roeckf73cf632013-03-18 09:22:50 -07002991static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2992 struct attribute *attr, int index)
2993{
2994 struct device *dev = container_of(kobj, struct device, kobj);
2995 struct nct6775_data *data = dev_get_drvdata(dev);
2996 int pwm = index / 36; /* pwm index */
2997 int nr = index % 36; /* attribute index */
2998
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002999 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003000 return 0;
3001
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003002 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3003 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3004 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003005 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3006 return 0;
3007 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3008 return 0;
3009 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3010 return 0;
3011
3012 if (nr >= 22 && nr <= 35) { /* auto point */
3013 int api = (nr - 22) / 2; /* auto point index */
3014
3015 if (api > data->auto_pwm_num)
3016 return 0;
3017 }
3018 return attr->mode;
3019}
3020
3021SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3022 show_fan_time, store_fan_time, 0, 0);
3023SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3024 show_fan_time, store_fan_time, 0, 1);
3025SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3026 show_fan_time, store_fan_time, 0, 2);
3027SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3028 store_pwm, 0, 1);
3029SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3030 store_pwm, 0, 2);
3031SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3032 show_temp_tolerance, store_temp_tolerance, 0, 0);
3033SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3034 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3035 0, 1);
3036
3037SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3038 0, 3);
3039
3040SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3041 store_pwm, 0, 4);
3042
3043SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3044 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3045SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3046 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3047
3048SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3049 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3050SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3051 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3052
3053SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3054 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3055SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3056 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3057
3058SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3059 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3060SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3061 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3062
3063SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3064 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3065SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3066 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3067
3068SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3069 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3070SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3071 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3072
3073SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3074 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3075SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3076 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3077
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003078/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003079 * nct6775_pwm_is_visible uses the index into the following array
3080 * to determine if attributes should be created or not.
3081 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003082 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003083static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3084 &sensor_dev_template_pwm,
3085 &sensor_dev_template_pwm_mode,
3086 &sensor_dev_template_pwm_enable,
3087 &sensor_dev_template_pwm_temp_sel,
3088 &sensor_dev_template_pwm_temp_tolerance,
3089 &sensor_dev_template_pwm_crit_temp_tolerance,
3090 &sensor_dev_template_pwm_target_temp,
3091 &sensor_dev_template_fan_target,
3092 &sensor_dev_template_fan_tolerance,
3093 &sensor_dev_template_pwm_stop_time,
3094 &sensor_dev_template_pwm_step_up_time,
3095 &sensor_dev_template_pwm_step_down_time,
3096 &sensor_dev_template_pwm_start,
3097 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003098 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003099 &sensor_dev_template_pwm_weight_temp_step,
3100 &sensor_dev_template_pwm_weight_temp_step_tol,
3101 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003102 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003103 &sensor_dev_template_pwm_max, /* 19 */
3104 &sensor_dev_template_pwm_step, /* 20 */
3105 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3106 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3107 &sensor_dev_template_pwm_auto_point1_temp,
3108 &sensor_dev_template_pwm_auto_point2_pwm,
3109 &sensor_dev_template_pwm_auto_point2_temp,
3110 &sensor_dev_template_pwm_auto_point3_pwm,
3111 &sensor_dev_template_pwm_auto_point3_temp,
3112 &sensor_dev_template_pwm_auto_point4_pwm,
3113 &sensor_dev_template_pwm_auto_point4_temp,
3114 &sensor_dev_template_pwm_auto_point5_pwm,
3115 &sensor_dev_template_pwm_auto_point5_temp,
3116 &sensor_dev_template_pwm_auto_point6_pwm,
3117 &sensor_dev_template_pwm_auto_point6_temp,
3118 &sensor_dev_template_pwm_auto_point7_pwm,
3119 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003120
Guenter Roeckf73cf632013-03-18 09:22:50 -07003121 NULL
3122};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003123
Julia Lawallc60fdf82015-12-12 17:36:39 +01003124static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003125 .templates = nct6775_attributes_pwm_template,
3126 .is_visible = nct6775_pwm_is_visible,
3127 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003128};
3129
3130static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003131cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003132{
3133 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003134
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003135 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3136}
3137
Julia Lawall93d72ac2016-12-22 13:05:23 +01003138static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003139
Guenter Roecka6bd5872012-12-04 03:13:34 -08003140/* Case open detection */
3141
3142static ssize_t
3143clear_caseopen(struct device *dev, struct device_attribute *attr,
3144 const char *buf, size_t count)
3145{
3146 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003147 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3148 unsigned long val;
3149 u8 reg;
3150 int ret;
3151
3152 if (kstrtoul(buf, 10, &val) || val != 0)
3153 return -EINVAL;
3154
3155 mutex_lock(&data->update_lock);
3156
3157 /*
3158 * Use CR registers to clear caseopen status.
3159 * The CR registers are the same for all chips, and not all chips
3160 * support clearing the caseopen status through "regular" registers.
3161 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003162 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003163 if (ret) {
3164 count = ret;
3165 goto error;
3166 }
3167
Guenter Roeckdf612d52013-07-08 13:15:04 -07003168 superio_select(data->sioreg, NCT6775_LD_ACPI);
3169 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003170 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003171 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003172 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003173 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3174 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003175
3176 data->valid = false; /* Force cache refresh */
3177error:
3178 mutex_unlock(&data->update_lock);
3179 return count;
3180}
3181
Guenter Roeckf73cf632013-03-18 09:22:50 -07003182static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3183 clear_caseopen, INTRUSION_ALARM_BASE);
3184static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3185 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003186static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3187 store_beep, INTRUSION_ALARM_BASE);
3188static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3189 store_beep, INTRUSION_ALARM_BASE + 1);
3190static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3191 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003192
3193static umode_t nct6775_other_is_visible(struct kobject *kobj,
3194 struct attribute *attr, int index)
3195{
3196 struct device *dev = container_of(kobj, struct device, kobj);
3197 struct nct6775_data *data = dev_get_drvdata(dev);
3198
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003199 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003200 return 0;
3201
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003202 if (index == 1 || index == 2) {
3203 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003204 return 0;
3205 }
3206
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003207 if (index == 3 || index == 4) {
3208 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003209 return 0;
3210 }
3211
Guenter Roeckf73cf632013-03-18 09:22:50 -07003212 return attr->mode;
3213}
3214
3215/*
3216 * nct6775_other_is_visible uses the index into the following array
3217 * to determine if attributes should be created or not.
3218 * Any change in order or content must be matched.
3219 */
3220static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003221 &dev_attr_cpu0_vid.attr, /* 0 */
3222 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3223 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3224 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3225 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3226 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003227
3228 NULL
3229};
3230
3231static const struct attribute_group nct6775_group_other = {
3232 .attrs = nct6775_attributes_other,
3233 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003234};
3235
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003236static inline void nct6775_init_device(struct nct6775_data *data)
3237{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003238 int i;
3239 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003240
3241 /* Start monitoring if needed */
3242 if (data->REG_CONFIG) {
3243 tmp = nct6775_read_value(data, data->REG_CONFIG);
3244 if (!(tmp & 0x01))
3245 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3246 }
3247
Guenter Roeckaa136e52012-12-04 03:26:05 -08003248 /* Enable temperature sensors if needed */
3249 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003250 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003251 continue;
3252 if (!data->reg_temp_config[i])
3253 continue;
3254 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3255 if (tmp & 0x01)
3256 nct6775_write_value(data, data->reg_temp_config[i],
3257 tmp & 0xfe);
3258 }
3259
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003260 /* Enable VBAT monitoring if needed */
3261 tmp = nct6775_read_value(data, data->REG_VBAT);
3262 if (!(tmp & 0x01))
3263 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003264
3265 diode = nct6775_read_value(data, data->REG_DIODE);
3266
3267 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003268 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003269 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003270 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3271 data->temp_type[i]
3272 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003273 else /* thermistor */
3274 data->temp_type[i] = 4;
3275 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003276}
3277
Guenter Roeckf73cf632013-03-18 09:22:50 -07003278static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003279nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003280{
David Bartley578ab5f2013-06-24 22:28:28 -07003281 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3282 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003283 int sioreg = data->sioreg;
3284 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003285
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003286 /* Store SIO_REG_ENABLE for use during resume */
3287 superio_select(sioreg, NCT6775_LD_HWM);
3288 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3289
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003290 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3291 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003292 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003293
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003294 fan3pin = regval & BIT(6);
3295 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003296
3297 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003298 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003299 fan4min = false;
3300 fan5pin = false;
3301 fan6pin = false;
3302 pwm4pin = false;
3303 pwm5pin = false;
3304 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003305 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003306 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003307 const char *board_vendor, *board_name;
3308
3309 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3310 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3311
3312 if (board_name && board_vendor &&
3313 !strcmp(board_vendor, "ASRock")) {
3314 /*
3315 * Auxiliary fan monitoring is not enabled on ASRock
3316 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3317 * Observed with BIOS version 2.00.
3318 */
3319 if (!strcmp(board_name, "Z77 Pro4-M")) {
3320 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3321 data->sio_reg_enable |= 0xe0;
3322 superio_outb(sioreg, SIO_REG_ENABLE,
3323 data->sio_reg_enable);
3324 }
3325 }
3326 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003327
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003328 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003329 fan3pin = gpok;
3330 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003331 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003332
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003333 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003334 fan4pin = gpok;
3335 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003336 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003337
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003338 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003339 fan5pin = gpok;
3340 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003341 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003342
3343 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003344 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003345 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003346 pwm4pin = false;
3347 pwm5pin = false;
3348 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003349 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003350 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003351 fan3pin = !(regval & 0x80);
3352 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003353
3354 fan4pin = false;
3355 fan4min = false;
3356 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003357 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003358 pwm4pin = false;
3359 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003360 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003361 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003362 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003363
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003364 fan3pin = !(regval & BIT(5));
3365 fan4pin = !(regval & BIT(6));
3366 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003367
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003368 pwm3pin = !(regval & BIT(0));
3369 pwm4pin = !(regval & BIT(1));
3370 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003371
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003372 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003373
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003374 if (data->kind == nct6791 || data->kind == nct6792 ||
3375 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003376 regval = superio_inb(sioreg, 0x2d);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003377 fan6pin = (regval & BIT(1));
3378 pwm6pin = (regval & BIT(0));
David Bartley578ab5f2013-06-24 22:28:28 -07003379 } else { /* NCT6779D */
3380 fan6pin = false;
3381 pwm6pin = false;
3382 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003383 }
3384
David Bartley578ab5f2013-06-24 22:28:28 -07003385 /* fan 1 and 2 (0x03) are always present */
3386 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3387 (fan5pin << 4) | (fan6pin << 5);
3388 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3389 (fan5pin << 4);
3390 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3391 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003392}
3393
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003394static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3395 int *available, int *mask)
3396{
3397 int i;
3398 u8 src;
3399
3400 for (i = 0; i < data->pwm_num && *available; i++) {
3401 int index;
3402
3403 if (!regp[i])
3404 continue;
3405 src = nct6775_read_value(data, regp[i]);
3406 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003407 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003408 continue;
3409 if (src >= data->temp_label_num ||
3410 !strlen(data->temp_label[src]))
3411 continue;
3412
3413 index = __ffs(*available);
3414 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003415 *available &= ~BIT(index);
3416 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003417 }
3418}
3419
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003420static int nct6775_probe(struct platform_device *pdev)
3421{
3422 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003423 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003424 struct nct6775_data *data;
3425 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003426 int i, s, err = 0;
3427 int src, mask, available;
3428 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003429 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003430 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003431 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003432 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003433 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003434 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003435 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003436
3437 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3438 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3439 DRVNAME))
3440 return -EBUSY;
3441
3442 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3443 GFP_KERNEL);
3444 if (!data)
3445 return -ENOMEM;
3446
3447 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003448 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003449 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003450 mutex_init(&data->update_lock);
3451 data->name = nct6775_device_names[data->kind];
3452 data->bank = 0xff; /* Force initial bank selection */
3453 platform_set_drvdata(pdev, data);
3454
3455 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003456 case nct6106:
3457 data->in_num = 9;
3458 data->pwm_num = 3;
3459 data->auto_pwm_num = 4;
3460 data->temp_fixed_num = 3;
3461 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003462 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003463
3464 data->fan_from_reg = fan_from_reg13;
3465 data->fan_from_reg_min = fan_from_reg13;
3466
3467 data->temp_label = nct6776_temp_label;
3468 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3469
3470 data->REG_VBAT = NCT6106_REG_VBAT;
3471 data->REG_DIODE = NCT6106_REG_DIODE;
3472 data->DIODE_MASK = NCT6106_DIODE_MASK;
3473 data->REG_VIN = NCT6106_REG_IN;
3474 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3475 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3476 data->REG_TARGET = NCT6106_REG_TARGET;
3477 data->REG_FAN = NCT6106_REG_FAN;
3478 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3479 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3480 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3481 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3482 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3483 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3484 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3485 data->REG_PWM[0] = NCT6106_REG_PWM;
3486 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3487 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3488 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3489 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3490 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3491 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3492 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3493 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3494 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3495 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3496 data->REG_CRITICAL_TEMP_TOLERANCE
3497 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3498 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3499 data->CRITICAL_PWM_ENABLE_MASK
3500 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3501 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3502 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3503 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3504 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3505 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3506 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3507 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3508 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3509 data->REG_ALARM = NCT6106_REG_ALARM;
3510 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003511 data->REG_BEEP = NCT6106_REG_BEEP;
3512 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003513
3514 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003515 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003516 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003517 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003518 reg_temp_over = NCT6106_REG_TEMP_OVER;
3519 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3520 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3521 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3522 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003523 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3524 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003525
3526 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003527 case nct6775:
3528 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003529 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003530 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003531 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003532 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003533 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003534 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003535
3536 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003537 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003538
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003539 data->fan_from_reg = fan_from_reg16;
3540 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003541 data->target_temp_mask = 0x7f;
3542 data->tolerance_mask = 0x0f;
3543 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003544
Guenter Roeckaa136e52012-12-04 03:26:05 -08003545 data->temp_label = nct6775_temp_label;
3546 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3547
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003548 data->REG_CONFIG = NCT6775_REG_CONFIG;
3549 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003550 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003551 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003552 data->REG_VIN = NCT6775_REG_IN;
3553 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3554 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003555 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003556 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003557 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003558 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003559 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003560 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003561 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3562 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3563 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003564 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003565 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3566 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3567 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3568 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003569 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003570 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3571 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3572 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003573 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3574 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3575 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3576 data->REG_CRITICAL_TEMP_TOLERANCE
3577 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003578 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3579 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003580 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003581 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3582 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3583 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3584 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003585 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003586 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003587
3588 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003589 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003590 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003591 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003592 reg_temp_over = NCT6775_REG_TEMP_OVER;
3593 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3594 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3595 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3596 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3597
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003598 break;
3599 case nct6776:
3600 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003601 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003602 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003603 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003604 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003605 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003606 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003607
3608 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003609 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003610
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003611 data->fan_from_reg = fan_from_reg13;
3612 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003613 data->target_temp_mask = 0xff;
3614 data->tolerance_mask = 0x07;
3615 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003616
Guenter Roeckaa136e52012-12-04 03:26:05 -08003617 data->temp_label = nct6776_temp_label;
3618 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3619
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003620 data->REG_CONFIG = NCT6775_REG_CONFIG;
3621 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003622 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003623 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003624 data->REG_VIN = NCT6775_REG_IN;
3625 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3626 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003627 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003628 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003629 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003630 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003631 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003632 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003633 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003634 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3635 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003636 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003637 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003638 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3639 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003640 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3641 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003642 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3643 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3644 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003645 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3646 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3647 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3648 data->REG_CRITICAL_TEMP_TOLERANCE
3649 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003650 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3651 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003652 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003653 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3654 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3655 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3656 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003657 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003658 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003659
3660 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003661 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003662 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003663 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003664 reg_temp_over = NCT6775_REG_TEMP_OVER;
3665 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3666 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3667 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3668 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3669
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003670 break;
3671 case nct6779:
3672 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003673 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003674 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003675 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003676 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003677 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003678 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003679
3680 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003681 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003682
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003683 data->fan_from_reg = fan_from_reg13;
3684 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003685 data->target_temp_mask = 0xff;
3686 data->tolerance_mask = 0x07;
3687 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003688
Guenter Roeckaa136e52012-12-04 03:26:05 -08003689 data->temp_label = nct6779_temp_label;
Guenter Roeck9a383712015-08-29 15:29:25 -07003690 data->temp_label_num = NCT6779_NUM_LABELS;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003691
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003692 data->REG_CONFIG = NCT6775_REG_CONFIG;
3693 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003694 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003695 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003696 data->REG_VIN = NCT6779_REG_IN;
3697 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3698 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003699 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003700 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003701 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003702 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003703 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003704 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003705 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003706 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3707 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003708 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003709 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003710 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3711 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003712 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3713 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003714 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3715 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3716 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003717 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3718 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3719 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3720 data->REG_CRITICAL_TEMP_TOLERANCE
3721 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003722 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3723 data->CRITICAL_PWM_ENABLE_MASK
3724 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3725 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003726 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3727 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003728 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003729 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3730 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3731 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3732 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003733 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003734 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003735
3736 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003737 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003738 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003739 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003740 reg_temp_over = NCT6779_REG_TEMP_OVER;
3741 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3742 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3743 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3744 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3745
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003746 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003747 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08003748 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003749 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003750 data->in_num = 15;
3751 data->pwm_num = 6;
3752 data->auto_pwm_num = 4;
3753 data->has_fan_div = false;
3754 data->temp_fixed_num = 6;
3755 data->num_temp_alarms = 2;
3756 data->num_temp_beeps = 2;
3757
3758 data->ALARM_BITS = NCT6791_ALARM_BITS;
3759 data->BEEP_BITS = NCT6779_BEEP_BITS;
3760
3761 data->fan_from_reg = fan_from_reg13;
3762 data->fan_from_reg_min = fan_from_reg13;
3763 data->target_temp_mask = 0xff;
3764 data->tolerance_mask = 0x07;
3765 data->speed_tolerance_limit = 63;
3766
Guenter Roeck50224f42015-10-30 07:52:39 -07003767 switch (data->kind) {
3768 default:
3769 case nct6791:
3770 data->temp_label = nct6779_temp_label;
3771 break;
3772 case nct6792:
3773 data->temp_label = nct6792_temp_label;
3774 break;
3775 case nct6793:
3776 data->temp_label = nct6793_temp_label;
3777 break;
3778 }
Guenter Roeck9a383712015-08-29 15:29:25 -07003779 data->temp_label_num = NCT6791_NUM_LABELS;
David Bartley578ab5f2013-06-24 22:28:28 -07003780
3781 data->REG_CONFIG = NCT6775_REG_CONFIG;
3782 data->REG_VBAT = NCT6775_REG_VBAT;
3783 data->REG_DIODE = NCT6775_REG_DIODE;
3784 data->DIODE_MASK = NCT6775_DIODE_MASK;
3785 data->REG_VIN = NCT6779_REG_IN;
3786 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3787 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3788 data->REG_TARGET = NCT6775_REG_TARGET;
3789 data->REG_FAN = NCT6779_REG_FAN;
3790 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3791 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3792 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3793 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3794 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003795 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3796 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003797 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3798 data->REG_PWM[0] = NCT6775_REG_PWM;
3799 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3800 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003801 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3802 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003803 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3804 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3805 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3806 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3807 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3808 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3809 data->REG_CRITICAL_TEMP_TOLERANCE
3810 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3811 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3812 data->CRITICAL_PWM_ENABLE_MASK
3813 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3814 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3815 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3816 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3817 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003818 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3819 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3820 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3821 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003822 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08003823 if (data->kind == nct6791)
3824 data->REG_BEEP = NCT6776_REG_BEEP;
3825 else
3826 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003827
3828 reg_temp = NCT6779_REG_TEMP;
3829 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08003830 if (data->kind == nct6791) {
3831 reg_temp_mon = NCT6779_REG_TEMP_MON;
3832 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3833 } else {
3834 reg_temp_mon = NCT6792_REG_TEMP_MON;
3835 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3836 }
David Bartley578ab5f2013-06-24 22:28:28 -07003837 reg_temp_over = NCT6779_REG_TEMP_OVER;
3838 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3839 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3840 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3841 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3842
3843 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003844 default:
3845 return -ENODEV;
3846 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003847 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003848 data->have_temp = 0;
3849
3850 /*
3851 * On some boards, not all available temperature sources are monitored,
3852 * even though some of the monitoring registers are unused.
3853 * Get list of unused monitoring registers, then detect if any fan
3854 * controls are configured to use unmonitored temperature sources.
3855 * If so, assign the unmonitored temperature sources to available
3856 * monitoring registers.
3857 */
3858 mask = 0;
3859 available = 0;
3860 for (i = 0; i < num_reg_temp; i++) {
3861 if (reg_temp[i] == 0)
3862 continue;
3863
3864 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003865 if (!src || (mask & BIT(src)))
3866 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003867
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003868 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003869 }
3870
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003871 /*
3872 * Now find unmonitored temperature registers and enable monitoring
3873 * if additional monitoring registers are available.
3874 */
3875 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3876 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3877
Guenter Roeckaa136e52012-12-04 03:26:05 -08003878 mask = 0;
3879 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3880 for (i = 0; i < num_reg_temp; i++) {
3881 if (reg_temp[i] == 0)
3882 continue;
3883
3884 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003885 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003886 continue;
3887
3888 if (src >= data->temp_label_num ||
3889 !strlen(data->temp_label[src])) {
3890 dev_info(dev,
3891 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3892 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3893 continue;
3894 }
3895
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003896 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003897
3898 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3899 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003900 data->have_temp |= BIT(src - 1);
3901 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003902 data->reg_temp[0][src - 1] = reg_temp[i];
3903 data->reg_temp[1][src - 1] = reg_temp_over[i];
3904 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003905 if (reg_temp_crit_h && reg_temp_crit_h[i])
3906 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3907 else if (reg_temp_crit[src - 1])
3908 data->reg_temp[3][src - 1]
3909 = reg_temp_crit[src - 1];
3910 if (reg_temp_crit_l && reg_temp_crit_l[i])
3911 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003912 data->reg_temp_config[src - 1] = reg_temp_config[i];
3913 data->temp_src[src - 1] = src;
3914 continue;
3915 }
3916
3917 if (s >= NUM_TEMP)
3918 continue;
3919
3920 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003921 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003922 data->reg_temp[0][s] = reg_temp[i];
3923 data->reg_temp[1][s] = reg_temp_over[i];
3924 data->reg_temp[2][s] = reg_temp_hyst[i];
3925 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003926 if (reg_temp_crit_h && reg_temp_crit_h[i])
3927 data->reg_temp[3][s] = reg_temp_crit_h[i];
3928 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003929 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003930 if (reg_temp_crit_l && reg_temp_crit_l[i])
3931 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003932
3933 data->temp_src[s] = src;
3934 s++;
3935 }
3936
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003937 /*
3938 * Repeat with temperatures used for fan control.
3939 * This set of registers does not support limits.
3940 */
3941 for (i = 0; i < num_reg_temp_mon; i++) {
3942 if (reg_temp_mon[i] == 0)
3943 continue;
3944
3945 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07003946 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003947 continue;
3948
3949 if (src >= data->temp_label_num ||
3950 !strlen(data->temp_label[src])) {
3951 dev_info(dev,
3952 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3953 src, i, data->REG_TEMP_SEL[i],
3954 reg_temp_mon[i]);
3955 continue;
3956 }
3957
Guenter Roeck7ce41902016-09-11 12:42:52 -07003958 /*
3959 * For virtual temperature sources, the 'virtual' temperature
3960 * for each fan reflects a different temperature, and there
3961 * are no duplicates.
3962 */
3963 if (src != TEMP_SOURCE_VIRTUAL) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003964 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07003965 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003966 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07003967 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003968
3969 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3970 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003971 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003972 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003973 data->have_temp |= BIT(src - 1);
3974 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003975 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3976 data->temp_src[src - 1] = src;
3977 continue;
3978 }
3979
3980 if (s >= NUM_TEMP)
3981 continue;
3982
3983 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003984 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003985 data->reg_temp[0][s] = reg_temp_mon[i];
3986 data->temp_src[s] = src;
3987 s++;
3988 }
3989
Guenter Roeckaa136e52012-12-04 03:26:05 -08003990#ifdef USE_ALTERNATE
3991 /*
3992 * Go through the list of alternate temp registers and enable
3993 * if possible.
3994 * The temperature is already monitored if the respective bit in <mask>
3995 * is set.
3996 */
3997 for (i = 0; i < data->temp_label_num - 1; i++) {
3998 if (!reg_temp_alternate[i])
3999 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004000 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004001 continue;
4002 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004003 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004004 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004005 data->have_temp |= BIT(i);
4006 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004007 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07004008 if (i < num_reg_temp) {
4009 data->reg_temp[1][i] = reg_temp_over[i];
4010 data->reg_temp[2][i] = reg_temp_hyst[i];
4011 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004012 data->temp_src[i] = i + 1;
4013 continue;
4014 }
4015
4016 if (s >= NUM_TEMP) /* Abort if no more space */
4017 break;
4018
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004019 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004020 data->reg_temp[0][s] = reg_temp_alternate[i];
4021 data->temp_src[s] = i + 1;
4022 s++;
4023 }
4024#endif /* USE_ALTERNATE */
4025
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004026 /* Initialize the chip */
4027 nct6775_init_device(data);
4028
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004029 err = superio_enter(sio_data->sioreg);
4030 if (err)
4031 return err;
4032
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004033 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4034 switch (data->kind) {
4035 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004036 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004037 break;
4038 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004039 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004040 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004041 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004042 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004043 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08004044 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004045 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004046 break;
4047 }
4048
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004049 /*
4050 * Read VID value
4051 * We can get the VID input values directly at logical device D 0xe3.
4052 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004053 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004054 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4055 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4056 data->vrm = vid_which_vrm();
4057 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004058
4059 if (fan_debounce) {
4060 u8 tmp;
4061
4062 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4063 tmp = superio_inb(sio_data->sioreg,
4064 NCT6775_REG_CR_FAN_DEBOUNCE);
4065 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004066 case nct6106:
4067 tmp |= 0xe0;
4068 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004069 case nct6775:
4070 tmp |= 0x1e;
4071 break;
4072 case nct6776:
4073 case nct6779:
4074 tmp |= 0x3e;
4075 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004076 case nct6791:
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08004077 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004078 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07004079 tmp |= 0x7e;
4080 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004081 }
4082 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4083 tmp);
4084 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4085 data->name);
4086 }
4087
Guenter Roeckdf612d52013-07-08 13:15:04 -07004088 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004089
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004090 superio_exit(sio_data->sioreg);
4091
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004092 /* Read fan clock dividers immediately */
4093 nct6775_init_fan_common(dev, data);
4094
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004095 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004096 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4097 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004098 if (IS_ERR(group))
4099 return PTR_ERR(group);
4100
Axel Lin55bdee62014-07-24 08:59:34 +08004101 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004102
Guenter Roeckf73cf632013-03-18 09:22:50 -07004103 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4104 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004105 if (IS_ERR(group))
4106 return PTR_ERR(group);
4107
Axel Lin55bdee62014-07-24 08:59:34 +08004108 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004109
Guenter Roeckf73cf632013-03-18 09:22:50 -07004110 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4111 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004112 if (IS_ERR(group))
4113 return PTR_ERR(group);
4114
Axel Lin55bdee62014-07-24 08:59:34 +08004115 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004116
Guenter Roeckf73cf632013-03-18 09:22:50 -07004117 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4118 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004119 if (IS_ERR(group))
4120 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004121
Axel Lin55bdee62014-07-24 08:59:34 +08004122 data->groups[num_attr_groups++] = group;
4123 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004124
Guenter Roecka150d952013-07-11 22:55:22 -07004125 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4126 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004127 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004128}
4129
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004130static void nct6791_enable_io_mapping(int sioaddr)
4131{
4132 int val;
4133
4134 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4135 if (val & 0x10) {
4136 pr_info("Enabling hardware monitor logical device mappings.\n");
4137 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4138 val & ~0x10);
4139 }
4140}
4141
Guenter Roeck48e93182015-02-07 08:48:49 -08004142static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004143{
4144 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004145
4146 mutex_lock(&data->update_lock);
4147 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004148 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004149 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4150 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4151 }
4152 mutex_unlock(&data->update_lock);
4153
4154 return 0;
4155}
4156
Guenter Roeck48e93182015-02-07 08:48:49 -08004157static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004158{
4159 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004160 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004161 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004162 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004163
4164 mutex_lock(&data->update_lock);
4165 data->bank = 0xff; /* Force initial bank selection */
4166
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004167 err = superio_enter(sioreg);
4168 if (err)
4169 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004170
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004171 superio_select(sioreg, NCT6775_LD_HWM);
4172 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4173 if (reg != data->sio_reg_enable)
4174 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4175
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004176 if (data->kind == nct6791 || data->kind == nct6792 ||
4177 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004178 nct6791_enable_io_mapping(sioreg);
4179
4180 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004181
Guenter Roeck84d19d92012-12-04 08:01:39 -08004182 /* Restore limits */
4183 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004184 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004185 continue;
4186
4187 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4188 data->in[i][1]);
4189 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4190 data->in[i][2]);
4191 }
4192
Guenter Roeckc409fd42013-04-09 05:04:00 -07004193 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004194 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004195 continue;
4196
4197 nct6775_write_value(data, data->REG_FAN_MIN[i],
4198 data->fan_min[i]);
4199 }
4200
4201 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004202 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004203 continue;
4204
Guenter Roeckc409fd42013-04-09 05:04:00 -07004205 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004206 if (data->reg_temp[j][i])
4207 nct6775_write_temp(data, data->reg_temp[j][i],
4208 data->temp[j][i]);
4209 }
4210
4211 /* Restore other settings */
4212 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004213 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004214 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4215 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4216 }
4217
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004218abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004219 /* Force re-reading all values */
4220 data->valid = false;
4221 mutex_unlock(&data->update_lock);
4222
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004223 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004224}
4225
Guenter Roeck48e93182015-02-07 08:48:49 -08004226static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004227
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004228static struct platform_driver nct6775_driver = {
4229 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004231 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004232 },
4233 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004234};
4235
4236/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004237static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004238{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004239 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004240 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004241 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004242
4243 err = superio_enter(sioaddr);
4244 if (err)
4245 return err;
4246
Guenter Roeckfc72af32016-08-03 22:07:18 -07004247 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4248 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4249 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004250 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004251
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004252 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004253 case SIO_NCT6106_ID:
4254 sio_data->kind = nct6106;
4255 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004256 case SIO_NCT6775_ID:
4257 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004258 break;
4259 case SIO_NCT6776_ID:
4260 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004261 break;
4262 case SIO_NCT6779_ID:
4263 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004264 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004265 case SIO_NCT6791_ID:
4266 sio_data->kind = nct6791;
4267 break;
Guenter Roeck8aefb93f2014-11-16 09:50:04 -08004268 case SIO_NCT6792_ID:
4269 sio_data->kind = nct6792;
4270 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004271 case SIO_NCT6793_ID:
4272 sio_data->kind = nct6793;
4273 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004274 default:
4275 if (val != 0xffff)
4276 pr_debug("unsupported chip ID: 0x%04x\n", val);
4277 superio_exit(sioaddr);
4278 return -ENODEV;
4279 }
4280
4281 /* We have a known chip, find the HWM I/O address */
4282 superio_select(sioaddr, NCT6775_LD_HWM);
4283 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4284 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004285 addr = val & IOREGION_ALIGNMENT;
4286 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004287 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4288 superio_exit(sioaddr);
4289 return -ENODEV;
4290 }
4291
4292 /* Activate logical device if needed */
4293 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4294 if (!(val & 0x01)) {
4295 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4296 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4297 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004298
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004299 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4300 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004301 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004302
4303 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004304 pr_info("Found %s or compatible chip at %#x:%#x\n",
4305 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004306 sio_data->sioreg = sioaddr;
4307
Guenter Roeck698a7c22013-04-05 07:35:25 -07004308 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004309}
4310
4311/*
4312 * when Super-I/O functions move to a separate file, the Super-I/O
4313 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004314 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004315 * must keep track of the device
4316 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004317static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004318
4319static int __init sensors_nct6775_init(void)
4320{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004321 int i, err;
4322 bool found = false;
4323 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004324 struct resource res;
4325 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004326 int sioaddr[2] = { 0x2e, 0x4e };
4327
4328 err = platform_driver_register(&nct6775_driver);
4329 if (err)
4330 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004331
4332 /*
4333 * initialize sio_data->kind and sio_data->sioreg.
4334 *
4335 * when Super-I/O functions move to a separate file, the Super-I/O
4336 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4337 * nct6775 hardware monitor, and call probe()
4338 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004339 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4340 address = nct6775_find(sioaddr[i], &sio_data);
4341 if (address <= 0)
4342 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004343
Guenter Roeck698a7c22013-04-05 07:35:25 -07004344 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004345
Guenter Roeck698a7c22013-04-05 07:35:25 -07004346 pdev[i] = platform_device_alloc(DRVNAME, address);
4347 if (!pdev[i]) {
4348 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004349 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004350 }
4351
4352 err = platform_device_add_data(pdev[i], &sio_data,
4353 sizeof(struct nct6775_sio_data));
4354 if (err)
4355 goto exit_device_put;
4356
4357 memset(&res, 0, sizeof(res));
4358 res.name = DRVNAME;
4359 res.start = address + IOREGION_OFFSET;
4360 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4361 res.flags = IORESOURCE_IO;
4362
4363 err = acpi_check_resource_conflict(&res);
4364 if (err) {
4365 platform_device_put(pdev[i]);
4366 pdev[i] = NULL;
4367 continue;
4368 }
4369
4370 err = platform_device_add_resources(pdev[i], &res, 1);
4371 if (err)
4372 goto exit_device_put;
4373
4374 /* platform_device_add calls probe() */
4375 err = platform_device_add(pdev[i]);
4376 if (err)
4377 goto exit_device_put;
4378 }
4379 if (!found) {
4380 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004381 goto exit_unregister;
4382 }
4383
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004384 return 0;
4385
4386exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004387 platform_device_put(pdev[i]);
4388exit_device_unregister:
4389 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004390 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004391 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004392 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004393exit_unregister:
4394 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004395 return err;
4396}
4397
4398static void __exit sensors_nct6775_exit(void)
4399{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004400 int i;
4401
4402 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4403 if (pdev[i])
4404 platform_device_unregister(pdev[i]);
4405 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004406 platform_driver_unregister(&nct6775_driver);
4407}
4408
4409MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004410MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004411MODULE_LICENSE("GPL");
4412
4413module_init(sensors_nct6775_init);
4414module_exit(sensors_nct6775_exit);