blob: cebd716ddc91a00bbd60e6acb7bddc8c6346223f [file] [log] [blame]
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001/*
2 * nct6775 - Driver for the hardware monitoring functionality of
3 * Nuvoton NCT677x Super-I/O chips
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from w83627ehf driver
Jean Delvare7c81c602014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070042 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck419220d2017-05-17 18:19:18 -070043 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
44 *
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070045 *
46 * #temp lists the number of monitored temperature sources (first value) plus
47 * the number of directly connectable temperature sensors (second value).
48 */
49
50#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51
52#include <linux/module.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/jiffies.h>
56#include <linux/platform_device.h>
57#include <linux/hwmon.h>
58#include <linux/hwmon-sysfs.h>
59#include <linux/hwmon-vid.h>
60#include <linux/err.h>
61#include <linux/mutex.h>
62#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070063#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080064#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070065#include <linux/io.h>
66#include "lm75.h"
67
Guenter Roeckaa136e52012-12-04 03:26:05 -080068#define USE_ALTERNATE
69
Guenter Roeck419220d2017-05-17 18:19:18 -070070enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
71 nct6795 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070072
73/* used to set data->name = nct6775_device_names[data->sio_kind] */
74static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070075 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070076 "nct6775",
77 "nct6776",
78 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070079 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080080 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070081 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070082 "nct6795",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070083};
84
85static const char * const nct6775_sio_names[] __initconst = {
86 "NCT6106D",
87 "NCT6775F",
88 "NCT6776D/F",
89 "NCT6779D",
90 "NCT6791D",
91 "NCT6792D",
92 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -070093 "NCT6795D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070094};
95
96static unsigned short force_id;
97module_param(force_id, ushort, 0);
98MODULE_PARM_DESC(force_id, "Override the detected device ID");
99
Guenter Roeck47ece962012-12-04 07:59:32 -0800100static unsigned short fan_debounce;
101module_param(fan_debounce, ushort, 0);
102MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
103
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700104#define DRVNAME "nct6775"
105
106/*
107 * Super-I/O constants and functions
108 */
109
Guenter Roecka6bd5872012-12-04 03:13:34 -0800110#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700111#define NCT6775_LD_HWM 0x0b
112#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700113#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114
115#define SIO_REG_LDSEL 0x07 /* Logical device select */
116#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
117#define SIO_REG_ENABLE 0x30 /* Logical device enable */
118#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
119
Guenter Roeck6c009502012-07-01 08:23:15 -0700120#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700121#define SIO_NCT6775_ID 0xb470
122#define SIO_NCT6776_ID 0xc330
123#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700124#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800125#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700126#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700127#define SIO_NCT6795_ID 0xd350
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700128#define SIO_ID_MASK 0xFFF0
129
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800130enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
131
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700132static inline void
133superio_outb(int ioreg, int reg, int val)
134{
135 outb(reg, ioreg);
136 outb(val, ioreg + 1);
137}
138
139static inline int
140superio_inb(int ioreg, int reg)
141{
142 outb(reg, ioreg);
143 return inb(ioreg + 1);
144}
145
146static inline void
147superio_select(int ioreg, int ld)
148{
149 outb(SIO_REG_LDSEL, ioreg);
150 outb(ld, ioreg + 1);
151}
152
153static inline int
154superio_enter(int ioreg)
155{
156 /*
157 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
158 */
159 if (!request_muxed_region(ioreg, 2, DRVNAME))
160 return -EBUSY;
161
162 outb(0x87, ioreg);
163 outb(0x87, ioreg);
164
165 return 0;
166}
167
168static inline void
169superio_exit(int ioreg)
170{
171 outb(0xaa, ioreg);
172 outb(0x02, ioreg);
173 outb(0x02, ioreg + 1);
174 release_region(ioreg, 2);
175}
176
177/*
178 * ISA constants
179 */
180
181#define IOREGION_ALIGNMENT (~7)
182#define IOREGION_OFFSET 5
183#define IOREGION_LENGTH 2
184#define ADDR_REG_OFFSET 0
185#define DATA_REG_OFFSET 1
186
187#define NCT6775_REG_BANK 0x4E
188#define NCT6775_REG_CONFIG 0x40
189
190/*
191 * Not currently used:
192 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
193 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
194 * REG_MAN_ID is at port 0x4f
195 * REG_CHIP_ID is at port 0x58
196 */
197
Guenter Roeckaa136e52012-12-04 03:26:05 -0800198#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
199#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
200
Guenter Roeck6c009502012-07-01 08:23:15 -0700201#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700202#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700203
David Bartley578ab5f2013-06-24 22:28:28 -0700204#define NUM_FAN 6
205
Guenter Roeck7ce41902016-09-11 12:42:52 -0700206#define TEMP_SOURCE_VIRTUAL 0x1f
207
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700208/* Common and NCT6775 specific data */
209
210/* Voltage min/max registers for nr=7..14 are in bank 5 */
211
212static const u16 NCT6775_REG_IN_MAX[] = {
213 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
214 0x55c, 0x55e, 0x560, 0x562 };
215static const u16 NCT6775_REG_IN_MIN[] = {
216 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
217 0x55d, 0x55f, 0x561, 0x563 };
218static const u16 NCT6775_REG_IN[] = {
219 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
220};
221
222#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800223#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700224#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700225
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800226#define NCT6775_REG_FANDIV1 0x506
227#define NCT6775_REG_FANDIV2 0x507
228
Guenter Roeck47ece962012-12-04 07:59:32 -0800229#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
230
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700231static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
232
Guenter Roeck30846992013-06-24 22:21:59 -0700233/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700234
235static const s8 NCT6775_ALARM_BITS[] = {
236 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
237 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
238 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700239 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700240 -1, -1, -1, /* unused */
241 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
242 12, -1 }; /* intrusion0, intrusion1 */
243
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800244#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800245#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800246#define INTRUSION_ALARM_BASE 30
247
Guenter Roeck30846992013-06-24 22:21:59 -0700248static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
249
250/*
251 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
252 * 30..31 intrusion
253 */
254static const s8 NCT6775_BEEP_BITS[] = {
255 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
256 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
257 21, /* global beep enable */
258 6, 7, 11, 28, -1, /* fan1..fan5 */
259 -1, -1, -1, /* unused */
260 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
261 12, -1 }; /* intrusion0, intrusion1 */
262
263#define BEEP_ENABLE_BASE 15
264
Guenter Roecka6bd5872012-12-04 03:13:34 -0800265static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
266static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
267
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800268/* DC or PWM output fan configuration */
269static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
270static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
271
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800272/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800273
David Bartley578ab5f2013-06-24 22:28:28 -0700274static const u16 NCT6775_REG_TARGET[] = {
275 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
276static const u16 NCT6775_REG_FAN_MODE[] = {
277 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800278static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700279 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800280static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700281 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800282static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700283 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
284static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
285 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800286static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
287static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
288
289static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700290 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
291static const u16 NCT6775_REG_PWM[] = {
292 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
293static const u16 NCT6775_REG_PWM_READ[] = {
294 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800295
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800296static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
297static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800298static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700299static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800300
Guenter Roeckaa136e52012-12-04 03:26:05 -0800301static const u16 NCT6775_REG_TEMP[] = {
302 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
303
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800304static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
305
Guenter Roeckaa136e52012-12-04 03:26:05 -0800306static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
307 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
308static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
309 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
310static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
311 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
312
313static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
314 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
315
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800316static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700317 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800318
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800319static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700320 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800321static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700322 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800323static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700324 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800325static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700326 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800327static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700328 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800329
Guenter Roeckaa136e52012-12-04 03:26:05 -0800330static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
331
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800332static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700333 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800334static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700335 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800336
337#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
338#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
339
340static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
341
342static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700343 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800344static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700345 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800346
Guenter Roeckaa136e52012-12-04 03:26:05 -0800347static const char *const nct6775_temp_label[] = {
348 "",
349 "SYSTIN",
350 "CPUTIN",
351 "AUXTIN",
352 "AMD SB-TSI",
353 "PECI Agent 0",
354 "PECI Agent 1",
355 "PECI Agent 2",
356 "PECI Agent 3",
357 "PECI Agent 4",
358 "PECI Agent 5",
359 "PECI Agent 6",
360 "PECI Agent 7",
361 "PCH_CHIP_CPU_MAX_TEMP",
362 "PCH_CHIP_TEMP",
363 "PCH_CPU_TEMP",
364 "PCH_MCH_TEMP",
365 "PCH_DIM0_TEMP",
366 "PCH_DIM1_TEMP",
367 "PCH_DIM2_TEMP",
368 "PCH_DIM3_TEMP"
369};
370
Guenter Roeckcc66b302017-05-17 18:05:06 -0700371#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800372
Guenter Roeckcc66b302017-05-17 18:05:06 -0700373static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
374 [13] = 0x661,
375 [14] = 0x662,
376 [15] = 0x664,
377};
378
379static const u16 NCT6775_REG_TEMP_CRIT[32] = {
380 [4] = 0xa00,
381 [5] = 0xa01,
382 [6] = 0xa02,
383 [7] = 0xa03,
384 [8] = 0xa04,
385 [9] = 0xa05,
386 [10] = 0xa06,
387 [11] = 0xa07
388};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800389
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700390/* NCT6776 specific data */
391
Guenter Roeck728d2942015-08-31 16:13:47 -0700392/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
393#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
394#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
395
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700396static const s8 NCT6776_ALARM_BITS[] = {
397 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
398 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
399 -1, /* unused */
400 6, 7, 11, 10, 23, /* fan1..fan5 */
401 -1, -1, -1, /* unused */
402 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
403 12, 9 }; /* intrusion0, intrusion1 */
404
Guenter Roeck30846992013-06-24 22:21:59 -0700405static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
406
407static const s8 NCT6776_BEEP_BITS[] = {
408 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
409 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
410 24, /* global beep enable */
411 25, 26, 27, 28, 29, /* fan1..fan5 */
412 -1, -1, -1, /* unused */
413 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
414 30, 31 }; /* intrusion0, intrusion1 */
415
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800416static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700417 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800418
David Bartley578ab5f2013-06-24 22:28:28 -0700419static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
420static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800421
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800422static const u16 NCT6776_REG_FAN_MIN[] = {
423 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a };
424static const u16 NCT6776_REG_FAN_PULSES[] = {
425 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800426
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800427static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700428 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800429
Guenter Roeckaa136e52012-12-04 03:26:05 -0800430static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
431 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
432
433static const char *const nct6776_temp_label[] = {
434 "",
435 "SYSTIN",
436 "CPUTIN",
437 "AUXTIN",
438 "SMBUSMASTER 0",
439 "SMBUSMASTER 1",
440 "SMBUSMASTER 2",
441 "SMBUSMASTER 3",
442 "SMBUSMASTER 4",
443 "SMBUSMASTER 5",
444 "SMBUSMASTER 6",
445 "SMBUSMASTER 7",
446 "PECI Agent 0",
447 "PECI Agent 1",
448 "PCH_CHIP_CPU_MAX_TEMP",
449 "PCH_CHIP_TEMP",
450 "PCH_CPU_TEMP",
451 "PCH_MCH_TEMP",
452 "PCH_DIM0_TEMP",
453 "PCH_DIM1_TEMP",
454 "PCH_DIM2_TEMP",
455 "PCH_DIM3_TEMP",
456 "BYTE_TEMP"
457};
458
Guenter Roeckcc66b302017-05-17 18:05:06 -0700459#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeckaa136e52012-12-04 03:26:05 -0800460
Guenter Roeckcc66b302017-05-17 18:05:06 -0700461static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
462 [14] = 0x401,
463 [15] = 0x402,
464 [16] = 0x404,
465};
466
467static const u16 NCT6776_REG_TEMP_CRIT[32] = {
468 [11] = 0x709,
469 [12] = 0x70a,
470};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800471
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700472/* NCT6779 specific data */
473
474static const u16 NCT6779_REG_IN[] = {
475 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
476 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
477
478static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
479 0x459, 0x45A, 0x45B, 0x568 };
480
481static const s8 NCT6779_ALARM_BITS[] = {
482 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
483 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
484 -1, /* unused */
485 6, 7, 11, 10, 23, /* fan1..fan5 */
486 -1, -1, -1, /* unused */
487 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
488 12, 9 }; /* intrusion0, intrusion1 */
489
Guenter Roeck30846992013-06-24 22:21:59 -0700490static const s8 NCT6779_BEEP_BITS[] = {
491 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
492 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
493 24, /* global beep enable */
494 25, 26, 27, 28, 29, /* fan1..fan5 */
495 -1, -1, -1, /* unused */
496 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
497 30, 31 }; /* intrusion0, intrusion1 */
498
David Bartley578ab5f2013-06-24 22:28:28 -0700499static const u16 NCT6779_REG_FAN[] = {
500 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800501static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700502 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800503
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800504static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700505 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700506#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800507static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700508 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800509
Guenter Roeckaa136e52012-12-04 03:26:05 -0800510static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800511static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800512static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
513 0x18, 0x152 };
514static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
515 0x3a, 0x153 };
516static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
517 0x39, 0x155 };
518
519static const u16 NCT6779_REG_TEMP_OFFSET[] = {
520 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
521
522static const char *const nct6779_temp_label[] = {
523 "",
524 "SYSTIN",
525 "CPUTIN",
526 "AUXTIN0",
527 "AUXTIN1",
528 "AUXTIN2",
529 "AUXTIN3",
530 "",
531 "SMBUSMASTER 0",
532 "SMBUSMASTER 1",
533 "SMBUSMASTER 2",
534 "SMBUSMASTER 3",
535 "SMBUSMASTER 4",
536 "SMBUSMASTER 5",
537 "SMBUSMASTER 6",
538 "SMBUSMASTER 7",
539 "PECI Agent 0",
540 "PECI Agent 1",
541 "PCH_CHIP_CPU_MAX_TEMP",
542 "PCH_CHIP_TEMP",
543 "PCH_CPU_TEMP",
544 "PCH_MCH_TEMP",
545 "PCH_DIM0_TEMP",
546 "PCH_DIM1_TEMP",
547 "PCH_DIM2_TEMP",
548 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700549 "BYTE_TEMP",
550 "",
551 "",
552 "",
553 "",
554 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800555};
556
Guenter Roeckcc66b302017-05-17 18:05:06 -0700557#define NCT6779_TEMP_MASK 0x07ffff7e
558#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck9a383712015-08-29 15:29:25 -0700559
Guenter Roeckcc66b302017-05-17 18:05:06 -0700560static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800561 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
562 0, 0, 0, 0, 0, 0, 0, 0,
563 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
564 0x408, 0 };
565
Guenter Roeckcc66b302017-05-17 18:05:06 -0700566static const u16 NCT6779_REG_TEMP_CRIT[32] = {
567 [15] = 0x709,
568 [16] = 0x70a,
569};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800570
David Bartley578ab5f2013-06-24 22:28:28 -0700571/* NCT6791 specific data */
572
573#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
574
Guenter Roecke2617262018-02-21 13:09:36 -0800575static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
576static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
577static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
578static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
579static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
580static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800581
David Bartley578ab5f2013-06-24 22:28:28 -0700582static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
583 0x459, 0x45A, 0x45B, 0x568, 0x45D };
584
585static const s8 NCT6791_ALARM_BITS[] = {
586 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
587 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
588 -1, /* unused */
589 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
590 -1, -1, /* unused */
591 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
592 12, 9 }; /* intrusion0, intrusion1 */
593
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700594/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800595
596static const u16 NCT6792_REG_TEMP_MON[] = {
597 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
598static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
599 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700600
Guenter Roeck50224f42015-10-30 07:52:39 -0700601static const char *const nct6792_temp_label[] = {
602 "",
603 "SYSTIN",
604 "CPUTIN",
605 "AUXTIN0",
606 "AUXTIN1",
607 "AUXTIN2",
608 "AUXTIN3",
609 "",
610 "SMBUSMASTER 0",
611 "SMBUSMASTER 1",
612 "SMBUSMASTER 2",
613 "SMBUSMASTER 3",
614 "SMBUSMASTER 4",
615 "SMBUSMASTER 5",
616 "SMBUSMASTER 6",
617 "SMBUSMASTER 7",
618 "PECI Agent 0",
619 "PECI Agent 1",
620 "PCH_CHIP_CPU_MAX_TEMP",
621 "PCH_CHIP_TEMP",
622 "PCH_CPU_TEMP",
623 "PCH_MCH_TEMP",
624 "PCH_DIM0_TEMP",
625 "PCH_DIM1_TEMP",
626 "PCH_DIM2_TEMP",
627 "PCH_DIM3_TEMP",
628 "BYTE_TEMP",
629 "PECI Agent 0 Calibration",
630 "PECI Agent 1 Calibration",
631 "",
632 "",
633 "Virtual_TEMP"
634};
635
Guenter Roeckcc66b302017-05-17 18:05:06 -0700636#define NCT6792_TEMP_MASK 0x9fffff7e
637
Guenter Roeck50224f42015-10-30 07:52:39 -0700638static const char *const nct6793_temp_label[] = {
639 "",
640 "SYSTIN",
641 "CPUTIN",
642 "AUXTIN0",
643 "AUXTIN1",
644 "AUXTIN2",
645 "AUXTIN3",
646 "",
647 "SMBUSMASTER 0",
648 "SMBUSMASTER 1",
649 "",
650 "",
651 "",
652 "",
653 "",
654 "",
655 "PECI Agent 0",
656 "PECI Agent 1",
657 "PCH_CHIP_CPU_MAX_TEMP",
658 "PCH_CHIP_TEMP",
659 "PCH_CPU_TEMP",
660 "PCH_MCH_TEMP",
661 "Agent0 Dimm0 ",
662 "Agent0 Dimm1",
663 "Agent1 Dimm0",
664 "Agent1 Dimm1",
665 "BYTE_TEMP0",
666 "BYTE_TEMP1",
667 "PECI Agent 0 Calibration",
668 "PECI Agent 1 Calibration",
669 "",
670 "Virtual_TEMP"
671};
672
Guenter Roeckcc66b302017-05-17 18:05:06 -0700673#define NCT6793_TEMP_MASK 0xbfff037e
674
Guenter Roeck419220d2017-05-17 18:19:18 -0700675static const char *const nct6795_temp_label[] = {
676 "",
677 "SYSTIN",
678 "CPUTIN",
679 "AUXTIN0",
680 "AUXTIN1",
681 "AUXTIN2",
682 "AUXTIN3",
683 "",
684 "SMBUSMASTER 0",
685 "SMBUSMASTER 1",
686 "SMBUSMASTER 2",
687 "SMBUSMASTER 3",
688 "SMBUSMASTER 4",
689 "SMBUSMASTER 5",
690 "SMBUSMASTER 6",
691 "SMBUSMASTER 7",
692 "PECI Agent 0",
693 "PECI Agent 1",
694 "PCH_CHIP_CPU_MAX_TEMP",
695 "PCH_CHIP_TEMP",
696 "PCH_CPU_TEMP",
697 "PCH_MCH_TEMP",
698 "PCH_DIM0_TEMP",
699 "PCH_DIM1_TEMP",
700 "PCH_DIM2_TEMP",
701 "PCH_DIM3_TEMP",
702 "BYTE_TEMP0",
703 "BYTE_TEMP1",
704 "PECI Agent 0 Calibration",
705 "PECI Agent 1 Calibration",
706 "",
707 "Virtual_TEMP"
708};
709
710#define NCT6795_TEMP_MASK 0xbfffff7e
711
Guenter Roeck6c009502012-07-01 08:23:15 -0700712/* NCT6102D/NCT6106D specific data */
713
714#define NCT6106_REG_VBAT 0x318
715#define NCT6106_REG_DIODE 0x319
716#define NCT6106_DIODE_MASK 0x01
717
718static const u16 NCT6106_REG_IN_MAX[] = {
719 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
720static const u16 NCT6106_REG_IN_MIN[] = {
721 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
722static const u16 NCT6106_REG_IN[] = {
723 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
724
725static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800726static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700727static const u16 NCT6106_REG_TEMP_HYST[] = {
728 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
729static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700730 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
731static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
732 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
733static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
734 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700735static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
736static const u16 NCT6106_REG_TEMP_CONFIG[] = {
737 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
738
739static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
740static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
741static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
742static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
743
744static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
745static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
746static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
747static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
748static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
749static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
750static const u16 NCT6106_REG_TEMP_SOURCE[] = {
751 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
752
753static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
754static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
755 0x11b, 0x12b, 0x13b };
756
757static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
758#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
759static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
760
761static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
762static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
763static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
764static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
765static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
766static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
767
768static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
769
770static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
771static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
772static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
773static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
774static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
775static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
776
777static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
778static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
779
780static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
781 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
782
783static const s8 NCT6106_ALARM_BITS[] = {
784 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
785 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
786 -1, /* unused */
787 32, 33, 34, -1, -1, /* fan1..fan5 */
788 -1, -1, -1, /* unused */
789 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
790 48, -1 /* intrusion0, intrusion1 */
791};
792
Guenter Roeck30846992013-06-24 22:21:59 -0700793static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
794 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
795
796static const s8 NCT6106_BEEP_BITS[] = {
797 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
798 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
799 32, /* global beep enable */
800 24, 25, 26, 27, 28, /* fan1..fan5 */
801 -1, -1, -1, /* unused */
802 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
803 34, -1 /* intrusion0, intrusion1 */
804};
805
Guenter Roeckcc66b302017-05-17 18:05:06 -0700806static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
807 [14] = 0x51,
808 [15] = 0x52,
809 [16] = 0x54,
810};
Guenter Roeck6c009502012-07-01 08:23:15 -0700811
Guenter Roeckcc66b302017-05-17 18:05:06 -0700812static const u16 NCT6106_REG_TEMP_CRIT[32] = {
813 [11] = 0x204,
814 [12] = 0x205,
815};
Guenter Roeck6c009502012-07-01 08:23:15 -0700816
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800817static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
818{
819 if (mode == 0 && pwm == 255)
820 return off;
821 return mode + 1;
822}
823
824static int pwm_enable_to_reg(enum pwm_enable mode)
825{
826 if (mode == off)
827 return 0;
828 return mode - 1;
829}
830
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700831/*
832 * Conversions
833 */
834
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800835/* 1 is DC mode, output in ms */
836static unsigned int step_time_from_reg(u8 reg, u8 mode)
837{
838 return mode ? 400 * reg : 100 * reg;
839}
840
841static u8 step_time_to_reg(unsigned int msec, u8 mode)
842{
843 return clamp_val((mode ? (msec + 200) / 400 :
844 (msec + 50) / 100), 1, 255);
845}
846
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800847static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
848{
849 if (reg == 0 || reg == 255)
850 return 0;
851 return 1350000U / (reg << divreg);
852}
853
854static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
855{
856 if ((reg & 0xff1f) == 0xff1f)
857 return 0;
858
859 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
860
861 if (reg == 0)
862 return 0;
863
864 return 1350000U / reg;
865}
866
867static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
868{
869 if (reg == 0 || reg == 0xffff)
870 return 0;
871
872 /*
873 * Even though the registers are 16 bit wide, the fan divisor
874 * still applies.
875 */
876 return 1350000U / (reg << divreg);
877}
878
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800879static u16 fan_to_reg(u32 fan, unsigned int divreg)
880{
881 if (!fan)
882 return 0;
883
884 return (1350000U / fan) >> divreg;
885}
886
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800887static inline unsigned int
888div_from_reg(u8 reg)
889{
Guenter Roeckd1bb21862017-05-17 18:40:10 -0700890 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800891}
892
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700893/*
894 * Some of the voltage inputs have internal scaling, the tables below
895 * contain 8 (the ADC LSB in mV) * scaling factor * 100
896 */
897static const u16 scale_in[15] = {
898 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
899 800, 800
900};
901
902static inline long in_from_reg(u8 reg, u8 nr)
903{
904 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
905}
906
907static inline u8 in_to_reg(u32 val, u8 nr)
908{
909 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
910}
911
912/*
913 * Data structures and manipulation thereof
914 */
915
916struct nct6775_data {
917 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700918 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700919 enum kinds kind;
920 const char *name;
921
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700922 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700923
Guenter Roeckb7a61352013-04-02 22:14:06 -0700924 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
925 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800926 */
927 u8 temp_src[NUM_TEMP];
928 u16 reg_temp_config[NUM_TEMP];
929 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -0700930 u32 temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800931
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700932 u16 REG_CONFIG;
933 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800934 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700935 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700936
937 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700938 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700939
940 const u16 *REG_VIN;
941 const u16 *REG_IN_MINMAX[2];
942
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800943 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800944 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800945 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800946 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800947 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700948 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800949 const u16 *REG_FAN_TIME[3];
950
951 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800952
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800953 const u8 *REG_PWM_MODE;
954 const u8 *PWM_MODE_MASK;
955
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800956 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
957 * [3]=pwm_max, [4]=pwm_step,
958 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800959 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800960 const u16 *REG_PWM_READ;
961
Guenter Roeck6c009502012-07-01 08:23:15 -0700962 const u16 *REG_CRITICAL_PWM_ENABLE;
963 u8 CRITICAL_PWM_ENABLE_MASK;
964 const u16 *REG_CRITICAL_PWM;
965
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800966 const u16 *REG_AUTO_TEMP;
967 const u16 *REG_AUTO_PWM;
968
969 const u16 *REG_CRITICAL_TEMP;
970 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
971
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800972 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800973 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800974 const u16 *REG_WEIGHT_TEMP_SEL;
975 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
976
Guenter Roeckaa136e52012-12-04 03:26:05 -0800977 const u16 *REG_TEMP_OFFSET;
978
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700979 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700980 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700981
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800982 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
983 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
984
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700985 struct mutex update_lock;
986 bool valid; /* true if following fields are valid */
987 unsigned long last_updated; /* In jiffies */
988
989 /* Register values */
990 u8 bank; /* current register bank */
991 u8 in_num; /* number of in inputs we have */
992 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700993 unsigned int rpm[NUM_FAN];
994 u16 fan_min[NUM_FAN];
995 u8 fan_pulses[NUM_FAN];
996 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800997 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800998 u8 has_fan; /* some fan inputs can be disabled */
999 u8 has_fan_min; /* some fans don't have min register */
1000 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001001
Guenter Roeck6c009502012-07-01 08:23:15 -07001002 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001003 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001004 u8 temp_fixed_num; /* 3 or 6 */
1005 u8 temp_type[NUM_TEMP_FIXED];
1006 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001007 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1008 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001009 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001010 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001011
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001012 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -07001013 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
1014 * 0->PWM variable duty cycle
1015 */
1016 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001017 /* 0->off
1018 * 1->manual
1019 * 2->thermal cruise mode (also called SmartFan I)
1020 * 3->fan speed cruise mode
1021 * 4->SmartFan III
1022 * 5->enhanced variable thermal cruise (SmartFan IV)
1023 */
David Bartley578ab5f2013-06-24 22:28:28 -07001024 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1025 * [3]=pwm_max, [4]=pwm_step,
1026 * [5]=weight_duty_step, [6]=weight_duty_base
1027 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001028
David Bartley578ab5f2013-06-24 22:28:28 -07001029 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001030 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001031 u32 target_speed[NUM_FAN];
1032 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001033 u8 speed_tolerance_limit;
1034
David Bartley578ab5f2013-06-24 22:28:28 -07001035 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001036 u8 tolerance_mask;
1037
David Bartley578ab5f2013-06-24 22:28:28 -07001038 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001039
1040 /* Automatic fan speed control registers */
1041 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001042 u8 auto_pwm[NUM_FAN][7];
1043 u8 auto_temp[NUM_FAN][7];
1044 u8 pwm_temp_sel[NUM_FAN];
1045 u8 pwm_weight_temp_sel[NUM_FAN];
1046 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1047 * 2->temp_base
1048 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001049
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001050 u8 vid;
1051 u8 vrm;
1052
Guenter Roeckf73cf632013-03-18 09:22:50 -07001053 bool have_vid;
1054
Guenter Roeckaa136e52012-12-04 03:26:05 -08001055 u16 have_temp;
1056 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001057 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001058
Guenter Roeck84d19d92012-12-04 08:01:39 -08001059 /* Remember extra register values over suspend/resume */
1060 u8 vbat;
1061 u8 fandiv1;
1062 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001063 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001064};
1065
1066struct nct6775_sio_data {
1067 int sioreg;
1068 enum kinds kind;
1069};
1070
Guenter Roeckf73cf632013-03-18 09:22:50 -07001071struct sensor_device_template {
1072 struct device_attribute dev_attr;
1073 union {
1074 struct {
1075 u8 nr;
1076 u8 index;
1077 } s;
1078 int index;
1079 } u;
1080 bool s2; /* true if both index and nr are used */
1081};
1082
1083struct sensor_device_attr_u {
1084 union {
1085 struct sensor_device_attribute a1;
1086 struct sensor_device_attribute_2 a2;
1087 } u;
1088 char name[32];
1089};
1090
1091#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1092 .attr = {.name = _template, .mode = _mode }, \
1093 .show = _show, \
1094 .store = _store, \
1095}
1096
1097#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1098 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1099 .u.index = _index, \
1100 .s2 = false }
1101
1102#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1103 _nr, _index) \
1104 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1105 .u.s.index = _index, \
1106 .u.s.nr = _nr, \
1107 .s2 = true }
1108
1109#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1110static struct sensor_device_template sensor_dev_template_##_name \
1111 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1112 _index)
1113
1114#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1115 _nr, _index) \
1116static struct sensor_device_template sensor_dev_template_##_name \
1117 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1118 _nr, _index)
1119
1120struct sensor_template_group {
1121 struct sensor_device_template **templates;
1122 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1123 int base;
1124};
1125
1126static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001127nct6775_create_attr_group(struct device *dev,
1128 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001129 int repeat)
1130{
1131 struct attribute_group *group;
1132 struct sensor_device_attr_u *su;
1133 struct sensor_device_attribute *a;
1134 struct sensor_device_attribute_2 *a2;
1135 struct attribute **attrs;
1136 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001137 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001138
1139 if (repeat <= 0)
1140 return ERR_PTR(-EINVAL);
1141
1142 t = tg->templates;
1143 for (count = 0; *t; t++, count++)
1144 ;
1145
1146 if (count == 0)
1147 return ERR_PTR(-EINVAL);
1148
1149 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1150 if (group == NULL)
1151 return ERR_PTR(-ENOMEM);
1152
1153 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1154 GFP_KERNEL);
1155 if (attrs == NULL)
1156 return ERR_PTR(-ENOMEM);
1157
1158 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1159 GFP_KERNEL);
1160 if (su == NULL)
1161 return ERR_PTR(-ENOMEM);
1162
1163 group->attrs = attrs;
1164 group->is_visible = tg->is_visible;
1165
1166 for (i = 0; i < repeat; i++) {
1167 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001168 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001169 snprintf(su->name, sizeof(su->name),
1170 (*t)->dev_attr.attr.name, tg->base + i);
1171 if ((*t)->s2) {
1172 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001173 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001174 a2->dev_attr.attr.name = su->name;
1175 a2->nr = (*t)->u.s.nr + i;
1176 a2->index = (*t)->u.s.index;
1177 a2->dev_attr.attr.mode =
1178 (*t)->dev_attr.attr.mode;
1179 a2->dev_attr.show = (*t)->dev_attr.show;
1180 a2->dev_attr.store = (*t)->dev_attr.store;
1181 *attrs = &a2->dev_attr.attr;
1182 } else {
1183 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001184 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001185 a->dev_attr.attr.name = su->name;
1186 a->index = (*t)->u.index + i;
1187 a->dev_attr.attr.mode =
1188 (*t)->dev_attr.attr.mode;
1189 a->dev_attr.show = (*t)->dev_attr.show;
1190 a->dev_attr.store = (*t)->dev_attr.store;
1191 *attrs = &a->dev_attr.attr;
1192 }
1193 attrs++;
1194 su++;
1195 t++;
1196 }
1197 }
1198
Guenter Roeckf73cf632013-03-18 09:22:50 -07001199 return group;
1200}
1201
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001202static bool is_word_sized(struct nct6775_data *data, u16 reg)
1203{
1204 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001205 case nct6106:
1206 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1207 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1208 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001209 case nct6775:
1210 return (((reg & 0xff00) == 0x100 ||
1211 (reg & 0xff00) == 0x200) &&
1212 ((reg & 0x00ff) == 0x50 ||
1213 (reg & 0x00ff) == 0x53 ||
1214 (reg & 0x00ff) == 0x55)) ||
1215 (reg & 0xfff0) == 0x630 ||
1216 reg == 0x640 || reg == 0x642 ||
1217 reg == 0x662 ||
1218 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1219 reg == 0x73 || reg == 0x75 || reg == 0x77;
1220 case nct6776:
1221 return (((reg & 0xff00) == 0x100 ||
1222 (reg & 0xff00) == 0x200) &&
1223 ((reg & 0x00ff) == 0x50 ||
1224 (reg & 0x00ff) == 0x53 ||
1225 (reg & 0x00ff) == 0x55)) ||
1226 (reg & 0xfff0) == 0x630 ||
1227 reg == 0x402 ||
1228 reg == 0x640 || reg == 0x642 ||
1229 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1230 reg == 0x73 || reg == 0x75 || reg == 0x77;
1231 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001232 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001233 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001234 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001235 case nct6795:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001236 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001237 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001238 reg == 0x402 ||
1239 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001240 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001241 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001242 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001243 }
1244 return false;
1245}
1246
1247/*
1248 * On older chips, only registers 0x50-0x5f are banked.
1249 * On more recent chips, all registers are banked.
1250 * Assume that is the case and set the bank number for each access.
1251 * Cache the bank number so it only needs to be set if it changes.
1252 */
1253static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1254{
1255 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001256
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001257 if (data->bank != bank) {
1258 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1259 outb_p(bank, data->addr + DATA_REG_OFFSET);
1260 data->bank = bank;
1261 }
1262}
1263
1264static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1265{
1266 int res, word_sized = is_word_sized(data, reg);
1267
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001268 nct6775_set_bank(data, reg);
1269 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1270 res = inb_p(data->addr + DATA_REG_OFFSET);
1271 if (word_sized) {
1272 outb_p((reg & 0xff) + 1,
1273 data->addr + ADDR_REG_OFFSET);
1274 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1275 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001276 return res;
1277}
1278
1279static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1280{
1281 int word_sized = is_word_sized(data, reg);
1282
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001283 nct6775_set_bank(data, reg);
1284 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1285 if (word_sized) {
1286 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1287 outb_p((reg & 0xff) + 1,
1288 data->addr + ADDR_REG_OFFSET);
1289 }
1290 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001291 return 0;
1292}
1293
Guenter Roeckaa136e52012-12-04 03:26:05 -08001294/* We left-align 8-bit temperature values to make the code simpler */
1295static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1296{
1297 u16 res;
1298
1299 res = nct6775_read_value(data, reg);
1300 if (!is_word_sized(data, reg))
1301 res <<= 8;
1302
1303 return res;
1304}
1305
1306static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1307{
1308 if (!is_word_sized(data, reg))
1309 value >>= 8;
1310 return nct6775_write_value(data, reg, value);
1311}
1312
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001313/* This function assumes that the caller holds data->update_lock */
1314static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1315{
1316 u8 reg;
1317
1318 switch (nr) {
1319 case 0:
1320 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1321 | (data->fan_div[0] & 0x7);
1322 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1323 break;
1324 case 1:
1325 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1326 | ((data->fan_div[1] << 4) & 0x70);
1327 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1328 break;
1329 case 2:
1330 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1331 | (data->fan_div[2] & 0x7);
1332 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1333 break;
1334 case 3:
1335 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1336 | ((data->fan_div[3] << 4) & 0x70);
1337 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1338 break;
1339 }
1340}
1341
1342static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1343{
1344 if (data->kind == nct6775)
1345 nct6775_write_fan_div(data, nr);
1346}
1347
1348static void nct6775_update_fan_div(struct nct6775_data *data)
1349{
1350 u8 i;
1351
1352 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1353 data->fan_div[0] = i & 0x7;
1354 data->fan_div[1] = (i & 0x70) >> 4;
1355 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1356 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001357 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001358 data->fan_div[3] = (i & 0x70) >> 4;
1359}
1360
1361static void nct6775_update_fan_div_common(struct nct6775_data *data)
1362{
1363 if (data->kind == nct6775)
1364 nct6775_update_fan_div(data);
1365}
1366
1367static void nct6775_init_fan_div(struct nct6775_data *data)
1368{
1369 int i;
1370
1371 nct6775_update_fan_div_common(data);
1372 /*
1373 * For all fans, start with highest divider value if the divider
1374 * register is not initialized. This ensures that we get a
1375 * reading from the fan count register, even if it is not optimal.
1376 * We'll compute a better divider later on.
1377 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001378 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001379 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001380 continue;
1381 if (data->fan_div[i] == 0) {
1382 data->fan_div[i] = 7;
1383 nct6775_write_fan_div_common(data, i);
1384 }
1385 }
1386}
1387
1388static void nct6775_init_fan_common(struct device *dev,
1389 struct nct6775_data *data)
1390{
1391 int i;
1392 u8 reg;
1393
1394 if (data->has_fan_div)
1395 nct6775_init_fan_div(data);
1396
1397 /*
1398 * If fan_min is not set (0), set it to 0xff to disable it. This
1399 * prevents the unnecessary warning when fanX_min is reported as 0.
1400 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001401 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001402 if (data->has_fan_min & BIT(i)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001403 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1404 if (!reg)
1405 nct6775_write_value(data, data->REG_FAN_MIN[i],
1406 data->has_fan_div ? 0xff
1407 : 0xff1f);
1408 }
1409 }
1410}
1411
1412static void nct6775_select_fan_div(struct device *dev,
1413 struct nct6775_data *data, int nr, u16 reg)
1414{
1415 u8 fan_div = data->fan_div[nr];
1416 u16 fan_min;
1417
1418 if (!data->has_fan_div)
1419 return;
1420
1421 /*
1422 * If we failed to measure the fan speed, or the reported value is not
1423 * in the optimal range, and the clock divider can be modified,
1424 * let's try that for next time.
1425 */
1426 if (reg == 0x00 && fan_div < 0x07)
1427 fan_div++;
1428 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1429 fan_div--;
1430
1431 if (fan_div != data->fan_div[nr]) {
1432 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1433 nr + 1, div_from_reg(data->fan_div[nr]),
1434 div_from_reg(fan_div));
1435
1436 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001437 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001438 fan_min = data->fan_min[nr];
1439 if (fan_div > data->fan_div[nr]) {
1440 if (fan_min != 255 && fan_min > 1)
1441 fan_min >>= 1;
1442 } else {
1443 if (fan_min != 255) {
1444 fan_min <<= 1;
1445 if (fan_min > 254)
1446 fan_min = 254;
1447 }
1448 }
1449 if (fan_min != data->fan_min[nr]) {
1450 data->fan_min[nr] = fan_min;
1451 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1452 fan_min);
1453 }
1454 }
1455 data->fan_div[nr] = fan_div;
1456 nct6775_write_fan_div_common(data, nr);
1457 }
1458}
1459
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001460static void nct6775_update_pwm(struct device *dev)
1461{
1462 struct nct6775_data *data = dev_get_drvdata(dev);
1463 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001464 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001465 bool duty_is_dc;
1466
1467 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001468 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001469 continue;
1470
1471 duty_is_dc = data->REG_PWM_MODE[i] &&
1472 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1473 & data->PWM_MODE_MASK[i]);
1474 data->pwm_mode[i] = duty_is_dc;
1475
1476 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1477 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1478 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1479 data->pwm[j][i]
1480 = nct6775_read_value(data,
1481 data->REG_PWM[j][i]);
1482 }
1483 }
1484
1485 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1486 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001487
1488 if (!data->temp_tolerance[0][i] ||
1489 data->pwm_enable[i] != speed_cruise)
1490 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1491 if (!data->target_speed_tolerance[i] ||
1492 data->pwm_enable[i] == speed_cruise) {
1493 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001494
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001495 if (data->REG_TOLERANCE_H) {
1496 t |= (nct6775_read_value(data,
1497 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1498 }
1499 data->target_speed_tolerance[i] = t;
1500 }
1501
1502 data->temp_tolerance[1][i] =
1503 nct6775_read_value(data,
1504 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1505
1506 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1507 data->pwm_temp_sel[i] = reg & 0x1f;
1508 /* If fan can stop, report floor as 0 */
1509 if (reg & 0x80)
1510 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001511
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001512 if (!data->REG_WEIGHT_TEMP_SEL[i])
1513 continue;
1514
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001515 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1516 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1517 /* If weight is disabled, report weight source as 0 */
1518 if (j == 1 && !(reg & 0x80))
1519 data->pwm_weight_temp_sel[i] = 0;
1520
1521 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001522 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001523 data->weight_temp[j][i]
1524 = nct6775_read_value(data,
1525 data->REG_WEIGHT_TEMP[j][i]);
1526 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001527 }
1528}
1529
1530static void nct6775_update_pwm_limits(struct device *dev)
1531{
1532 struct nct6775_data *data = dev_get_drvdata(dev);
1533 int i, j;
1534 u8 reg;
1535 u16 reg_t;
1536
1537 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001538 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001539 continue;
1540
Guenter Roeckc409fd42013-04-09 05:04:00 -07001541 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001542 data->fan_time[j][i] =
1543 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1544 }
1545
1546 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1547 /* Update only in matching mode or if never updated */
1548 if (!data->target_temp[i] ||
1549 data->pwm_enable[i] == thermal_cruise)
1550 data->target_temp[i] = reg_t & data->target_temp_mask;
1551 if (!data->target_speed[i] ||
1552 data->pwm_enable[i] == speed_cruise) {
1553 if (data->REG_TOLERANCE_H) {
1554 reg_t |= (nct6775_read_value(data,
1555 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1556 }
1557 data->target_speed[i] = reg_t;
1558 }
1559
1560 for (j = 0; j < data->auto_pwm_num; j++) {
1561 data->auto_pwm[i][j] =
1562 nct6775_read_value(data,
1563 NCT6775_AUTO_PWM(data, i, j));
1564 data->auto_temp[i][j] =
1565 nct6775_read_value(data,
1566 NCT6775_AUTO_TEMP(data, i, j));
1567 }
1568
1569 /* critical auto_pwm temperature data */
1570 data->auto_temp[i][data->auto_pwm_num] =
1571 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1572
1573 switch (data->kind) {
1574 case nct6775:
1575 reg = nct6775_read_value(data,
1576 NCT6775_REG_CRITICAL_ENAB[i]);
1577 data->auto_pwm[i][data->auto_pwm_num] =
1578 (reg & 0x02) ? 0xff : 0x00;
1579 break;
1580 case nct6776:
1581 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1582 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001583 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001584 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001585 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001586 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001587 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001588 case nct6795:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001589 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001590 data->REG_CRITICAL_PWM_ENABLE[i]);
1591 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1592 reg = nct6775_read_value(data,
1593 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001594 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001595 reg = 0xff;
1596 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001597 break;
1598 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001599 }
1600}
1601
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001602static struct nct6775_data *nct6775_update_device(struct device *dev)
1603{
1604 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001605 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001606
1607 mutex_lock(&data->update_lock);
1608
Guenter Roeck6445e662013-04-21 09:13:28 -07001609 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001610 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001611 /* Fan clock dividers */
1612 nct6775_update_fan_div_common(data);
1613
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001614 /* Measured voltages and limits */
1615 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001616 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001617 continue;
1618
1619 data->in[i][0] = nct6775_read_value(data,
1620 data->REG_VIN[i]);
1621 data->in[i][1] = nct6775_read_value(data,
1622 data->REG_IN_MINMAX[0][i]);
1623 data->in[i][2] = nct6775_read_value(data,
1624 data->REG_IN_MINMAX[1][i]);
1625 }
1626
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001627 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001628 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001629 u16 reg;
1630
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001631 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001632 continue;
1633
1634 reg = nct6775_read_value(data, data->REG_FAN[i]);
1635 data->rpm[i] = data->fan_from_reg(reg,
1636 data->fan_div[i]);
1637
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001638 if (data->has_fan_min & BIT(i))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001639 data->fan_min[i] = nct6775_read_value(data,
1640 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001641 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001642 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1643 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001644
1645 nct6775_select_fan_div(dev, data, i, reg);
1646 }
1647
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001648 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001649 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001650
Guenter Roeckaa136e52012-12-04 03:26:05 -08001651 /* Measured temperatures and limits */
1652 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001653 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001654 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001655 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001656 if (data->reg_temp[j][i])
1657 data->temp[j][i]
1658 = nct6775_read_temp(data,
1659 data->reg_temp[j][i]);
1660 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001661 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001662 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001663 continue;
1664 data->temp_offset[i]
1665 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1666 }
1667
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001668 data->alarms = 0;
1669 for (i = 0; i < NUM_REG_ALARM; i++) {
1670 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001671
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001672 if (!data->REG_ALARM[i])
1673 continue;
1674 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1675 data->alarms |= ((u64)alarm) << (i << 3);
1676 }
1677
Guenter Roeck30846992013-06-24 22:21:59 -07001678 data->beeps = 0;
1679 for (i = 0; i < NUM_REG_BEEP; i++) {
1680 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001681
Guenter Roeck30846992013-06-24 22:21:59 -07001682 if (!data->REG_BEEP[i])
1683 continue;
1684 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1685 data->beeps |= ((u64)beep) << (i << 3);
1686 }
1687
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001688 data->last_updated = jiffies;
1689 data->valid = true;
1690 }
1691
1692 mutex_unlock(&data->update_lock);
1693 return data;
1694}
1695
1696/*
1697 * Sysfs callback functions
1698 */
1699static ssize_t
1700show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1701{
1702 struct nct6775_data *data = nct6775_update_device(dev);
1703 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001704 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001705 int nr = sattr->nr;
1706
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001707 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1708}
1709
1710static ssize_t
1711store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1712 size_t count)
1713{
1714 struct nct6775_data *data = dev_get_drvdata(dev);
1715 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001716 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001717 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001718 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001719 int err;
1720
1721 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001722 if (err < 0)
1723 return err;
1724 mutex_lock(&data->update_lock);
1725 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001726 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001727 data->in[nr][index]);
1728 mutex_unlock(&data->update_lock);
1729 return count;
1730}
1731
1732static ssize_t
1733show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1734{
1735 struct nct6775_data *data = nct6775_update_device(dev);
1736 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1737 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001738
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001739 return sprintf(buf, "%u\n",
1740 (unsigned int)((data->alarms >> nr) & 0x01));
1741}
1742
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001743static int find_temp_source(struct nct6775_data *data, int index, int count)
1744{
1745 int source = data->temp_src[index];
1746 int nr;
1747
1748 for (nr = 0; nr < count; nr++) {
1749 int src;
1750
1751 src = nct6775_read_value(data,
1752 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1753 if (src == source)
1754 return nr;
1755 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001756 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001757}
1758
1759static ssize_t
1760show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1761{
1762 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1763 struct nct6775_data *data = nct6775_update_device(dev);
1764 unsigned int alarm = 0;
1765 int nr;
1766
1767 /*
1768 * For temperatures, there is no fixed mapping from registers to alarm
1769 * bits. Alarm bits are determined by the temperature source mapping.
1770 */
1771 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1772 if (nr >= 0) {
1773 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001774
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001775 alarm = (data->alarms >> bit) & 0x01;
1776 }
1777 return sprintf(buf, "%u\n", alarm);
1778}
1779
Guenter Roeck30846992013-06-24 22:21:59 -07001780static ssize_t
1781show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1782{
1783 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1784 struct nct6775_data *data = nct6775_update_device(dev);
1785 int nr = data->BEEP_BITS[sattr->index];
1786
1787 return sprintf(buf, "%u\n",
1788 (unsigned int)((data->beeps >> nr) & 0x01));
1789}
1790
1791static ssize_t
1792store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1793 size_t count)
1794{
1795 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1796 struct nct6775_data *data = dev_get_drvdata(dev);
1797 int nr = data->BEEP_BITS[sattr->index];
1798 int regindex = nr >> 3;
1799 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001800 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001801
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001802 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001803 if (err < 0)
1804 return err;
1805 if (val > 1)
1806 return -EINVAL;
1807
1808 mutex_lock(&data->update_lock);
1809 if (val)
1810 data->beeps |= (1ULL << nr);
1811 else
1812 data->beeps &= ~(1ULL << nr);
1813 nct6775_write_value(data, data->REG_BEEP[regindex],
1814 (data->beeps >> (regindex << 3)) & 0xff);
1815 mutex_unlock(&data->update_lock);
1816 return count;
1817}
1818
1819static ssize_t
1820show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1821{
1822 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1823 struct nct6775_data *data = nct6775_update_device(dev);
1824 unsigned int beep = 0;
1825 int nr;
1826
1827 /*
1828 * For temperatures, there is no fixed mapping from registers to beep
1829 * enable bits. Beep enable bits are determined by the temperature
1830 * source mapping.
1831 */
1832 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1833 if (nr >= 0) {
1834 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001835
Guenter Roeck30846992013-06-24 22:21:59 -07001836 beep = (data->beeps >> bit) & 0x01;
1837 }
1838 return sprintf(buf, "%u\n", beep);
1839}
1840
1841static ssize_t
1842store_temp_beep(struct device *dev, struct device_attribute *attr,
1843 const char *buf, size_t count)
1844{
1845 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1846 struct nct6775_data *data = dev_get_drvdata(dev);
1847 int nr, bit, regindex;
1848 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001849 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001850
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001851 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001852 if (err < 0)
1853 return err;
1854 if (val > 1)
1855 return -EINVAL;
1856
1857 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1858 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001859 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001860
1861 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1862 regindex = bit >> 3;
1863
1864 mutex_lock(&data->update_lock);
1865 if (val)
1866 data->beeps |= (1ULL << bit);
1867 else
1868 data->beeps &= ~(1ULL << bit);
1869 nct6775_write_value(data, data->REG_BEEP[regindex],
1870 (data->beeps >> (regindex << 3)) & 0xff);
1871 mutex_unlock(&data->update_lock);
1872
1873 return count;
1874}
1875
Guenter Roeckf73cf632013-03-18 09:22:50 -07001876static umode_t nct6775_in_is_visible(struct kobject *kobj,
1877 struct attribute *attr, int index)
1878{
1879 struct device *dev = container_of(kobj, struct device, kobj);
1880 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001881 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001882
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001883 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07001884 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001885
Guenter Roeckf73cf632013-03-18 09:22:50 -07001886 return attr->mode;
1887}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001888
Guenter Roeckf73cf632013-03-18 09:22:50 -07001889SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1890SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001891SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1892 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001893SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1894 store_in_reg, 0, 1);
1895SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1896 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001897
Guenter Roeckf73cf632013-03-18 09:22:50 -07001898/*
1899 * nct6775_in_is_visible uses the index into the following array
1900 * to determine if attributes should be created or not.
1901 * Any change in order or content must be matched.
1902 */
1903static struct sensor_device_template *nct6775_attributes_in_template[] = {
1904 &sensor_dev_template_in_input,
1905 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001906 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001907 &sensor_dev_template_in_min,
1908 &sensor_dev_template_in_max,
1909 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001910};
1911
Julia Lawallc60fdf82015-12-12 17:36:39 +01001912static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001913 .templates = nct6775_attributes_in_template,
1914 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001915};
1916
1917static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001918show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1919{
1920 struct nct6775_data *data = nct6775_update_device(dev);
1921 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1922 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001923
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001924 return sprintf(buf, "%d\n", data->rpm[nr]);
1925}
1926
1927static ssize_t
1928show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1929{
1930 struct nct6775_data *data = nct6775_update_device(dev);
1931 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1932 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001933
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001934 return sprintf(buf, "%d\n",
1935 data->fan_from_reg_min(data->fan_min[nr],
1936 data->fan_div[nr]));
1937}
1938
1939static ssize_t
1940show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1941{
1942 struct nct6775_data *data = nct6775_update_device(dev);
1943 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1944 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001945
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001946 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1947}
1948
1949static ssize_t
1950store_fan_min(struct device *dev, struct device_attribute *attr,
1951 const char *buf, size_t count)
1952{
1953 struct nct6775_data *data = dev_get_drvdata(dev);
1954 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1955 int nr = sattr->index;
1956 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001957 unsigned int reg;
1958 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001959 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001960
1961 err = kstrtoul(buf, 10, &val);
1962 if (err < 0)
1963 return err;
1964
1965 mutex_lock(&data->update_lock);
1966 if (!data->has_fan_div) {
1967 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1968 if (!val) {
1969 val = 0xff1f;
1970 } else {
1971 if (val > 1350000U)
1972 val = 135000U;
1973 val = 1350000U / val;
1974 val = (val & 0x1f) | ((val << 3) & 0xff00);
1975 }
1976 data->fan_min[nr] = val;
1977 goto write_min; /* Leave fan divider alone */
1978 }
1979 if (!val) {
1980 /* No min limit, alarm disabled */
1981 data->fan_min[nr] = 255;
1982 new_div = data->fan_div[nr]; /* No change */
1983 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1984 goto write_div;
1985 }
1986 reg = 1350000U / val;
1987 if (reg >= 128 * 255) {
1988 /*
1989 * Speed below this value cannot possibly be represented,
1990 * even with the highest divider (128)
1991 */
1992 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001993 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001994 dev_warn(dev,
1995 "fan%u low limit %lu below minimum %u, set to minimum\n",
1996 nr + 1, val, data->fan_from_reg_min(254, 7));
1997 } else if (!reg) {
1998 /*
1999 * Speed above this value cannot possibly be represented,
2000 * even with the lowest divider (1)
2001 */
2002 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002003 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002004 dev_warn(dev,
2005 "fan%u low limit %lu above maximum %u, set to maximum\n",
2006 nr + 1, val, data->fan_from_reg_min(1, 0));
2007 } else {
2008 /*
2009 * Automatically pick the best divider, i.e. the one such
2010 * that the min limit will correspond to a register value
2011 * in the 96..192 range
2012 */
2013 new_div = 0;
2014 while (reg > 192 && new_div < 7) {
2015 reg >>= 1;
2016 new_div++;
2017 }
2018 data->fan_min[nr] = reg;
2019 }
2020
2021write_div:
2022 /*
2023 * Write both the fan clock divider (if it changed) and the new
2024 * fan min (unconditionally)
2025 */
2026 if (new_div != data->fan_div[nr]) {
2027 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2028 nr + 1, div_from_reg(data->fan_div[nr]),
2029 div_from_reg(new_div));
2030 data->fan_div[nr] = new_div;
2031 nct6775_write_fan_div_common(data, nr);
2032 /* Give the chip time to sample a new speed value */
2033 data->last_updated = jiffies;
2034 }
2035
2036write_min:
2037 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
2038 mutex_unlock(&data->update_lock);
2039
2040 return count;
2041}
2042
Guenter Roeck5c25d952012-12-11 07:29:06 -08002043static ssize_t
2044show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2045{
2046 struct nct6775_data *data = nct6775_update_device(dev);
2047 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2048 int p = data->fan_pulses[sattr->index];
2049
2050 return sprintf(buf, "%d\n", p ? : 4);
2051}
2052
2053static ssize_t
2054store_fan_pulses(struct device *dev, struct device_attribute *attr,
2055 const char *buf, size_t count)
2056{
2057 struct nct6775_data *data = dev_get_drvdata(dev);
2058 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2059 int nr = sattr->index;
2060 unsigned long val;
2061 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002062 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002063
2064 err = kstrtoul(buf, 10, &val);
2065 if (err < 0)
2066 return err;
2067
2068 if (val > 4)
2069 return -EINVAL;
2070
2071 mutex_lock(&data->update_lock);
2072 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07002073 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
2074 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2075 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
2076 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002077 mutex_unlock(&data->update_lock);
2078
2079 return count;
2080}
2081
Guenter Roeckf73cf632013-03-18 09:22:50 -07002082static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2083 struct attribute *attr, int index)
2084{
2085 struct device *dev = container_of(kobj, struct device, kobj);
2086 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002087 int fan = index / 6; /* fan index */
2088 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002089
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002090 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002091 return 0;
2092
2093 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2094 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002095 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002096 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002097 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002098 return 0;
2099 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002100 return 0;
2101
2102 return attr->mode;
2103}
2104
2105SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2106SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2107 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002108SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2109 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002110SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2111 store_fan_pulses, 0);
2112SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2113 store_fan_min, 0);
2114SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2115
2116/*
2117 * nct6775_fan_is_visible uses the index into the following array
2118 * to determine if attributes should be created or not.
2119 * Any change in order or content must be matched.
2120 */
2121static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2122 &sensor_dev_template_fan_input,
2123 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002124 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002125 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002126 &sensor_dev_template_fan_min, /* 4 */
2127 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002128 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002129};
2130
Julia Lawallc60fdf82015-12-12 17:36:39 +01002131static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002132 .templates = nct6775_attributes_fan_template,
2133 .is_visible = nct6775_fan_is_visible,
2134 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002135};
2136
2137static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002138show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2139{
2140 struct nct6775_data *data = nct6775_update_device(dev);
2141 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2142 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002143
Guenter Roeckaa136e52012-12-04 03:26:05 -08002144 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2145}
2146
2147static ssize_t
2148show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2149{
2150 struct nct6775_data *data = nct6775_update_device(dev);
2151 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2152 int nr = sattr->nr;
2153 int index = sattr->index;
2154
2155 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2156}
2157
2158static ssize_t
2159store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2160 size_t count)
2161{
2162 struct nct6775_data *data = dev_get_drvdata(dev);
2163 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2164 int nr = sattr->nr;
2165 int index = sattr->index;
2166 int err;
2167 long val;
2168
2169 err = kstrtol(buf, 10, &val);
2170 if (err < 0)
2171 return err;
2172
2173 mutex_lock(&data->update_lock);
2174 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2175 nct6775_write_temp(data, data->reg_temp[index][nr],
2176 data->temp[index][nr]);
2177 mutex_unlock(&data->update_lock);
2178 return count;
2179}
2180
2181static ssize_t
2182show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2183{
2184 struct nct6775_data *data = nct6775_update_device(dev);
2185 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2186
2187 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2188}
2189
2190static ssize_t
2191store_temp_offset(struct device *dev, struct device_attribute *attr,
2192 const char *buf, size_t count)
2193{
2194 struct nct6775_data *data = dev_get_drvdata(dev);
2195 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2196 int nr = sattr->index;
2197 long val;
2198 int err;
2199
2200 err = kstrtol(buf, 10, &val);
2201 if (err < 0)
2202 return err;
2203
2204 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2205
2206 mutex_lock(&data->update_lock);
2207 data->temp_offset[nr] = val;
2208 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2209 mutex_unlock(&data->update_lock);
2210
2211 return count;
2212}
2213
2214static ssize_t
2215show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2216{
2217 struct nct6775_data *data = nct6775_update_device(dev);
2218 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2219 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002220
Guenter Roeckaa136e52012-12-04 03:26:05 -08002221 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2222}
2223
2224static ssize_t
2225store_temp_type(struct device *dev, struct device_attribute *attr,
2226 const char *buf, size_t count)
2227{
2228 struct nct6775_data *data = nct6775_update_device(dev);
2229 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2230 int nr = sattr->index;
2231 unsigned long val;
2232 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002233 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002234
2235 err = kstrtoul(buf, 10, &val);
2236 if (err < 0)
2237 return err;
2238
2239 if (val != 1 && val != 3 && val != 4)
2240 return -EINVAL;
2241
2242 mutex_lock(&data->update_lock);
2243
2244 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002245 vbit = 0x02 << nr;
2246 dbit = data->DIODE_MASK << nr;
2247 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2248 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002249 switch (val) {
2250 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002251 vbat |= vbit;
2252 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002253 break;
2254 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002255 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002256 break;
2257 case 4: /* thermistor */
2258 break;
2259 }
2260 nct6775_write_value(data, data->REG_VBAT, vbat);
2261 nct6775_write_value(data, data->REG_DIODE, diode);
2262
2263 mutex_unlock(&data->update_lock);
2264 return count;
2265}
2266
Guenter Roeckf73cf632013-03-18 09:22:50 -07002267static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2268 struct attribute *attr, int index)
2269{
2270 struct device *dev = container_of(kobj, struct device, kobj);
2271 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002272 int temp = index / 10; /* temp index */
2273 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002274
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002275 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002276 return 0;
2277
Guenter Roeckcc66b302017-05-17 18:05:06 -07002278 if (nr == 1 && !data->temp_label)
2279 return 0;
2280
Guenter Roeckf73cf632013-03-18 09:22:50 -07002281 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2282 return 0; /* alarm */
2283
Guenter Roeck30846992013-06-24 22:21:59 -07002284 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2285 return 0; /* beep */
2286
2287 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002288 return 0;
2289
Guenter Roeck30846992013-06-24 22:21:59 -07002290 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002291 return 0;
2292
Guenter Roeck30846992013-06-24 22:21:59 -07002293 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002294 return 0;
2295
Guenter Roeck30846992013-06-24 22:21:59 -07002296 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002297 return 0;
2298
2299 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002300 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002301 return 0;
2302
2303 return attr->mode;
2304}
2305
2306SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2307SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2308SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2309 store_temp, 0, 1);
2310SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2311 show_temp, store_temp, 0, 2);
2312SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2313 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002314SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2315 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002316SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2317 show_temp_offset, store_temp_offset, 0);
2318SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2319 store_temp_type, 0);
2320SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002321SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2322 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002323
2324/*
2325 * nct6775_temp_is_visible uses the index into the following array
2326 * to determine if attributes should be created or not.
2327 * Any change in order or content must be matched.
2328 */
2329static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2330 &sensor_dev_template_temp_input,
2331 &sensor_dev_template_temp_label,
2332 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002333 &sensor_dev_template_temp_beep, /* 3 */
2334 &sensor_dev_template_temp_max, /* 4 */
2335 &sensor_dev_template_temp_max_hyst, /* 5 */
2336 &sensor_dev_template_temp_crit, /* 6 */
2337 &sensor_dev_template_temp_lcrit, /* 7 */
2338 &sensor_dev_template_temp_offset, /* 8 */
2339 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002340 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002341};
2342
Julia Lawallc60fdf82015-12-12 17:36:39 +01002343static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002344 .templates = nct6775_attributes_temp_template,
2345 .is_visible = nct6775_temp_is_visible,
2346 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002347};
2348
Guenter Roeckaa136e52012-12-04 03:26:05 -08002349static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002350show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2351{
2352 struct nct6775_data *data = nct6775_update_device(dev);
2353 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2354
2355 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2356}
2357
2358static ssize_t
2359store_pwm_mode(struct device *dev, struct device_attribute *attr,
2360 const char *buf, size_t count)
2361{
2362 struct nct6775_data *data = dev_get_drvdata(dev);
2363 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2364 int nr = sattr->index;
2365 unsigned long val;
2366 int err;
2367 u8 reg;
2368
2369 err = kstrtoul(buf, 10, &val);
2370 if (err < 0)
2371 return err;
2372
2373 if (val > 1)
2374 return -EINVAL;
2375
2376 /* Setting DC mode is not supported for all chips/channels */
2377 if (data->REG_PWM_MODE[nr] == 0) {
2378 if (val)
2379 return -EINVAL;
2380 return count;
2381 }
2382
2383 mutex_lock(&data->update_lock);
2384 data->pwm_mode[nr] = val;
2385 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2386 reg &= ~data->PWM_MODE_MASK[nr];
2387 if (val)
2388 reg |= data->PWM_MODE_MASK[nr];
2389 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2390 mutex_unlock(&data->update_lock);
2391 return count;
2392}
2393
2394static ssize_t
2395show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2396{
2397 struct nct6775_data *data = nct6775_update_device(dev);
2398 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2399 int nr = sattr->nr;
2400 int index = sattr->index;
2401 int pwm;
2402
2403 /*
2404 * For automatic fan control modes, show current pwm readings.
2405 * Otherwise, show the configured value.
2406 */
2407 if (index == 0 && data->pwm_enable[nr] > manual)
2408 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2409 else
2410 pwm = data->pwm[index][nr];
2411
2412 return sprintf(buf, "%d\n", pwm);
2413}
2414
2415static ssize_t
2416store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2417 size_t count)
2418{
2419 struct nct6775_data *data = dev_get_drvdata(dev);
2420 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2421 int nr = sattr->nr;
2422 int index = sattr->index;
2423 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002424 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2425 int maxval[7]
2426 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002427 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002428 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002429
2430 err = kstrtoul(buf, 10, &val);
2431 if (err < 0)
2432 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002433 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002434
2435 mutex_lock(&data->update_lock);
2436 data->pwm[index][nr] = val;
2437 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002438 if (index == 2) { /* floor: disable if val == 0 */
2439 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2440 reg &= 0x7f;
2441 if (val)
2442 reg |= 0x80;
2443 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2444 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002445 mutex_unlock(&data->update_lock);
2446 return count;
2447}
2448
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002449/* Returns 0 if OK, -EINVAL otherwise */
2450static int check_trip_points(struct nct6775_data *data, int nr)
2451{
2452 int i;
2453
2454 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2455 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2456 return -EINVAL;
2457 }
2458 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2459 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2460 return -EINVAL;
2461 }
2462 /* validate critical temperature and pwm if enabled (pwm > 0) */
2463 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2464 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2465 data->auto_temp[nr][data->auto_pwm_num] ||
2466 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2467 data->auto_pwm[nr][data->auto_pwm_num])
2468 return -EINVAL;
2469 }
2470 return 0;
2471}
2472
2473static void pwm_update_registers(struct nct6775_data *data, int nr)
2474{
2475 u8 reg;
2476
2477 switch (data->pwm_enable[nr]) {
2478 case off:
2479 case manual:
2480 break;
2481 case speed_cruise:
2482 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2483 reg = (reg & ~data->tolerance_mask) |
2484 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2485 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2486 nct6775_write_value(data, data->REG_TARGET[nr],
2487 data->target_speed[nr] & 0xff);
2488 if (data->REG_TOLERANCE_H) {
2489 reg = (data->target_speed[nr] >> 8) & 0x0f;
2490 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2491 nct6775_write_value(data,
2492 data->REG_TOLERANCE_H[nr],
2493 reg);
2494 }
2495 break;
2496 case thermal_cruise:
2497 nct6775_write_value(data, data->REG_TARGET[nr],
2498 data->target_temp[nr]);
2499 /* intentional */
2500 default:
2501 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2502 reg = (reg & ~data->tolerance_mask) |
2503 data->temp_tolerance[0][nr];
2504 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2505 break;
2506 }
2507}
2508
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002509static ssize_t
2510show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2511{
2512 struct nct6775_data *data = nct6775_update_device(dev);
2513 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2514
2515 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2516}
2517
2518static ssize_t
2519store_pwm_enable(struct device *dev, struct device_attribute *attr,
2520 const char *buf, size_t count)
2521{
2522 struct nct6775_data *data = dev_get_drvdata(dev);
2523 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2524 int nr = sattr->index;
2525 unsigned long val;
2526 int err;
2527 u16 reg;
2528
2529 err = kstrtoul(buf, 10, &val);
2530 if (err < 0)
2531 return err;
2532
2533 if (val > sf4)
2534 return -EINVAL;
2535
2536 if (val == sf3 && data->kind != nct6775)
2537 return -EINVAL;
2538
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002539 if (val == sf4 && check_trip_points(data, nr)) {
2540 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2541 dev_err(dev, "Adjust trip points and try again\n");
2542 return -EINVAL;
2543 }
2544
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002545 mutex_lock(&data->update_lock);
2546 data->pwm_enable[nr] = val;
2547 if (val == off) {
2548 /*
2549 * turn off pwm control: select manual mode, set pwm to maximum
2550 */
2551 data->pwm[0][nr] = 255;
2552 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2553 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002554 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002555 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2556 reg &= 0x0f;
2557 reg |= pwm_enable_to_reg(val) << 4;
2558 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2559 mutex_unlock(&data->update_lock);
2560 return count;
2561}
2562
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002563static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002564show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002565{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002566 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002567
2568 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002569 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002570 continue;
2571 if (src == data->temp_src[i]) {
2572 sel = i + 1;
2573 break;
2574 }
2575 }
2576
2577 return sprintf(buf, "%d\n", sel);
2578}
2579
2580static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002581show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2582{
2583 struct nct6775_data *data = nct6775_update_device(dev);
2584 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2585 int index = sattr->index;
2586
2587 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2588}
2589
2590static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002591store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2592 const char *buf, size_t count)
2593{
2594 struct nct6775_data *data = nct6775_update_device(dev);
2595 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2596 int nr = sattr->index;
2597 unsigned long val;
2598 int err, reg, src;
2599
2600 err = kstrtoul(buf, 10, &val);
2601 if (err < 0)
2602 return err;
2603 if (val == 0 || val > NUM_TEMP)
2604 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002605 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002606 return -EINVAL;
2607
2608 mutex_lock(&data->update_lock);
2609 src = data->temp_src[val - 1];
2610 data->pwm_temp_sel[nr] = src;
2611 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2612 reg &= 0xe0;
2613 reg |= src;
2614 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2615 mutex_unlock(&data->update_lock);
2616
2617 return count;
2618}
2619
2620static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002621show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2622 char *buf)
2623{
2624 struct nct6775_data *data = nct6775_update_device(dev);
2625 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2626 int index = sattr->index;
2627
2628 return show_pwm_temp_sel_common(data, buf,
2629 data->pwm_weight_temp_sel[index]);
2630}
2631
2632static ssize_t
2633store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2634 const char *buf, size_t count)
2635{
2636 struct nct6775_data *data = nct6775_update_device(dev);
2637 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2638 int nr = sattr->index;
2639 unsigned long val;
2640 int err, reg, src;
2641
2642 err = kstrtoul(buf, 10, &val);
2643 if (err < 0)
2644 return err;
2645 if (val > NUM_TEMP)
2646 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002647 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002648 !data->temp_src[val - 1]))
2649 return -EINVAL;
2650
2651 mutex_lock(&data->update_lock);
2652 if (val) {
2653 src = data->temp_src[val - 1];
2654 data->pwm_weight_temp_sel[nr] = src;
2655 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2656 reg &= 0xe0;
2657 reg |= (src | 0x80);
2658 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2659 } else {
2660 data->pwm_weight_temp_sel[nr] = 0;
2661 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2662 reg &= 0x7f;
2663 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2664 }
2665 mutex_unlock(&data->update_lock);
2666
2667 return count;
2668}
2669
2670static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002671show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2672{
2673 struct nct6775_data *data = nct6775_update_device(dev);
2674 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2675
2676 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2677}
2678
2679static ssize_t
2680store_target_temp(struct device *dev, struct device_attribute *attr,
2681 const char *buf, size_t count)
2682{
2683 struct nct6775_data *data = dev_get_drvdata(dev);
2684 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2685 int nr = sattr->index;
2686 unsigned long val;
2687 int err;
2688
2689 err = kstrtoul(buf, 10, &val);
2690 if (err < 0)
2691 return err;
2692
2693 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2694 data->target_temp_mask);
2695
2696 mutex_lock(&data->update_lock);
2697 data->target_temp[nr] = val;
2698 pwm_update_registers(data, nr);
2699 mutex_unlock(&data->update_lock);
2700 return count;
2701}
2702
2703static ssize_t
2704show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2705{
2706 struct nct6775_data *data = nct6775_update_device(dev);
2707 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2708 int nr = sattr->index;
2709
2710 return sprintf(buf, "%d\n",
2711 fan_from_reg16(data->target_speed[nr],
2712 data->fan_div[nr]));
2713}
2714
2715static ssize_t
2716store_target_speed(struct device *dev, struct device_attribute *attr,
2717 const char *buf, size_t count)
2718{
2719 struct nct6775_data *data = dev_get_drvdata(dev);
2720 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2721 int nr = sattr->index;
2722 unsigned long val;
2723 int err;
2724 u16 speed;
2725
2726 err = kstrtoul(buf, 10, &val);
2727 if (err < 0)
2728 return err;
2729
2730 val = clamp_val(val, 0, 1350000U);
2731 speed = fan_to_reg(val, data->fan_div[nr]);
2732
2733 mutex_lock(&data->update_lock);
2734 data->target_speed[nr] = speed;
2735 pwm_update_registers(data, nr);
2736 mutex_unlock(&data->update_lock);
2737 return count;
2738}
2739
2740static ssize_t
2741show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2742 char *buf)
2743{
2744 struct nct6775_data *data = nct6775_update_device(dev);
2745 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2746 int nr = sattr->nr;
2747 int index = sattr->index;
2748
2749 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2750}
2751
2752static ssize_t
2753store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2754 const char *buf, size_t count)
2755{
2756 struct nct6775_data *data = dev_get_drvdata(dev);
2757 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2758 int nr = sattr->nr;
2759 int index = sattr->index;
2760 unsigned long val;
2761 int err;
2762
2763 err = kstrtoul(buf, 10, &val);
2764 if (err < 0)
2765 return err;
2766
2767 /* Limit tolerance as needed */
2768 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2769
2770 mutex_lock(&data->update_lock);
2771 data->temp_tolerance[index][nr] = val;
2772 if (index)
2773 pwm_update_registers(data, nr);
2774 else
2775 nct6775_write_value(data,
2776 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2777 val);
2778 mutex_unlock(&data->update_lock);
2779 return count;
2780}
2781
2782/*
2783 * Fan speed tolerance is a tricky beast, since the associated register is
2784 * a tick counter, but the value is reported and configured as rpm.
2785 * Compute resulting low and high rpm values and report the difference.
2786 */
2787static ssize_t
2788show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2789 char *buf)
2790{
2791 struct nct6775_data *data = nct6775_update_device(dev);
2792 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2793 int nr = sattr->index;
2794 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2795 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2796 int tolerance;
2797
2798 if (low <= 0)
2799 low = 1;
2800 if (high > 0xffff)
2801 high = 0xffff;
2802 if (high < low)
2803 high = low;
2804
2805 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2806 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2807
2808 return sprintf(buf, "%d\n", tolerance);
2809}
2810
2811static ssize_t
2812store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2813 const char *buf, size_t count)
2814{
2815 struct nct6775_data *data = dev_get_drvdata(dev);
2816 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2817 int nr = sattr->index;
2818 unsigned long val;
2819 int err;
2820 int low, high;
2821
2822 err = kstrtoul(buf, 10, &val);
2823 if (err < 0)
2824 return err;
2825
2826 high = fan_from_reg16(data->target_speed[nr],
2827 data->fan_div[nr]) + val;
2828 low = fan_from_reg16(data->target_speed[nr],
2829 data->fan_div[nr]) - val;
2830 if (low <= 0)
2831 low = 1;
2832 if (high < low)
2833 high = low;
2834
2835 val = (fan_to_reg(low, data->fan_div[nr]) -
2836 fan_to_reg(high, data->fan_div[nr])) / 2;
2837
2838 /* Limit tolerance as needed */
2839 val = clamp_val(val, 0, data->speed_tolerance_limit);
2840
2841 mutex_lock(&data->update_lock);
2842 data->target_speed_tolerance[nr] = val;
2843 pwm_update_registers(data, nr);
2844 mutex_unlock(&data->update_lock);
2845 return count;
2846}
2847
Guenter Roeckf73cf632013-03-18 09:22:50 -07002848SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2849SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2850 store_pwm_mode, 0);
2851SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2852 store_pwm_enable, 0);
2853SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2854 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2855SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2856 show_target_temp, store_target_temp, 0);
2857SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2858 show_target_speed, store_target_speed, 0);
2859SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2860 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002861
2862/* Smart Fan registers */
2863
2864static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002865show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2866{
2867 struct nct6775_data *data = nct6775_update_device(dev);
2868 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2869 int nr = sattr->nr;
2870 int index = sattr->index;
2871
2872 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2873}
2874
2875static ssize_t
2876store_weight_temp(struct device *dev, struct device_attribute *attr,
2877 const char *buf, size_t count)
2878{
2879 struct nct6775_data *data = dev_get_drvdata(dev);
2880 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2881 int nr = sattr->nr;
2882 int index = sattr->index;
2883 unsigned long val;
2884 int err;
2885
2886 err = kstrtoul(buf, 10, &val);
2887 if (err < 0)
2888 return err;
2889
2890 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2891
2892 mutex_lock(&data->update_lock);
2893 data->weight_temp[index][nr] = val;
2894 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2895 mutex_unlock(&data->update_lock);
2896 return count;
2897}
2898
Guenter Roeckf73cf632013-03-18 09:22:50 -07002899SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2900 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2901SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2902 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2903SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2904 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2905SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2906 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2907SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2908 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2909SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2910 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002911
2912static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002913show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2914{
2915 struct nct6775_data *data = nct6775_update_device(dev);
2916 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2917 int nr = sattr->nr;
2918 int index = sattr->index;
2919
2920 return sprintf(buf, "%d\n",
2921 step_time_from_reg(data->fan_time[index][nr],
2922 data->pwm_mode[nr]));
2923}
2924
2925static ssize_t
2926store_fan_time(struct device *dev, struct device_attribute *attr,
2927 const char *buf, size_t count)
2928{
2929 struct nct6775_data *data = dev_get_drvdata(dev);
2930 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2931 int nr = sattr->nr;
2932 int index = sattr->index;
2933 unsigned long val;
2934 int err;
2935
2936 err = kstrtoul(buf, 10, &val);
2937 if (err < 0)
2938 return err;
2939
2940 val = step_time_to_reg(val, data->pwm_mode[nr]);
2941 mutex_lock(&data->update_lock);
2942 data->fan_time[index][nr] = val;
2943 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2944 mutex_unlock(&data->update_lock);
2945 return count;
2946}
2947
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002948static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002949show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2950{
2951 struct nct6775_data *data = nct6775_update_device(dev);
2952 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2953
2954 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2955}
2956
2957static ssize_t
2958store_auto_pwm(struct device *dev, struct device_attribute *attr,
2959 const char *buf, size_t count)
2960{
2961 struct nct6775_data *data = dev_get_drvdata(dev);
2962 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2963 int nr = sattr->nr;
2964 int point = sattr->index;
2965 unsigned long val;
2966 int err;
2967 u8 reg;
2968
2969 err = kstrtoul(buf, 10, &val);
2970 if (err < 0)
2971 return err;
2972 if (val > 255)
2973 return -EINVAL;
2974
2975 if (point == data->auto_pwm_num) {
2976 if (data->kind != nct6775 && !val)
2977 return -EINVAL;
2978 if (data->kind != nct6779 && val)
2979 val = 0xff;
2980 }
2981
2982 mutex_lock(&data->update_lock);
2983 data->auto_pwm[nr][point] = val;
2984 if (point < data->auto_pwm_num) {
2985 nct6775_write_value(data,
2986 NCT6775_AUTO_PWM(data, nr, point),
2987 data->auto_pwm[nr][point]);
2988 } else {
2989 switch (data->kind) {
2990 case nct6775:
2991 /* disable if needed (pwm == 0) */
2992 reg = nct6775_read_value(data,
2993 NCT6775_REG_CRITICAL_ENAB[nr]);
2994 if (val)
2995 reg |= 0x02;
2996 else
2997 reg &= ~0x02;
2998 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2999 reg);
3000 break;
3001 case nct6776:
3002 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003003 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003004 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003005 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003006 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003007 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003008 case nct6795:
Guenter Roeck6c009502012-07-01 08:23:15 -07003009 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003010 val);
3011 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003012 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003013 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003014 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003015 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003016 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003017 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003018 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003019 reg);
3020 break;
3021 }
3022 }
3023 mutex_unlock(&data->update_lock);
3024 return count;
3025}
3026
3027static ssize_t
3028show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3029{
3030 struct nct6775_data *data = nct6775_update_device(dev);
3031 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3032 int nr = sattr->nr;
3033 int point = sattr->index;
3034
3035 /*
3036 * We don't know for sure if the temperature is signed or unsigned.
3037 * Assume it is unsigned.
3038 */
3039 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3040}
3041
3042static ssize_t
3043store_auto_temp(struct device *dev, struct device_attribute *attr,
3044 const char *buf, size_t count)
3045{
3046 struct nct6775_data *data = dev_get_drvdata(dev);
3047 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3048 int nr = sattr->nr;
3049 int point = sattr->index;
3050 unsigned long val;
3051 int err;
3052
3053 err = kstrtoul(buf, 10, &val);
3054 if (err)
3055 return err;
3056 if (val > 255000)
3057 return -EINVAL;
3058
3059 mutex_lock(&data->update_lock);
3060 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3061 if (point < data->auto_pwm_num) {
3062 nct6775_write_value(data,
3063 NCT6775_AUTO_TEMP(data, nr, point),
3064 data->auto_temp[nr][point]);
3065 } else {
3066 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
3067 data->auto_temp[nr][point]);
3068 }
3069 mutex_unlock(&data->update_lock);
3070 return count;
3071}
3072
Guenter Roeckf73cf632013-03-18 09:22:50 -07003073static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3074 struct attribute *attr, int index)
3075{
3076 struct device *dev = container_of(kobj, struct device, kobj);
3077 struct nct6775_data *data = dev_get_drvdata(dev);
3078 int pwm = index / 36; /* pwm index */
3079 int nr = index % 36; /* attribute index */
3080
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003081 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003082 return 0;
3083
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003084 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3085 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3086 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003087 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3088 return 0;
3089 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3090 return 0;
3091 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3092 return 0;
3093
3094 if (nr >= 22 && nr <= 35) { /* auto point */
3095 int api = (nr - 22) / 2; /* auto point index */
3096
3097 if (api > data->auto_pwm_num)
3098 return 0;
3099 }
3100 return attr->mode;
3101}
3102
3103SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3104 show_fan_time, store_fan_time, 0, 0);
3105SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3106 show_fan_time, store_fan_time, 0, 1);
3107SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3108 show_fan_time, store_fan_time, 0, 2);
3109SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3110 store_pwm, 0, 1);
3111SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3112 store_pwm, 0, 2);
3113SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3114 show_temp_tolerance, store_temp_tolerance, 0, 0);
3115SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3116 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3117 0, 1);
3118
3119SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3120 0, 3);
3121
3122SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3123 store_pwm, 0, 4);
3124
3125SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3126 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3127SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3128 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3129
3130SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3131 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3132SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3133 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3134
3135SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3136 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3137SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3138 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3139
3140SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3141 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3142SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3143 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3144
3145SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3146 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3147SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3148 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3149
3150SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3151 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3152SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3153 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3154
3155SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3156 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3157SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3158 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3159
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003160/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003161 * nct6775_pwm_is_visible uses the index into the following array
3162 * to determine if attributes should be created or not.
3163 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003164 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003165static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3166 &sensor_dev_template_pwm,
3167 &sensor_dev_template_pwm_mode,
3168 &sensor_dev_template_pwm_enable,
3169 &sensor_dev_template_pwm_temp_sel,
3170 &sensor_dev_template_pwm_temp_tolerance,
3171 &sensor_dev_template_pwm_crit_temp_tolerance,
3172 &sensor_dev_template_pwm_target_temp,
3173 &sensor_dev_template_fan_target,
3174 &sensor_dev_template_fan_tolerance,
3175 &sensor_dev_template_pwm_stop_time,
3176 &sensor_dev_template_pwm_step_up_time,
3177 &sensor_dev_template_pwm_step_down_time,
3178 &sensor_dev_template_pwm_start,
3179 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003180 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003181 &sensor_dev_template_pwm_weight_temp_step,
3182 &sensor_dev_template_pwm_weight_temp_step_tol,
3183 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003184 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003185 &sensor_dev_template_pwm_max, /* 19 */
3186 &sensor_dev_template_pwm_step, /* 20 */
3187 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3188 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3189 &sensor_dev_template_pwm_auto_point1_temp,
3190 &sensor_dev_template_pwm_auto_point2_pwm,
3191 &sensor_dev_template_pwm_auto_point2_temp,
3192 &sensor_dev_template_pwm_auto_point3_pwm,
3193 &sensor_dev_template_pwm_auto_point3_temp,
3194 &sensor_dev_template_pwm_auto_point4_pwm,
3195 &sensor_dev_template_pwm_auto_point4_temp,
3196 &sensor_dev_template_pwm_auto_point5_pwm,
3197 &sensor_dev_template_pwm_auto_point5_temp,
3198 &sensor_dev_template_pwm_auto_point6_pwm,
3199 &sensor_dev_template_pwm_auto_point6_temp,
3200 &sensor_dev_template_pwm_auto_point7_pwm,
3201 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003202
Guenter Roeckf73cf632013-03-18 09:22:50 -07003203 NULL
3204};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003205
Julia Lawallc60fdf82015-12-12 17:36:39 +01003206static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003207 .templates = nct6775_attributes_pwm_template,
3208 .is_visible = nct6775_pwm_is_visible,
3209 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003210};
3211
3212static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003213cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003214{
3215 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003216
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003217 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3218}
3219
Julia Lawall93d72ac2016-12-22 13:05:23 +01003220static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003221
Guenter Roecka6bd5872012-12-04 03:13:34 -08003222/* Case open detection */
3223
3224static ssize_t
3225clear_caseopen(struct device *dev, struct device_attribute *attr,
3226 const char *buf, size_t count)
3227{
3228 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003229 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3230 unsigned long val;
3231 u8 reg;
3232 int ret;
3233
3234 if (kstrtoul(buf, 10, &val) || val != 0)
3235 return -EINVAL;
3236
3237 mutex_lock(&data->update_lock);
3238
3239 /*
3240 * Use CR registers to clear caseopen status.
3241 * The CR registers are the same for all chips, and not all chips
3242 * support clearing the caseopen status through "regular" registers.
3243 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003244 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003245 if (ret) {
3246 count = ret;
3247 goto error;
3248 }
3249
Guenter Roeckdf612d52013-07-08 13:15:04 -07003250 superio_select(data->sioreg, NCT6775_LD_ACPI);
3251 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003252 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003253 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003254 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003255 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3256 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003257
3258 data->valid = false; /* Force cache refresh */
3259error:
3260 mutex_unlock(&data->update_lock);
3261 return count;
3262}
3263
Guenter Roeckf73cf632013-03-18 09:22:50 -07003264static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3265 clear_caseopen, INTRUSION_ALARM_BASE);
3266static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3267 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003268static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3269 store_beep, INTRUSION_ALARM_BASE);
3270static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3271 store_beep, INTRUSION_ALARM_BASE + 1);
3272static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3273 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003274
3275static umode_t nct6775_other_is_visible(struct kobject *kobj,
3276 struct attribute *attr, int index)
3277{
3278 struct device *dev = container_of(kobj, struct device, kobj);
3279 struct nct6775_data *data = dev_get_drvdata(dev);
3280
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003281 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003282 return 0;
3283
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003284 if (index == 1 || index == 2) {
3285 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003286 return 0;
3287 }
3288
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003289 if (index == 3 || index == 4) {
3290 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003291 return 0;
3292 }
3293
Guenter Roeckf73cf632013-03-18 09:22:50 -07003294 return attr->mode;
3295}
3296
3297/*
3298 * nct6775_other_is_visible uses the index into the following array
3299 * to determine if attributes should be created or not.
3300 * Any change in order or content must be matched.
3301 */
3302static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003303 &dev_attr_cpu0_vid.attr, /* 0 */
3304 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3305 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3306 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3307 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3308 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003309
3310 NULL
3311};
3312
3313static const struct attribute_group nct6775_group_other = {
3314 .attrs = nct6775_attributes_other,
3315 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003316};
3317
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003318static inline void nct6775_init_device(struct nct6775_data *data)
3319{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003320 int i;
3321 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003322
3323 /* Start monitoring if needed */
3324 if (data->REG_CONFIG) {
3325 tmp = nct6775_read_value(data, data->REG_CONFIG);
3326 if (!(tmp & 0x01))
3327 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3328 }
3329
Guenter Roeckaa136e52012-12-04 03:26:05 -08003330 /* Enable temperature sensors if needed */
3331 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003332 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003333 continue;
3334 if (!data->reg_temp_config[i])
3335 continue;
3336 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3337 if (tmp & 0x01)
3338 nct6775_write_value(data, data->reg_temp_config[i],
3339 tmp & 0xfe);
3340 }
3341
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003342 /* Enable VBAT monitoring if needed */
3343 tmp = nct6775_read_value(data, data->REG_VBAT);
3344 if (!(tmp & 0x01))
3345 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003346
3347 diode = nct6775_read_value(data, data->REG_DIODE);
3348
3349 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003350 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003351 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003352 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3353 data->temp_type[i]
3354 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003355 else /* thermistor */
3356 data->temp_type[i] = 4;
3357 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003358}
3359
Guenter Roeckf73cf632013-03-18 09:22:50 -07003360static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003361nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003362{
David Bartley578ab5f2013-06-24 22:28:28 -07003363 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3364 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003365 int sioreg = data->sioreg;
3366 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003367
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003368 /* Store SIO_REG_ENABLE for use during resume */
3369 superio_select(sioreg, NCT6775_LD_HWM);
3370 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3371
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003372 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3373 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003374 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003375
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003376 fan3pin = regval & BIT(6);
3377 pwm3pin = regval & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003378
3379 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003380 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003381 fan4min = false;
3382 fan5pin = false;
3383 fan6pin = false;
3384 pwm4pin = false;
3385 pwm5pin = false;
3386 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003387 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003388 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003389 const char *board_vendor, *board_name;
3390
3391 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3392 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3393
3394 if (board_name && board_vendor &&
3395 !strcmp(board_vendor, "ASRock")) {
3396 /*
3397 * Auxiliary fan monitoring is not enabled on ASRock
3398 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3399 * Observed with BIOS version 2.00.
3400 */
3401 if (!strcmp(board_name, "Z77 Pro4-M")) {
3402 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3403 data->sio_reg_enable |= 0xe0;
3404 superio_outb(sioreg, SIO_REG_ENABLE,
3405 data->sio_reg_enable);
3406 }
3407 }
3408 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003409
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003410 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003411 fan3pin = gpok;
3412 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003413 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003414
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003415 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003416 fan4pin = gpok;
3417 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003418 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003419
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003420 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003421 fan5pin = gpok;
3422 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003423 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003424
3425 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003426 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003427 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003428 pwm4pin = false;
3429 pwm5pin = false;
3430 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003431 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003432 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003433 fan3pin = !(regval & 0x80);
3434 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003435
3436 fan4pin = false;
3437 fan4min = false;
3438 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003439 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003440 pwm4pin = false;
3441 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003442 pwm6pin = false;
Guenter Roeck419220d2017-05-17 18:19:18 -07003443 } else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, or NCT6795D */
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003444 int regval_1b, regval_2a, regval_2f, regval_eb;
3445 bool dsw_en;
Guenter Roecke5c85222017-05-17 18:09:41 -07003446
Guenter Roeckdf612d52013-07-08 13:15:04 -07003447 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003448
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003449 fan3pin = !(regval & BIT(5));
3450 fan4pin = !(regval & BIT(6));
3451 fan5pin = !(regval & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003452
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003453 pwm3pin = !(regval & BIT(0));
3454 pwm4pin = !(regval & BIT(1));
3455 pwm5pin = !(regval & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003456
Guenter Roecke5c85222017-05-17 18:09:41 -07003457 regval = superio_inb(sioreg, 0x2d);
3458 switch (data->kind) {
3459 case nct6791:
3460 case nct6792:
3461 fan6pin = regval & BIT(1);
3462 pwm6pin = regval & BIT(0);
3463 break;
3464 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003465 case nct6795:
Guenter Roecke5c85222017-05-17 18:09:41 -07003466 regval_1b = superio_inb(sioreg, 0x1b);
3467 regval_2a = superio_inb(sioreg, 0x2a);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003468 regval_2f = superio_inb(sioreg, 0x2f);
3469 dsw_en = regval_2f & BIT(3);
David Bartley578ab5f2013-06-24 22:28:28 -07003470
Guenter Roecke5c85222017-05-17 18:09:41 -07003471 if (!pwm5pin)
3472 pwm5pin = regval & BIT(7);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003473
Guenter Roecke5c85222017-05-17 18:09:41 -07003474 if (!fan5pin)
3475 fan5pin = regval_1b & BIT(5);
3476
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003477 fan6pin = false;
3478 pwm6pin = false;
3479 if (!dsw_en) {
3480 fan6pin = regval & BIT(1);
3481 pwm6pin = regval & BIT(0);
3482 }
3483
Guenter Roecke5c85222017-05-17 18:09:41 -07003484 superio_select(sioreg, NCT6775_LD_12);
3485 regval_eb = superio_inb(sioreg, 0xeb);
3486 if (!fan5pin)
3487 fan5pin = regval_eb & BIT(5);
3488 if (!pwm5pin)
3489 pwm5pin = (regval_eb & BIT(4)) &&
3490 !(regval_2a & BIT(0));
3491 if (!fan6pin)
3492 fan6pin = regval_eb & BIT(3);
3493 if (!pwm6pin)
3494 pwm6pin = regval_eb & BIT(2);
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003495
3496 if (data->kind == nct6795) {
3497 int regval_ed = superio_inb(sioreg, 0xed);
3498
3499 if (!fan6pin)
3500 fan6pin = (regval_2a & BIT(4)) &&
3501 (!dsw_en ||
3502 (dsw_en && (regval_ed & BIT(4))));
3503 if (!pwm6pin)
3504 pwm6pin = (regval_2a & BIT(3)) &&
3505 (regval_ed & BIT(2));
3506 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003507 break;
3508 default: /* NCT6779D */
David Bartley578ab5f2013-06-24 22:28:28 -07003509 fan6pin = false;
3510 pwm6pin = false;
Guenter Roecke5c85222017-05-17 18:09:41 -07003511 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003512 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003513
3514 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003515 }
3516
David Bartley578ab5f2013-06-24 22:28:28 -07003517 /* fan 1 and 2 (0x03) are always present */
3518 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3519 (fan5pin << 4) | (fan6pin << 5);
3520 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08003521 (fan5pin << 4) | (fan6pin << 5);
David Bartley578ab5f2013-06-24 22:28:28 -07003522 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3523 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003524}
3525
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003526static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3527 int *available, int *mask)
3528{
3529 int i;
3530 u8 src;
3531
3532 for (i = 0; i < data->pwm_num && *available; i++) {
3533 int index;
3534
3535 if (!regp[i])
3536 continue;
3537 src = nct6775_read_value(data, regp[i]);
3538 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003539 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003540 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003541 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003542 continue;
3543
3544 index = __ffs(*available);
3545 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003546 *available &= ~BIT(index);
3547 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003548 }
3549}
3550
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003551static int nct6775_probe(struct platform_device *pdev)
3552{
3553 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003554 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003555 struct nct6775_data *data;
3556 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003557 int i, s, err = 0;
3558 int src, mask, available;
3559 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003560 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003561 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003562 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003563 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003564 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003565 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003566 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003567
3568 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3569 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3570 DRVNAME))
3571 return -EBUSY;
3572
3573 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3574 GFP_KERNEL);
3575 if (!data)
3576 return -ENOMEM;
3577
3578 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003579 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003580 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003581 mutex_init(&data->update_lock);
3582 data->name = nct6775_device_names[data->kind];
3583 data->bank = 0xff; /* Force initial bank selection */
3584 platform_set_drvdata(pdev, data);
3585
3586 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003587 case nct6106:
3588 data->in_num = 9;
3589 data->pwm_num = 3;
3590 data->auto_pwm_num = 4;
3591 data->temp_fixed_num = 3;
3592 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003593 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003594
3595 data->fan_from_reg = fan_from_reg13;
3596 data->fan_from_reg_min = fan_from_reg13;
3597
3598 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003599 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07003600
3601 data->REG_VBAT = NCT6106_REG_VBAT;
3602 data->REG_DIODE = NCT6106_REG_DIODE;
3603 data->DIODE_MASK = NCT6106_DIODE_MASK;
3604 data->REG_VIN = NCT6106_REG_IN;
3605 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3606 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3607 data->REG_TARGET = NCT6106_REG_TARGET;
3608 data->REG_FAN = NCT6106_REG_FAN;
3609 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3610 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3611 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3612 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3613 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3614 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3615 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3616 data->REG_PWM[0] = NCT6106_REG_PWM;
3617 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3618 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3619 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3620 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3621 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3622 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3623 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3624 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3625 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3626 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3627 data->REG_CRITICAL_TEMP_TOLERANCE
3628 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3629 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3630 data->CRITICAL_PWM_ENABLE_MASK
3631 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3632 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3633 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3634 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3635 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3636 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3637 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3638 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3639 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3640 data->REG_ALARM = NCT6106_REG_ALARM;
3641 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003642 data->REG_BEEP = NCT6106_REG_BEEP;
3643 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003644
3645 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003646 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003647 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003648 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003649 reg_temp_over = NCT6106_REG_TEMP_OVER;
3650 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3651 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3652 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3653 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003654 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3655 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003656
3657 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003658 case nct6775:
3659 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003660 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003661 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003662 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003663 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003664 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003665 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003666
3667 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003668 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003669
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003670 data->fan_from_reg = fan_from_reg16;
3671 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003672 data->target_temp_mask = 0x7f;
3673 data->tolerance_mask = 0x0f;
3674 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003675
Guenter Roeckaa136e52012-12-04 03:26:05 -08003676 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003677 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003678
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003679 data->REG_CONFIG = NCT6775_REG_CONFIG;
3680 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003681 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003682 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003683 data->REG_VIN = NCT6775_REG_IN;
3684 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3685 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003686 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003687 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003688 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003689 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003690 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003691 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003692 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3693 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3694 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003695 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003696 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3697 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3698 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3699 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003700 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003701 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3702 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3703 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003704 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3705 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3706 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3707 data->REG_CRITICAL_TEMP_TOLERANCE
3708 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003709 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3710 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003711 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003712 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3713 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3714 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3715 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003716 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003717 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003718
3719 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003720 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003721 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003722 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003723 reg_temp_over = NCT6775_REG_TEMP_OVER;
3724 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3725 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3726 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3727 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3728
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003729 break;
3730 case nct6776:
3731 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003732 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003733 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003734 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003735 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003736 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003737 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003738
3739 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003740 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003741
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003742 data->fan_from_reg = fan_from_reg13;
3743 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003744 data->target_temp_mask = 0xff;
3745 data->tolerance_mask = 0x07;
3746 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003747
Guenter Roeckaa136e52012-12-04 03:26:05 -08003748 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003749 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003750
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003751 data->REG_CONFIG = NCT6775_REG_CONFIG;
3752 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003753 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003754 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003755 data->REG_VIN = NCT6775_REG_IN;
3756 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3757 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003758 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003759 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003760 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003761 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003762 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003763 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003764 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003765 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3766 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003767 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003768 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003769 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3770 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003771 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3772 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003773 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3774 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3775 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003776 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3777 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3778 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3779 data->REG_CRITICAL_TEMP_TOLERANCE
3780 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003781 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3782 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003783 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003784 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3785 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3786 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3787 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003788 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003789 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003790
3791 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003792 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003793 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003794 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003795 reg_temp_over = NCT6775_REG_TEMP_OVER;
3796 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3797 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3798 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3799 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3800
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003801 break;
3802 case nct6779:
3803 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003804 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003805 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003806 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003807 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003808 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003809 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003810
3811 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003812 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003813
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003814 data->fan_from_reg = fan_from_reg13;
3815 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003816 data->target_temp_mask = 0xff;
3817 data->tolerance_mask = 0x07;
3818 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003819
Guenter Roeckaa136e52012-12-04 03:26:05 -08003820 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003821 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003822
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003823 data->REG_CONFIG = NCT6775_REG_CONFIG;
3824 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003825 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003826 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003827 data->REG_VIN = NCT6779_REG_IN;
3828 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3829 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003830 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003831 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003832 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003833 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003834 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003835 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003836 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003837 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3838 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003839 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003840 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003841 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3842 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003843 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3844 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003845 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3846 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3847 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003848 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3849 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3850 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3851 data->REG_CRITICAL_TEMP_TOLERANCE
3852 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003853 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3854 data->CRITICAL_PWM_ENABLE_MASK
3855 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3856 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003857 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3858 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003859 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003860 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3861 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3862 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3863 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003864 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003865 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003866
3867 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003868 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003869 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003870 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003871 reg_temp_over = NCT6779_REG_TEMP_OVER;
3872 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3873 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3874 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3875 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3876
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003877 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003878 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003879 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003880 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003881 case nct6795:
David Bartley578ab5f2013-06-24 22:28:28 -07003882 data->in_num = 15;
3883 data->pwm_num = 6;
3884 data->auto_pwm_num = 4;
3885 data->has_fan_div = false;
3886 data->temp_fixed_num = 6;
3887 data->num_temp_alarms = 2;
3888 data->num_temp_beeps = 2;
3889
3890 data->ALARM_BITS = NCT6791_ALARM_BITS;
3891 data->BEEP_BITS = NCT6779_BEEP_BITS;
3892
3893 data->fan_from_reg = fan_from_reg13;
3894 data->fan_from_reg_min = fan_from_reg13;
3895 data->target_temp_mask = 0xff;
3896 data->tolerance_mask = 0x07;
3897 data->speed_tolerance_limit = 63;
3898
Guenter Roeck50224f42015-10-30 07:52:39 -07003899 switch (data->kind) {
3900 default:
3901 case nct6791:
3902 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003903 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003904 break;
3905 case nct6792:
3906 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003907 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003908 break;
3909 case nct6793:
3910 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003911 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07003912 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003913 case nct6795:
3914 data->temp_label = nct6795_temp_label;
3915 data->temp_mask = NCT6795_TEMP_MASK;
3916 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07003917 }
David Bartley578ab5f2013-06-24 22:28:28 -07003918
3919 data->REG_CONFIG = NCT6775_REG_CONFIG;
3920 data->REG_VBAT = NCT6775_REG_VBAT;
3921 data->REG_DIODE = NCT6775_REG_DIODE;
3922 data->DIODE_MASK = NCT6775_DIODE_MASK;
3923 data->REG_VIN = NCT6779_REG_IN;
3924 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3925 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3926 data->REG_TARGET = NCT6775_REG_TARGET;
3927 data->REG_FAN = NCT6779_REG_FAN;
3928 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3929 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3930 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3931 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3932 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003933 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3934 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003935 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3936 data->REG_PWM[0] = NCT6775_REG_PWM;
3937 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3938 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003939 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3940 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003941 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3942 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3943 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3944 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3945 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3946 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3947 data->REG_CRITICAL_TEMP_TOLERANCE
3948 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3949 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3950 data->CRITICAL_PWM_ENABLE_MASK
3951 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3952 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3953 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3954 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3955 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003956 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3957 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3958 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3959 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003960 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003961 if (data->kind == nct6791)
3962 data->REG_BEEP = NCT6776_REG_BEEP;
3963 else
3964 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003965
3966 reg_temp = NCT6779_REG_TEMP;
3967 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003968 if (data->kind == nct6791) {
3969 reg_temp_mon = NCT6779_REG_TEMP_MON;
3970 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3971 } else {
3972 reg_temp_mon = NCT6792_REG_TEMP_MON;
3973 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3974 }
David Bartley578ab5f2013-06-24 22:28:28 -07003975 reg_temp_over = NCT6779_REG_TEMP_OVER;
3976 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3977 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3978 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3979 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3980
3981 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003982 default:
3983 return -ENODEV;
3984 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003985 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003986 data->have_temp = 0;
3987
3988 /*
3989 * On some boards, not all available temperature sources are monitored,
3990 * even though some of the monitoring registers are unused.
3991 * Get list of unused monitoring registers, then detect if any fan
3992 * controls are configured to use unmonitored temperature sources.
3993 * If so, assign the unmonitored temperature sources to available
3994 * monitoring registers.
3995 */
3996 mask = 0;
3997 available = 0;
3998 for (i = 0; i < num_reg_temp; i++) {
3999 if (reg_temp[i] == 0)
4000 continue;
4001
4002 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004003 if (!src || (mask & BIT(src)))
4004 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004005
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004006 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004007 }
4008
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004009 /*
4010 * Now find unmonitored temperature registers and enable monitoring
4011 * if additional monitoring registers are available.
4012 */
4013 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4014 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4015
Guenter Roeckaa136e52012-12-04 03:26:05 -08004016 mask = 0;
4017 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4018 for (i = 0; i < num_reg_temp; i++) {
4019 if (reg_temp[i] == 0)
4020 continue;
4021
4022 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004023 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004024 continue;
4025
Guenter Roeckcc66b302017-05-17 18:05:06 -07004026 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004027 dev_info(dev,
4028 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4029 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4030 continue;
4031 }
4032
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004033 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004034
4035 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4036 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004037 data->have_temp |= BIT(src - 1);
4038 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004039 data->reg_temp[0][src - 1] = reg_temp[i];
4040 data->reg_temp[1][src - 1] = reg_temp_over[i];
4041 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004042 if (reg_temp_crit_h && reg_temp_crit_h[i])
4043 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4044 else if (reg_temp_crit[src - 1])
4045 data->reg_temp[3][src - 1]
4046 = reg_temp_crit[src - 1];
4047 if (reg_temp_crit_l && reg_temp_crit_l[i])
4048 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004049 data->reg_temp_config[src - 1] = reg_temp_config[i];
4050 data->temp_src[src - 1] = src;
4051 continue;
4052 }
4053
4054 if (s >= NUM_TEMP)
4055 continue;
4056
4057 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004058 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004059 data->reg_temp[0][s] = reg_temp[i];
4060 data->reg_temp[1][s] = reg_temp_over[i];
4061 data->reg_temp[2][s] = reg_temp_hyst[i];
4062 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004063 if (reg_temp_crit_h && reg_temp_crit_h[i])
4064 data->reg_temp[3][s] = reg_temp_crit_h[i];
4065 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004066 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004067 if (reg_temp_crit_l && reg_temp_crit_l[i])
4068 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004069
4070 data->temp_src[s] = src;
4071 s++;
4072 }
4073
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004074 /*
4075 * Repeat with temperatures used for fan control.
4076 * This set of registers does not support limits.
4077 */
4078 for (i = 0; i < num_reg_temp_mon; i++) {
4079 if (reg_temp_mon[i] == 0)
4080 continue;
4081
4082 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004083 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004084 continue;
4085
Guenter Roeckcc66b302017-05-17 18:05:06 -07004086 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004087 dev_info(dev,
4088 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4089 src, i, data->REG_TEMP_SEL[i],
4090 reg_temp_mon[i]);
4091 continue;
4092 }
4093
Guenter Roeck7ce41902016-09-11 12:42:52 -07004094 /*
4095 * For virtual temperature sources, the 'virtual' temperature
4096 * for each fan reflects a different temperature, and there
4097 * are no duplicates.
4098 */
4099 if (src != TEMP_SOURCE_VIRTUAL) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004100 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004101 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004102 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004103 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004104
4105 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4106 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004107 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004108 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004109 data->have_temp |= BIT(src - 1);
4110 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004111 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4112 data->temp_src[src - 1] = src;
4113 continue;
4114 }
4115
4116 if (s >= NUM_TEMP)
4117 continue;
4118
4119 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004120 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004121 data->reg_temp[0][s] = reg_temp_mon[i];
4122 data->temp_src[s] = src;
4123 s++;
4124 }
4125
Guenter Roeckaa136e52012-12-04 03:26:05 -08004126#ifdef USE_ALTERNATE
4127 /*
4128 * Go through the list of alternate temp registers and enable
4129 * if possible.
4130 * The temperature is already monitored if the respective bit in <mask>
4131 * is set.
4132 */
Guenter Roeckcc66b302017-05-17 18:05:06 -07004133 for (i = 0; i < 32; i++) {
4134 if (!(data->temp_mask & BIT(i + 1)))
4135 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004136 if (!reg_temp_alternate[i])
4137 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004138 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004139 continue;
4140 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004141 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004142 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004143 data->have_temp |= BIT(i);
4144 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004145 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07004146 if (i < num_reg_temp) {
4147 data->reg_temp[1][i] = reg_temp_over[i];
4148 data->reg_temp[2][i] = reg_temp_hyst[i];
4149 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004150 data->temp_src[i] = i + 1;
4151 continue;
4152 }
4153
4154 if (s >= NUM_TEMP) /* Abort if no more space */
4155 break;
4156
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004157 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004158 data->reg_temp[0][s] = reg_temp_alternate[i];
4159 data->temp_src[s] = i + 1;
4160 s++;
4161 }
4162#endif /* USE_ALTERNATE */
4163
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004164 /* Initialize the chip */
4165 nct6775_init_device(data);
4166
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004167 err = superio_enter(sio_data->sioreg);
4168 if (err)
4169 return err;
4170
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004171 cr2a = superio_inb(sio_data->sioreg, 0x2a);
4172 switch (data->kind) {
4173 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004174 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004175 break;
4176 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004177 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004178 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004179 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004180 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004181 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004182 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004183 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004184 case nct6795:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004185 break;
4186 }
4187
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004188 /*
4189 * Read VID value
4190 * We can get the VID input values directly at logical device D 0xe3.
4191 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004192 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004193 superio_select(sio_data->sioreg, NCT6775_LD_VID);
4194 data->vid = superio_inb(sio_data->sioreg, 0xe3);
4195 data->vrm = vid_which_vrm();
4196 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004197
4198 if (fan_debounce) {
4199 u8 tmp;
4200
4201 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
4202 tmp = superio_inb(sio_data->sioreg,
4203 NCT6775_REG_CR_FAN_DEBOUNCE);
4204 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004205 case nct6106:
4206 tmp |= 0xe0;
4207 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004208 case nct6775:
4209 tmp |= 0x1e;
4210 break;
4211 case nct6776:
4212 case nct6779:
4213 tmp |= 0x3e;
4214 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004215 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004216 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004217 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004218 case nct6795:
David Bartley578ab5f2013-06-24 22:28:28 -07004219 tmp |= 0x7e;
4220 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004221 }
4222 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
4223 tmp);
4224 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4225 data->name);
4226 }
4227
Guenter Roeckdf612d52013-07-08 13:15:04 -07004228 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004229
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230 superio_exit(sio_data->sioreg);
4231
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004232 /* Read fan clock dividers immediately */
4233 nct6775_init_fan_common(dev, data);
4234
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004235 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004236 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4237 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004238 if (IS_ERR(group))
4239 return PTR_ERR(group);
4240
Axel Lin55bdee62014-07-24 08:59:34 +08004241 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004242
Guenter Roeckf73cf632013-03-18 09:22:50 -07004243 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4244 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004245 if (IS_ERR(group))
4246 return PTR_ERR(group);
4247
Axel Lin55bdee62014-07-24 08:59:34 +08004248 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004249
Guenter Roeckf73cf632013-03-18 09:22:50 -07004250 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4251 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004252 if (IS_ERR(group))
4253 return PTR_ERR(group);
4254
Axel Lin55bdee62014-07-24 08:59:34 +08004255 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004256
Guenter Roeckf73cf632013-03-18 09:22:50 -07004257 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4258 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004259 if (IS_ERR(group))
4260 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004261
Axel Lin55bdee62014-07-24 08:59:34 +08004262 data->groups[num_attr_groups++] = group;
4263 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004264
Guenter Roecka150d952013-07-11 22:55:22 -07004265 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4266 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004267 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004268}
4269
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004270static void nct6791_enable_io_mapping(int sioaddr)
4271{
4272 int val;
4273
4274 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4275 if (val & 0x10) {
4276 pr_info("Enabling hardware monitor logical device mappings.\n");
4277 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4278 val & ~0x10);
4279 }
4280}
4281
Guenter Roeck48e93182015-02-07 08:48:49 -08004282static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004283{
4284 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004285
4286 mutex_lock(&data->update_lock);
4287 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004288 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004289 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4290 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4291 }
4292 mutex_unlock(&data->update_lock);
4293
4294 return 0;
4295}
4296
Guenter Roeck48e93182015-02-07 08:48:49 -08004297static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004298{
4299 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004300 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004301 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004302 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004303
4304 mutex_lock(&data->update_lock);
4305 data->bank = 0xff; /* Force initial bank selection */
4306
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004307 err = superio_enter(sioreg);
4308 if (err)
4309 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004310
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004311 superio_select(sioreg, NCT6775_LD_HWM);
4312 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4313 if (reg != data->sio_reg_enable)
4314 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4315
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004316 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck419220d2017-05-17 18:19:18 -07004317 data->kind == nct6793 || data->kind == nct6795)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004318 nct6791_enable_io_mapping(sioreg);
4319
4320 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004321
Guenter Roeck84d19d92012-12-04 08:01:39 -08004322 /* Restore limits */
4323 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004324 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004325 continue;
4326
4327 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4328 data->in[i][1]);
4329 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4330 data->in[i][2]);
4331 }
4332
Guenter Roeckc409fd42013-04-09 05:04:00 -07004333 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004334 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004335 continue;
4336
4337 nct6775_write_value(data, data->REG_FAN_MIN[i],
4338 data->fan_min[i]);
4339 }
4340
4341 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004342 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004343 continue;
4344
Guenter Roeckc409fd42013-04-09 05:04:00 -07004345 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004346 if (data->reg_temp[j][i])
4347 nct6775_write_temp(data, data->reg_temp[j][i],
4348 data->temp[j][i]);
4349 }
4350
4351 /* Restore other settings */
4352 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004353 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004354 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4355 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4356 }
4357
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004358abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004359 /* Force re-reading all values */
4360 data->valid = false;
4361 mutex_unlock(&data->update_lock);
4362
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004363 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004364}
4365
Guenter Roeck48e93182015-02-07 08:48:49 -08004366static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004367
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004368static struct platform_driver nct6775_driver = {
4369 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004370 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004371 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004372 },
4373 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004374};
4375
4376/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004377static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004378{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004379 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004380 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004381 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004382
4383 err = superio_enter(sioaddr);
4384 if (err)
4385 return err;
4386
Guenter Roeckfc72af32016-08-03 22:07:18 -07004387 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
4388 superio_inb(sioaddr, SIO_REG_DEVID + 1);
4389 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004390 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004391
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004392 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004393 case SIO_NCT6106_ID:
4394 sio_data->kind = nct6106;
4395 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004396 case SIO_NCT6775_ID:
4397 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004398 break;
4399 case SIO_NCT6776_ID:
4400 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004401 break;
4402 case SIO_NCT6779_ID:
4403 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004404 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004405 case SIO_NCT6791_ID:
4406 sio_data->kind = nct6791;
4407 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004408 case SIO_NCT6792_ID:
4409 sio_data->kind = nct6792;
4410 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004411 case SIO_NCT6793_ID:
4412 sio_data->kind = nct6793;
4413 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004414 case SIO_NCT6795_ID:
4415 sio_data->kind = nct6795;
4416 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004417 default:
4418 if (val != 0xffff)
4419 pr_debug("unsupported chip ID: 0x%04x\n", val);
4420 superio_exit(sioaddr);
4421 return -ENODEV;
4422 }
4423
4424 /* We have a known chip, find the HWM I/O address */
4425 superio_select(sioaddr, NCT6775_LD_HWM);
4426 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4427 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004428 addr = val & IOREGION_ALIGNMENT;
4429 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004430 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4431 superio_exit(sioaddr);
4432 return -ENODEV;
4433 }
4434
4435 /* Activate logical device if needed */
4436 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4437 if (!(val & 0x01)) {
4438 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4439 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4440 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004441
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004442 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck419220d2017-05-17 18:19:18 -07004443 sio_data->kind == nct6793 || sio_data->kind == nct6795)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004444 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004445
4446 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004447 pr_info("Found %s or compatible chip at %#x:%#x\n",
4448 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004449 sio_data->sioreg = sioaddr;
4450
Guenter Roeck698a7c22013-04-05 07:35:25 -07004451 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004452}
4453
4454/*
4455 * when Super-I/O functions move to a separate file, the Super-I/O
4456 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004457 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004458 * must keep track of the device
4459 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004460static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004461
4462static int __init sensors_nct6775_init(void)
4463{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004464 int i, err;
4465 bool found = false;
4466 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004467 struct resource res;
4468 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004469 int sioaddr[2] = { 0x2e, 0x4e };
4470
4471 err = platform_driver_register(&nct6775_driver);
4472 if (err)
4473 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004474
4475 /*
4476 * initialize sio_data->kind and sio_data->sioreg.
4477 *
4478 * when Super-I/O functions move to a separate file, the Super-I/O
4479 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4480 * nct6775 hardware monitor, and call probe()
4481 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004482 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4483 address = nct6775_find(sioaddr[i], &sio_data);
4484 if (address <= 0)
4485 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004486
Guenter Roeck698a7c22013-04-05 07:35:25 -07004487 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004488
Guenter Roeck698a7c22013-04-05 07:35:25 -07004489 pdev[i] = platform_device_alloc(DRVNAME, address);
4490 if (!pdev[i]) {
4491 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004492 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004493 }
4494
4495 err = platform_device_add_data(pdev[i], &sio_data,
4496 sizeof(struct nct6775_sio_data));
4497 if (err)
4498 goto exit_device_put;
4499
4500 memset(&res, 0, sizeof(res));
4501 res.name = DRVNAME;
4502 res.start = address + IOREGION_OFFSET;
4503 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4504 res.flags = IORESOURCE_IO;
4505
4506 err = acpi_check_resource_conflict(&res);
4507 if (err) {
4508 platform_device_put(pdev[i]);
4509 pdev[i] = NULL;
4510 continue;
4511 }
4512
4513 err = platform_device_add_resources(pdev[i], &res, 1);
4514 if (err)
4515 goto exit_device_put;
4516
4517 /* platform_device_add calls probe() */
4518 err = platform_device_add(pdev[i]);
4519 if (err)
4520 goto exit_device_put;
4521 }
4522 if (!found) {
4523 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004524 goto exit_unregister;
4525 }
4526
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004527 return 0;
4528
4529exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004530 platform_device_put(pdev[i]);
4531exit_device_unregister:
4532 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004533 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004534 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004535 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004536exit_unregister:
4537 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004538 return err;
4539}
4540
4541static void __exit sensors_nct6775_exit(void)
4542{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004543 int i;
4544
4545 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4546 if (pdev[i])
4547 platform_device_unregister(pdev[i]);
4548 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004549 platform_driver_unregister(&nct6775_driver);
4550}
4551
4552MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004553MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004554MODULE_LICENSE("GPL");
4555
4556module_init(sensors_nct6775_init);
4557module_exit(sensors_nct6775_exit);