blob: 724401a368f75adf51e70048068d2b8c9f690706 [file] [log] [blame]
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001/*
2 * nct6775 - Driver for the hardware monitoring functionality of
3 * Nuvoton NCT677x Super-I/O chips
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from w83627ehf driver
Jean Delvare7c81c602014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070042 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070043 *
44 * #temp lists the number of monitored temperature sources (first value) plus
45 * the number of directly connectable temperature sensors (second value).
46 */
47
48#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
50#include <linux/module.h>
51#include <linux/init.h>
52#include <linux/slab.h>
53#include <linux/jiffies.h>
54#include <linux/platform_device.h>
55#include <linux/hwmon.h>
56#include <linux/hwmon-sysfs.h>
57#include <linux/hwmon-vid.h>
58#include <linux/err.h>
59#include <linux/mutex.h>
60#include <linux/acpi.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080061#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070062#include <linux/io.h>
63#include "lm75.h"
64
Guenter Roeckaa136e52012-12-04 03:26:05 -080065#define USE_ALTERNATE
66
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070067enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070068
69/* used to set data->name = nct6775_device_names[data->sio_kind] */
70static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070071 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070072 "nct6775",
73 "nct6776",
74 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070075 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080076 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070077 "nct6793",
78};
79
80static const char * const nct6775_sio_names[] __initconst = {
81 "NCT6106D",
82 "NCT6775F",
83 "NCT6776D/F",
84 "NCT6779D",
85 "NCT6791D",
86 "NCT6792D",
87 "NCT6793D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070088};
89
90static unsigned short force_id;
91module_param(force_id, ushort, 0);
92MODULE_PARM_DESC(force_id, "Override the detected device ID");
93
Guenter Roeck47ece962012-12-04 07:59:32 -080094static unsigned short fan_debounce;
95module_param(fan_debounce, ushort, 0);
96MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
97
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070098#define DRVNAME "nct6775"
99
100/*
101 * Super-I/O constants and functions
102 */
103
Guenter Roecka6bd5872012-12-04 03:13:34 -0800104#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700105#define NCT6775_LD_HWM 0x0b
106#define NCT6775_LD_VID 0x0d
107
108#define SIO_REG_LDSEL 0x07 /* Logical device select */
109#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
110#define SIO_REG_ENABLE 0x30 /* Logical device enable */
111#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
112
Guenter Roeck6c009502012-07-01 08:23:15 -0700113#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700114#define SIO_NCT6775_ID 0xb470
115#define SIO_NCT6776_ID 0xc330
116#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700117#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800118#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700119#define SIO_NCT6793_ID 0xd120
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700120#define SIO_ID_MASK 0xFFF0
121
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800122enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
123
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700124static inline void
125superio_outb(int ioreg, int reg, int val)
126{
127 outb(reg, ioreg);
128 outb(val, ioreg + 1);
129}
130
131static inline int
132superio_inb(int ioreg, int reg)
133{
134 outb(reg, ioreg);
135 return inb(ioreg + 1);
136}
137
138static inline void
139superio_select(int ioreg, int ld)
140{
141 outb(SIO_REG_LDSEL, ioreg);
142 outb(ld, ioreg + 1);
143}
144
145static inline int
146superio_enter(int ioreg)
147{
148 /*
149 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
150 */
151 if (!request_muxed_region(ioreg, 2, DRVNAME))
152 return -EBUSY;
153
154 outb(0x87, ioreg);
155 outb(0x87, ioreg);
156
157 return 0;
158}
159
160static inline void
161superio_exit(int ioreg)
162{
163 outb(0xaa, ioreg);
164 outb(0x02, ioreg);
165 outb(0x02, ioreg + 1);
166 release_region(ioreg, 2);
167}
168
169/*
170 * ISA constants
171 */
172
173#define IOREGION_ALIGNMENT (~7)
174#define IOREGION_OFFSET 5
175#define IOREGION_LENGTH 2
176#define ADDR_REG_OFFSET 0
177#define DATA_REG_OFFSET 1
178
179#define NCT6775_REG_BANK 0x4E
180#define NCT6775_REG_CONFIG 0x40
181
182/*
183 * Not currently used:
184 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
185 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
186 * REG_MAN_ID is at port 0x4f
187 * REG_CHIP_ID is at port 0x58
188 */
189
Guenter Roeckaa136e52012-12-04 03:26:05 -0800190#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
191#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
192
Guenter Roeck6c009502012-07-01 08:23:15 -0700193#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700194#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700195
David Bartley578ab5f2013-06-24 22:28:28 -0700196#define NUM_FAN 6
197
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700198/* Common and NCT6775 specific data */
199
200/* Voltage min/max registers for nr=7..14 are in bank 5 */
201
202static const u16 NCT6775_REG_IN_MAX[] = {
203 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
204 0x55c, 0x55e, 0x560, 0x562 };
205static const u16 NCT6775_REG_IN_MIN[] = {
206 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
207 0x55d, 0x55f, 0x561, 0x563 };
208static const u16 NCT6775_REG_IN[] = {
209 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
210};
211
212#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800213#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700214#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700215
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800216#define NCT6775_REG_FANDIV1 0x506
217#define NCT6775_REG_FANDIV2 0x507
218
Guenter Roeck47ece962012-12-04 07:59:32 -0800219#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
220
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700221static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
222
Guenter Roeck30846992013-06-24 22:21:59 -0700223/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700224
225static const s8 NCT6775_ALARM_BITS[] = {
226 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
227 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
228 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700229 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700230 -1, -1, -1, /* unused */
231 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
232 12, -1 }; /* intrusion0, intrusion1 */
233
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800234#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800235#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800236#define INTRUSION_ALARM_BASE 30
237
Guenter Roeck30846992013-06-24 22:21:59 -0700238static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
239
240/*
241 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
242 * 30..31 intrusion
243 */
244static const s8 NCT6775_BEEP_BITS[] = {
245 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
246 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
247 21, /* global beep enable */
248 6, 7, 11, 28, -1, /* fan1..fan5 */
249 -1, -1, -1, /* unused */
250 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
251 12, -1 }; /* intrusion0, intrusion1 */
252
253#define BEEP_ENABLE_BASE 15
254
Guenter Roecka6bd5872012-12-04 03:13:34 -0800255static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
256static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
257
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800258/* DC or PWM output fan configuration */
259static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
260static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
261
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800262/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800263
David Bartley578ab5f2013-06-24 22:28:28 -0700264static const u16 NCT6775_REG_TARGET[] = {
265 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
266static const u16 NCT6775_REG_FAN_MODE[] = {
267 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800268static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700269 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800270static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700271 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800272static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700273 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
274static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
275 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800276static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
277static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
278
279static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700280 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
281static const u16 NCT6775_REG_PWM[] = {
282 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
283static const u16 NCT6775_REG_PWM_READ[] = {
284 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800285
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800286static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
287static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800288static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700289static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800290
Guenter Roeckaa136e52012-12-04 03:26:05 -0800291static const u16 NCT6775_REG_TEMP[] = {
292 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
293
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800294static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
295
Guenter Roeckaa136e52012-12-04 03:26:05 -0800296static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
297 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
298static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
299 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
300static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
301 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
302
303static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
304 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
305
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800306static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700307 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800308
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800309static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700310 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800311static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700312 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800313static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700314 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800315static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700316 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800317static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700318 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800319
Guenter Roeckaa136e52012-12-04 03:26:05 -0800320static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
321
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800322static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700323 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800324static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700325 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800326
327#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
328#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
329
330static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
331
332static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700333 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800334static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700335 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800336
Guenter Roeckaa136e52012-12-04 03:26:05 -0800337static const char *const nct6775_temp_label[] = {
338 "",
339 "SYSTIN",
340 "CPUTIN",
341 "AUXTIN",
342 "AMD SB-TSI",
343 "PECI Agent 0",
344 "PECI Agent 1",
345 "PECI Agent 2",
346 "PECI Agent 3",
347 "PECI Agent 4",
348 "PECI Agent 5",
349 "PECI Agent 6",
350 "PECI Agent 7",
351 "PCH_CHIP_CPU_MAX_TEMP",
352 "PCH_CHIP_TEMP",
353 "PCH_CPU_TEMP",
354 "PCH_MCH_TEMP",
355 "PCH_DIM0_TEMP",
356 "PCH_DIM1_TEMP",
357 "PCH_DIM2_TEMP",
358 "PCH_DIM3_TEMP"
359};
360
361static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
362 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
363
364static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
365 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
366 0xa07 };
367
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700368/* NCT6776 specific data */
369
Guenter Roeck728d2942015-08-31 16:13:47 -0700370/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
371#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
372#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
373
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700374static const s8 NCT6776_ALARM_BITS[] = {
375 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
376 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
377 -1, /* unused */
378 6, 7, 11, 10, 23, /* fan1..fan5 */
379 -1, -1, -1, /* unused */
380 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
381 12, 9 }; /* intrusion0, intrusion1 */
382
Guenter Roeck30846992013-06-24 22:21:59 -0700383static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
384
385static const s8 NCT6776_BEEP_BITS[] = {
386 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
387 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
388 24, /* global beep enable */
389 25, 26, 27, 28, 29, /* fan1..fan5 */
390 -1, -1, -1, /* unused */
391 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
392 30, 31 }; /* intrusion0, intrusion1 */
393
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800394static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700395 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800396
David Bartley578ab5f2013-06-24 22:28:28 -0700397static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
398static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800399
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800400static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800401static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800402
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800403static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700404 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800405
Guenter Roeckaa136e52012-12-04 03:26:05 -0800406static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
407 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
408
409static const char *const nct6776_temp_label[] = {
410 "",
411 "SYSTIN",
412 "CPUTIN",
413 "AUXTIN",
414 "SMBUSMASTER 0",
415 "SMBUSMASTER 1",
416 "SMBUSMASTER 2",
417 "SMBUSMASTER 3",
418 "SMBUSMASTER 4",
419 "SMBUSMASTER 5",
420 "SMBUSMASTER 6",
421 "SMBUSMASTER 7",
422 "PECI Agent 0",
423 "PECI Agent 1",
424 "PCH_CHIP_CPU_MAX_TEMP",
425 "PCH_CHIP_TEMP",
426 "PCH_CPU_TEMP",
427 "PCH_MCH_TEMP",
428 "PCH_DIM0_TEMP",
429 "PCH_DIM1_TEMP",
430 "PCH_DIM2_TEMP",
431 "PCH_DIM3_TEMP",
432 "BYTE_TEMP"
433};
434
435static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
436 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
437
438static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
439 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
440
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700441/* NCT6779 specific data */
442
443static const u16 NCT6779_REG_IN[] = {
444 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
445 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
446
447static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
448 0x459, 0x45A, 0x45B, 0x568 };
449
450static const s8 NCT6779_ALARM_BITS[] = {
451 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
452 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
453 -1, /* unused */
454 6, 7, 11, 10, 23, /* fan1..fan5 */
455 -1, -1, -1, /* unused */
456 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
457 12, 9 }; /* intrusion0, intrusion1 */
458
Guenter Roeck30846992013-06-24 22:21:59 -0700459static const s8 NCT6779_BEEP_BITS[] = {
460 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
461 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
462 24, /* global beep enable */
463 25, 26, 27, 28, 29, /* fan1..fan5 */
464 -1, -1, -1, /* unused */
465 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
466 30, 31 }; /* intrusion0, intrusion1 */
467
David Bartley578ab5f2013-06-24 22:28:28 -0700468static const u16 NCT6779_REG_FAN[] = {
469 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800470static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700471 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800472
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800473static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700474 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700475#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800476static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700477 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800478
Guenter Roeckaa136e52012-12-04 03:26:05 -0800479static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800480static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800481static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
482 0x18, 0x152 };
483static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
484 0x3a, 0x153 };
485static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
486 0x39, 0x155 };
487
488static const u16 NCT6779_REG_TEMP_OFFSET[] = {
489 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
490
491static const char *const nct6779_temp_label[] = {
492 "",
493 "SYSTIN",
494 "CPUTIN",
495 "AUXTIN0",
496 "AUXTIN1",
497 "AUXTIN2",
498 "AUXTIN3",
499 "",
500 "SMBUSMASTER 0",
501 "SMBUSMASTER 1",
502 "SMBUSMASTER 2",
503 "SMBUSMASTER 3",
504 "SMBUSMASTER 4",
505 "SMBUSMASTER 5",
506 "SMBUSMASTER 6",
507 "SMBUSMASTER 7",
508 "PECI Agent 0",
509 "PECI Agent 1",
510 "PCH_CHIP_CPU_MAX_TEMP",
511 "PCH_CHIP_TEMP",
512 "PCH_CPU_TEMP",
513 "PCH_MCH_TEMP",
514 "PCH_DIM0_TEMP",
515 "PCH_DIM1_TEMP",
516 "PCH_DIM2_TEMP",
517 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700518 "BYTE_TEMP",
519 "",
520 "",
521 "",
522 "",
523 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800524};
525
Guenter Roeck9a383712015-08-29 15:29:25 -0700526#define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5)
527#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label)
528
529static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800530 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
531 0, 0, 0, 0, 0, 0, 0, 0,
532 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
533 0x408, 0 };
534
Guenter Roeck9a383712015-08-29 15:29:25 -0700535static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800536 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
537
David Bartley578ab5f2013-06-24 22:28:28 -0700538/* NCT6791 specific data */
539
540#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
541
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800542static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
543static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
544static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
545static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
546static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
547static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
548
David Bartley578ab5f2013-06-24 22:28:28 -0700549static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
550 0x459, 0x45A, 0x45B, 0x568, 0x45D };
551
552static const s8 NCT6791_ALARM_BITS[] = {
553 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
554 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
555 -1, /* unused */
556 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
557 -1, -1, /* unused */
558 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
559 12, 9 }; /* intrusion0, intrusion1 */
560
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700561/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800562
563static const u16 NCT6792_REG_TEMP_MON[] = {
564 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
565static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
566 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700567
Guenter Roeck6c009502012-07-01 08:23:15 -0700568/* NCT6102D/NCT6106D specific data */
569
570#define NCT6106_REG_VBAT 0x318
571#define NCT6106_REG_DIODE 0x319
572#define NCT6106_DIODE_MASK 0x01
573
574static const u16 NCT6106_REG_IN_MAX[] = {
575 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
576static const u16 NCT6106_REG_IN_MIN[] = {
577 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
578static const u16 NCT6106_REG_IN[] = {
579 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
580
581static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800582static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700583static const u16 NCT6106_REG_TEMP_HYST[] = {
584 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
585static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700586 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
587static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
588 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
589static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
590 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700591static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
592static const u16 NCT6106_REG_TEMP_CONFIG[] = {
593 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
594
595static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
596static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
597static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
598static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
599
600static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
601static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
602static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
603static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
604static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
605static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
606static const u16 NCT6106_REG_TEMP_SOURCE[] = {
607 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
608
609static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
610static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
611 0x11b, 0x12b, 0x13b };
612
613static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
614#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
615static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
616
617static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
618static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
619static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
620static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
621static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
622static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
623
624static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
625
626static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
627static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
628static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
629static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
630static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
631static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
632
633static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
634static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
635
636static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
637 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
638
639static const s8 NCT6106_ALARM_BITS[] = {
640 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
641 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
642 -1, /* unused */
643 32, 33, 34, -1, -1, /* fan1..fan5 */
644 -1, -1, -1, /* unused */
645 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
646 48, -1 /* intrusion0, intrusion1 */
647};
648
Guenter Roeck30846992013-06-24 22:21:59 -0700649static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
650 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
651
652static const s8 NCT6106_BEEP_BITS[] = {
653 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
654 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
655 32, /* global beep enable */
656 24, 25, 26, 27, 28, /* fan1..fan5 */
657 -1, -1, -1, /* unused */
658 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
659 34, -1 /* intrusion0, intrusion1 */
660};
661
Guenter Roeck6c009502012-07-01 08:23:15 -0700662static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
663 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
664
665static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
666 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
667
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800668static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
669{
670 if (mode == 0 && pwm == 255)
671 return off;
672 return mode + 1;
673}
674
675static int pwm_enable_to_reg(enum pwm_enable mode)
676{
677 if (mode == off)
678 return 0;
679 return mode - 1;
680}
681
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700682/*
683 * Conversions
684 */
685
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800686/* 1 is DC mode, output in ms */
687static unsigned int step_time_from_reg(u8 reg, u8 mode)
688{
689 return mode ? 400 * reg : 100 * reg;
690}
691
692static u8 step_time_to_reg(unsigned int msec, u8 mode)
693{
694 return clamp_val((mode ? (msec + 200) / 400 :
695 (msec + 50) / 100), 1, 255);
696}
697
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800698static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
699{
700 if (reg == 0 || reg == 255)
701 return 0;
702 return 1350000U / (reg << divreg);
703}
704
705static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
706{
707 if ((reg & 0xff1f) == 0xff1f)
708 return 0;
709
710 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
711
712 if (reg == 0)
713 return 0;
714
715 return 1350000U / reg;
716}
717
718static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
719{
720 if (reg == 0 || reg == 0xffff)
721 return 0;
722
723 /*
724 * Even though the registers are 16 bit wide, the fan divisor
725 * still applies.
726 */
727 return 1350000U / (reg << divreg);
728}
729
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800730static u16 fan_to_reg(u32 fan, unsigned int divreg)
731{
732 if (!fan)
733 return 0;
734
735 return (1350000U / fan) >> divreg;
736}
737
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800738static inline unsigned int
739div_from_reg(u8 reg)
740{
741 return 1 << reg;
742}
743
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700744/*
745 * Some of the voltage inputs have internal scaling, the tables below
746 * contain 8 (the ADC LSB in mV) * scaling factor * 100
747 */
748static const u16 scale_in[15] = {
749 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
750 800, 800
751};
752
753static inline long in_from_reg(u8 reg, u8 nr)
754{
755 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
756}
757
758static inline u8 in_to_reg(u32 val, u8 nr)
759{
760 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
761}
762
763/*
764 * Data structures and manipulation thereof
765 */
766
767struct nct6775_data {
768 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700769 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700770 enum kinds kind;
771 const char *name;
772
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700773 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700774
Guenter Roeckb7a61352013-04-02 22:14:06 -0700775 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
776 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800777 */
778 u8 temp_src[NUM_TEMP];
779 u16 reg_temp_config[NUM_TEMP];
780 const char * const *temp_label;
781 int temp_label_num;
782
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700783 u16 REG_CONFIG;
784 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800785 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700786 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700787
788 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700789 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700790
791 const u16 *REG_VIN;
792 const u16 *REG_IN_MINMAX[2];
793
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800794 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800795 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800796 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800797 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800798 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700799 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800800 const u16 *REG_FAN_TIME[3];
801
802 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800803
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800804 const u8 *REG_PWM_MODE;
805 const u8 *PWM_MODE_MASK;
806
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800807 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
808 * [3]=pwm_max, [4]=pwm_step,
809 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800810 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800811 const u16 *REG_PWM_READ;
812
Guenter Roeck6c009502012-07-01 08:23:15 -0700813 const u16 *REG_CRITICAL_PWM_ENABLE;
814 u8 CRITICAL_PWM_ENABLE_MASK;
815 const u16 *REG_CRITICAL_PWM;
816
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800817 const u16 *REG_AUTO_TEMP;
818 const u16 *REG_AUTO_PWM;
819
820 const u16 *REG_CRITICAL_TEMP;
821 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
822
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800823 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800824 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800825 const u16 *REG_WEIGHT_TEMP_SEL;
826 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
827
Guenter Roeckaa136e52012-12-04 03:26:05 -0800828 const u16 *REG_TEMP_OFFSET;
829
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700830 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700831 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700832
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800833 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
834 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
835
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700836 struct mutex update_lock;
837 bool valid; /* true if following fields are valid */
838 unsigned long last_updated; /* In jiffies */
839
840 /* Register values */
841 u8 bank; /* current register bank */
842 u8 in_num; /* number of in inputs we have */
843 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700844 unsigned int rpm[NUM_FAN];
845 u16 fan_min[NUM_FAN];
846 u8 fan_pulses[NUM_FAN];
847 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800848 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800849 u8 has_fan; /* some fan inputs can be disabled */
850 u8 has_fan_min; /* some fans don't have min register */
851 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700852
Guenter Roeck6c009502012-07-01 08:23:15 -0700853 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700854 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800855 u8 temp_fixed_num; /* 3 or 6 */
856 u8 temp_type[NUM_TEMP_FIXED];
857 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300858 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
859 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700860 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700861 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700862
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800863 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700864 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
865 * 0->PWM variable duty cycle
866 */
867 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800868 /* 0->off
869 * 1->manual
870 * 2->thermal cruise mode (also called SmartFan I)
871 * 3->fan speed cruise mode
872 * 4->SmartFan III
873 * 5->enhanced variable thermal cruise (SmartFan IV)
874 */
David Bartley578ab5f2013-06-24 22:28:28 -0700875 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
876 * [3]=pwm_max, [4]=pwm_step,
877 * [5]=weight_duty_step, [6]=weight_duty_base
878 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800879
David Bartley578ab5f2013-06-24 22:28:28 -0700880 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800881 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700882 u32 target_speed[NUM_FAN];
883 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800884 u8 speed_tolerance_limit;
885
David Bartley578ab5f2013-06-24 22:28:28 -0700886 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800887 u8 tolerance_mask;
888
David Bartley578ab5f2013-06-24 22:28:28 -0700889 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800890
891 /* Automatic fan speed control registers */
892 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700893 u8 auto_pwm[NUM_FAN][7];
894 u8 auto_temp[NUM_FAN][7];
895 u8 pwm_temp_sel[NUM_FAN];
896 u8 pwm_weight_temp_sel[NUM_FAN];
897 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
898 * 2->temp_base
899 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800900
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700901 u8 vid;
902 u8 vrm;
903
Guenter Roeckf73cf632013-03-18 09:22:50 -0700904 bool have_vid;
905
Guenter Roeckaa136e52012-12-04 03:26:05 -0800906 u16 have_temp;
907 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700908 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800909
Guenter Roeck84d19d92012-12-04 08:01:39 -0800910 /* Remember extra register values over suspend/resume */
911 u8 vbat;
912 u8 fandiv1;
913 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800914 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700915};
916
917struct nct6775_sio_data {
918 int sioreg;
919 enum kinds kind;
920};
921
Guenter Roeckf73cf632013-03-18 09:22:50 -0700922struct sensor_device_template {
923 struct device_attribute dev_attr;
924 union {
925 struct {
926 u8 nr;
927 u8 index;
928 } s;
929 int index;
930 } u;
931 bool s2; /* true if both index and nr are used */
932};
933
934struct sensor_device_attr_u {
935 union {
936 struct sensor_device_attribute a1;
937 struct sensor_device_attribute_2 a2;
938 } u;
939 char name[32];
940};
941
942#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
943 .attr = {.name = _template, .mode = _mode }, \
944 .show = _show, \
945 .store = _store, \
946}
947
948#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
949 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
950 .u.index = _index, \
951 .s2 = false }
952
953#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
954 _nr, _index) \
955 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
956 .u.s.index = _index, \
957 .u.s.nr = _nr, \
958 .s2 = true }
959
960#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
961static struct sensor_device_template sensor_dev_template_##_name \
962 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
963 _index)
964
965#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
966 _nr, _index) \
967static struct sensor_device_template sensor_dev_template_##_name \
968 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
969 _nr, _index)
970
971struct sensor_template_group {
972 struct sensor_device_template **templates;
973 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
974 int base;
975};
976
977static struct attribute_group *
978nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
979 int repeat)
980{
981 struct attribute_group *group;
982 struct sensor_device_attr_u *su;
983 struct sensor_device_attribute *a;
984 struct sensor_device_attribute_2 *a2;
985 struct attribute **attrs;
986 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300987 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700988
989 if (repeat <= 0)
990 return ERR_PTR(-EINVAL);
991
992 t = tg->templates;
993 for (count = 0; *t; t++, count++)
994 ;
995
996 if (count == 0)
997 return ERR_PTR(-EINVAL);
998
999 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1000 if (group == NULL)
1001 return ERR_PTR(-ENOMEM);
1002
1003 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
1004 GFP_KERNEL);
1005 if (attrs == NULL)
1006 return ERR_PTR(-ENOMEM);
1007
1008 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1009 GFP_KERNEL);
1010 if (su == NULL)
1011 return ERR_PTR(-ENOMEM);
1012
1013 group->attrs = attrs;
1014 group->is_visible = tg->is_visible;
1015
1016 for (i = 0; i < repeat; i++) {
1017 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001018 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001019 snprintf(su->name, sizeof(su->name),
1020 (*t)->dev_attr.attr.name, tg->base + i);
1021 if ((*t)->s2) {
1022 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001023 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001024 a2->dev_attr.attr.name = su->name;
1025 a2->nr = (*t)->u.s.nr + i;
1026 a2->index = (*t)->u.s.index;
1027 a2->dev_attr.attr.mode =
1028 (*t)->dev_attr.attr.mode;
1029 a2->dev_attr.show = (*t)->dev_attr.show;
1030 a2->dev_attr.store = (*t)->dev_attr.store;
1031 *attrs = &a2->dev_attr.attr;
1032 } else {
1033 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001034 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001035 a->dev_attr.attr.name = su->name;
1036 a->index = (*t)->u.index + i;
1037 a->dev_attr.attr.mode =
1038 (*t)->dev_attr.attr.mode;
1039 a->dev_attr.show = (*t)->dev_attr.show;
1040 a->dev_attr.store = (*t)->dev_attr.store;
1041 *attrs = &a->dev_attr.attr;
1042 }
1043 attrs++;
1044 su++;
1045 t++;
1046 }
1047 }
1048
Guenter Roeckf73cf632013-03-18 09:22:50 -07001049 return group;
1050}
1051
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001052static bool is_word_sized(struct nct6775_data *data, u16 reg)
1053{
1054 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001055 case nct6106:
1056 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1057 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1058 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001059 case nct6775:
1060 return (((reg & 0xff00) == 0x100 ||
1061 (reg & 0xff00) == 0x200) &&
1062 ((reg & 0x00ff) == 0x50 ||
1063 (reg & 0x00ff) == 0x53 ||
1064 (reg & 0x00ff) == 0x55)) ||
1065 (reg & 0xfff0) == 0x630 ||
1066 reg == 0x640 || reg == 0x642 ||
1067 reg == 0x662 ||
1068 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1069 reg == 0x73 || reg == 0x75 || reg == 0x77;
1070 case nct6776:
1071 return (((reg & 0xff00) == 0x100 ||
1072 (reg & 0xff00) == 0x200) &&
1073 ((reg & 0x00ff) == 0x50 ||
1074 (reg & 0x00ff) == 0x53 ||
1075 (reg & 0x00ff) == 0x55)) ||
1076 (reg & 0xfff0) == 0x630 ||
1077 reg == 0x402 ||
1078 reg == 0x640 || reg == 0x642 ||
1079 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1080 reg == 0x73 || reg == 0x75 || reg == 0x77;
1081 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001082 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001083 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001084 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001085 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001086 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001087 reg == 0x402 ||
1088 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1089 reg == 0x640 || reg == 0x642 ||
1090 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001091 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001092 }
1093 return false;
1094}
1095
1096/*
1097 * On older chips, only registers 0x50-0x5f are banked.
1098 * On more recent chips, all registers are banked.
1099 * Assume that is the case and set the bank number for each access.
1100 * Cache the bank number so it only needs to be set if it changes.
1101 */
1102static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1103{
1104 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001105
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001106 if (data->bank != bank) {
1107 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1108 outb_p(bank, data->addr + DATA_REG_OFFSET);
1109 data->bank = bank;
1110 }
1111}
1112
1113static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1114{
1115 int res, word_sized = is_word_sized(data, reg);
1116
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001117 nct6775_set_bank(data, reg);
1118 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1119 res = inb_p(data->addr + DATA_REG_OFFSET);
1120 if (word_sized) {
1121 outb_p((reg & 0xff) + 1,
1122 data->addr + ADDR_REG_OFFSET);
1123 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1124 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001125 return res;
1126}
1127
1128static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1129{
1130 int word_sized = is_word_sized(data, reg);
1131
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001132 nct6775_set_bank(data, reg);
1133 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1134 if (word_sized) {
1135 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1136 outb_p((reg & 0xff) + 1,
1137 data->addr + ADDR_REG_OFFSET);
1138 }
1139 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001140 return 0;
1141}
1142
Guenter Roeckaa136e52012-12-04 03:26:05 -08001143/* We left-align 8-bit temperature values to make the code simpler */
1144static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1145{
1146 u16 res;
1147
1148 res = nct6775_read_value(data, reg);
1149 if (!is_word_sized(data, reg))
1150 res <<= 8;
1151
1152 return res;
1153}
1154
1155static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1156{
1157 if (!is_word_sized(data, reg))
1158 value >>= 8;
1159 return nct6775_write_value(data, reg, value);
1160}
1161
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001162/* This function assumes that the caller holds data->update_lock */
1163static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1164{
1165 u8 reg;
1166
1167 switch (nr) {
1168 case 0:
1169 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1170 | (data->fan_div[0] & 0x7);
1171 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1172 break;
1173 case 1:
1174 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1175 | ((data->fan_div[1] << 4) & 0x70);
1176 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1177 break;
1178 case 2:
1179 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1180 | (data->fan_div[2] & 0x7);
1181 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1182 break;
1183 case 3:
1184 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1185 | ((data->fan_div[3] << 4) & 0x70);
1186 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1187 break;
1188 }
1189}
1190
1191static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1192{
1193 if (data->kind == nct6775)
1194 nct6775_write_fan_div(data, nr);
1195}
1196
1197static void nct6775_update_fan_div(struct nct6775_data *data)
1198{
1199 u8 i;
1200
1201 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1202 data->fan_div[0] = i & 0x7;
1203 data->fan_div[1] = (i & 0x70) >> 4;
1204 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1205 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001206 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001207 data->fan_div[3] = (i & 0x70) >> 4;
1208}
1209
1210static void nct6775_update_fan_div_common(struct nct6775_data *data)
1211{
1212 if (data->kind == nct6775)
1213 nct6775_update_fan_div(data);
1214}
1215
1216static void nct6775_init_fan_div(struct nct6775_data *data)
1217{
1218 int i;
1219
1220 nct6775_update_fan_div_common(data);
1221 /*
1222 * For all fans, start with highest divider value if the divider
1223 * register is not initialized. This ensures that we get a
1224 * reading from the fan count register, even if it is not optimal.
1225 * We'll compute a better divider later on.
1226 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001227 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001228 if (!(data->has_fan & (1 << i)))
1229 continue;
1230 if (data->fan_div[i] == 0) {
1231 data->fan_div[i] = 7;
1232 nct6775_write_fan_div_common(data, i);
1233 }
1234 }
1235}
1236
1237static void nct6775_init_fan_common(struct device *dev,
1238 struct nct6775_data *data)
1239{
1240 int i;
1241 u8 reg;
1242
1243 if (data->has_fan_div)
1244 nct6775_init_fan_div(data);
1245
1246 /*
1247 * If fan_min is not set (0), set it to 0xff to disable it. This
1248 * prevents the unnecessary warning when fanX_min is reported as 0.
1249 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001250 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001251 if (data->has_fan_min & (1 << i)) {
1252 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1253 if (!reg)
1254 nct6775_write_value(data, data->REG_FAN_MIN[i],
1255 data->has_fan_div ? 0xff
1256 : 0xff1f);
1257 }
1258 }
1259}
1260
1261static void nct6775_select_fan_div(struct device *dev,
1262 struct nct6775_data *data, int nr, u16 reg)
1263{
1264 u8 fan_div = data->fan_div[nr];
1265 u16 fan_min;
1266
1267 if (!data->has_fan_div)
1268 return;
1269
1270 /*
1271 * If we failed to measure the fan speed, or the reported value is not
1272 * in the optimal range, and the clock divider can be modified,
1273 * let's try that for next time.
1274 */
1275 if (reg == 0x00 && fan_div < 0x07)
1276 fan_div++;
1277 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1278 fan_div--;
1279
1280 if (fan_div != data->fan_div[nr]) {
1281 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1282 nr + 1, div_from_reg(data->fan_div[nr]),
1283 div_from_reg(fan_div));
1284
1285 /* Preserve min limit if possible */
1286 if (data->has_fan_min & (1 << nr)) {
1287 fan_min = data->fan_min[nr];
1288 if (fan_div > data->fan_div[nr]) {
1289 if (fan_min != 255 && fan_min > 1)
1290 fan_min >>= 1;
1291 } else {
1292 if (fan_min != 255) {
1293 fan_min <<= 1;
1294 if (fan_min > 254)
1295 fan_min = 254;
1296 }
1297 }
1298 if (fan_min != data->fan_min[nr]) {
1299 data->fan_min[nr] = fan_min;
1300 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1301 fan_min);
1302 }
1303 }
1304 data->fan_div[nr] = fan_div;
1305 nct6775_write_fan_div_common(data, nr);
1306 }
1307}
1308
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001309static void nct6775_update_pwm(struct device *dev)
1310{
1311 struct nct6775_data *data = dev_get_drvdata(dev);
1312 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001313 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001314 bool duty_is_dc;
1315
1316 for (i = 0; i < data->pwm_num; i++) {
1317 if (!(data->has_pwm & (1 << i)))
1318 continue;
1319
1320 duty_is_dc = data->REG_PWM_MODE[i] &&
1321 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1322 & data->PWM_MODE_MASK[i]);
1323 data->pwm_mode[i] = duty_is_dc;
1324
1325 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1326 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1327 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1328 data->pwm[j][i]
1329 = nct6775_read_value(data,
1330 data->REG_PWM[j][i]);
1331 }
1332 }
1333
1334 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1335 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001336
1337 if (!data->temp_tolerance[0][i] ||
1338 data->pwm_enable[i] != speed_cruise)
1339 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1340 if (!data->target_speed_tolerance[i] ||
1341 data->pwm_enable[i] == speed_cruise) {
1342 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001343
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001344 if (data->REG_TOLERANCE_H) {
1345 t |= (nct6775_read_value(data,
1346 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1347 }
1348 data->target_speed_tolerance[i] = t;
1349 }
1350
1351 data->temp_tolerance[1][i] =
1352 nct6775_read_value(data,
1353 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1354
1355 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1356 data->pwm_temp_sel[i] = reg & 0x1f;
1357 /* If fan can stop, report floor as 0 */
1358 if (reg & 0x80)
1359 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001360
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001361 if (!data->REG_WEIGHT_TEMP_SEL[i])
1362 continue;
1363
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001364 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1365 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1366 /* If weight is disabled, report weight source as 0 */
1367 if (j == 1 && !(reg & 0x80))
1368 data->pwm_weight_temp_sel[i] = 0;
1369
1370 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001371 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001372 data->weight_temp[j][i]
1373 = nct6775_read_value(data,
1374 data->REG_WEIGHT_TEMP[j][i]);
1375 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001376 }
1377}
1378
1379static void nct6775_update_pwm_limits(struct device *dev)
1380{
1381 struct nct6775_data *data = dev_get_drvdata(dev);
1382 int i, j;
1383 u8 reg;
1384 u16 reg_t;
1385
1386 for (i = 0; i < data->pwm_num; i++) {
1387 if (!(data->has_pwm & (1 << i)))
1388 continue;
1389
Guenter Roeckc409fd42013-04-09 05:04:00 -07001390 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001391 data->fan_time[j][i] =
1392 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1393 }
1394
1395 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1396 /* Update only in matching mode or if never updated */
1397 if (!data->target_temp[i] ||
1398 data->pwm_enable[i] == thermal_cruise)
1399 data->target_temp[i] = reg_t & data->target_temp_mask;
1400 if (!data->target_speed[i] ||
1401 data->pwm_enable[i] == speed_cruise) {
1402 if (data->REG_TOLERANCE_H) {
1403 reg_t |= (nct6775_read_value(data,
1404 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1405 }
1406 data->target_speed[i] = reg_t;
1407 }
1408
1409 for (j = 0; j < data->auto_pwm_num; j++) {
1410 data->auto_pwm[i][j] =
1411 nct6775_read_value(data,
1412 NCT6775_AUTO_PWM(data, i, j));
1413 data->auto_temp[i][j] =
1414 nct6775_read_value(data,
1415 NCT6775_AUTO_TEMP(data, i, j));
1416 }
1417
1418 /* critical auto_pwm temperature data */
1419 data->auto_temp[i][data->auto_pwm_num] =
1420 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1421
1422 switch (data->kind) {
1423 case nct6775:
1424 reg = nct6775_read_value(data,
1425 NCT6775_REG_CRITICAL_ENAB[i]);
1426 data->auto_pwm[i][data->auto_pwm_num] =
1427 (reg & 0x02) ? 0xff : 0x00;
1428 break;
1429 case nct6776:
1430 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1431 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001432 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001433 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001434 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001435 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001436 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001437 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001438 data->REG_CRITICAL_PWM_ENABLE[i]);
1439 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1440 reg = nct6775_read_value(data,
1441 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001442 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001443 reg = 0xff;
1444 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001445 break;
1446 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001447 }
1448}
1449
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001450static struct nct6775_data *nct6775_update_device(struct device *dev)
1451{
1452 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001453 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001454
1455 mutex_lock(&data->update_lock);
1456
Guenter Roeck6445e662013-04-21 09:13:28 -07001457 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001458 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001459 /* Fan clock dividers */
1460 nct6775_update_fan_div_common(data);
1461
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001462 /* Measured voltages and limits */
1463 for (i = 0; i < data->in_num; i++) {
1464 if (!(data->have_in & (1 << i)))
1465 continue;
1466
1467 data->in[i][0] = nct6775_read_value(data,
1468 data->REG_VIN[i]);
1469 data->in[i][1] = nct6775_read_value(data,
1470 data->REG_IN_MINMAX[0][i]);
1471 data->in[i][2] = nct6775_read_value(data,
1472 data->REG_IN_MINMAX[1][i]);
1473 }
1474
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001475 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001476 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001477 u16 reg;
1478
1479 if (!(data->has_fan & (1 << i)))
1480 continue;
1481
1482 reg = nct6775_read_value(data, data->REG_FAN[i]);
1483 data->rpm[i] = data->fan_from_reg(reg,
1484 data->fan_div[i]);
1485
1486 if (data->has_fan_min & (1 << i))
1487 data->fan_min[i] = nct6775_read_value(data,
1488 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001489 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001490 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1491 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001492
1493 nct6775_select_fan_div(dev, data, i, reg);
1494 }
1495
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001496 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001497 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001498
Guenter Roeckaa136e52012-12-04 03:26:05 -08001499 /* Measured temperatures and limits */
1500 for (i = 0; i < NUM_TEMP; i++) {
1501 if (!(data->have_temp & (1 << i)))
1502 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001503 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001504 if (data->reg_temp[j][i])
1505 data->temp[j][i]
1506 = nct6775_read_temp(data,
1507 data->reg_temp[j][i]);
1508 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001509 if (i >= NUM_TEMP_FIXED ||
1510 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001511 continue;
1512 data->temp_offset[i]
1513 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1514 }
1515
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001516 data->alarms = 0;
1517 for (i = 0; i < NUM_REG_ALARM; i++) {
1518 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001519
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001520 if (!data->REG_ALARM[i])
1521 continue;
1522 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1523 data->alarms |= ((u64)alarm) << (i << 3);
1524 }
1525
Guenter Roeck30846992013-06-24 22:21:59 -07001526 data->beeps = 0;
1527 for (i = 0; i < NUM_REG_BEEP; i++) {
1528 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001529
Guenter Roeck30846992013-06-24 22:21:59 -07001530 if (!data->REG_BEEP[i])
1531 continue;
1532 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1533 data->beeps |= ((u64)beep) << (i << 3);
1534 }
1535
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001536 data->last_updated = jiffies;
1537 data->valid = true;
1538 }
1539
1540 mutex_unlock(&data->update_lock);
1541 return data;
1542}
1543
1544/*
1545 * Sysfs callback functions
1546 */
1547static ssize_t
1548show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1549{
1550 struct nct6775_data *data = nct6775_update_device(dev);
1551 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001552 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001553 int nr = sattr->nr;
1554
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001555 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1556}
1557
1558static ssize_t
1559store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1560 size_t count)
1561{
1562 struct nct6775_data *data = dev_get_drvdata(dev);
1563 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001564 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001565 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001566 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001567 int err;
1568
1569 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001570 if (err < 0)
1571 return err;
1572 mutex_lock(&data->update_lock);
1573 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001574 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001575 data->in[nr][index]);
1576 mutex_unlock(&data->update_lock);
1577 return count;
1578}
1579
1580static ssize_t
1581show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1582{
1583 struct nct6775_data *data = nct6775_update_device(dev);
1584 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1585 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001586
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001587 return sprintf(buf, "%u\n",
1588 (unsigned int)((data->alarms >> nr) & 0x01));
1589}
1590
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001591static int find_temp_source(struct nct6775_data *data, int index, int count)
1592{
1593 int source = data->temp_src[index];
1594 int nr;
1595
1596 for (nr = 0; nr < count; nr++) {
1597 int src;
1598
1599 src = nct6775_read_value(data,
1600 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1601 if (src == source)
1602 return nr;
1603 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001604 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001605}
1606
1607static ssize_t
1608show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1609{
1610 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1611 struct nct6775_data *data = nct6775_update_device(dev);
1612 unsigned int alarm = 0;
1613 int nr;
1614
1615 /*
1616 * For temperatures, there is no fixed mapping from registers to alarm
1617 * bits. Alarm bits are determined by the temperature source mapping.
1618 */
1619 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1620 if (nr >= 0) {
1621 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001622
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001623 alarm = (data->alarms >> bit) & 0x01;
1624 }
1625 return sprintf(buf, "%u\n", alarm);
1626}
1627
Guenter Roeck30846992013-06-24 22:21:59 -07001628static ssize_t
1629show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1630{
1631 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1632 struct nct6775_data *data = nct6775_update_device(dev);
1633 int nr = data->BEEP_BITS[sattr->index];
1634
1635 return sprintf(buf, "%u\n",
1636 (unsigned int)((data->beeps >> nr) & 0x01));
1637}
1638
1639static ssize_t
1640store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1641 size_t count)
1642{
1643 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1644 struct nct6775_data *data = dev_get_drvdata(dev);
1645 int nr = data->BEEP_BITS[sattr->index];
1646 int regindex = nr >> 3;
1647 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001648 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001649
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001650 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001651 if (err < 0)
1652 return err;
1653 if (val > 1)
1654 return -EINVAL;
1655
1656 mutex_lock(&data->update_lock);
1657 if (val)
1658 data->beeps |= (1ULL << nr);
1659 else
1660 data->beeps &= ~(1ULL << nr);
1661 nct6775_write_value(data, data->REG_BEEP[regindex],
1662 (data->beeps >> (regindex << 3)) & 0xff);
1663 mutex_unlock(&data->update_lock);
1664 return count;
1665}
1666
1667static ssize_t
1668show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1669{
1670 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1671 struct nct6775_data *data = nct6775_update_device(dev);
1672 unsigned int beep = 0;
1673 int nr;
1674
1675 /*
1676 * For temperatures, there is no fixed mapping from registers to beep
1677 * enable bits. Beep enable bits are determined by the temperature
1678 * source mapping.
1679 */
1680 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1681 if (nr >= 0) {
1682 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001683
Guenter Roeck30846992013-06-24 22:21:59 -07001684 beep = (data->beeps >> bit) & 0x01;
1685 }
1686 return sprintf(buf, "%u\n", beep);
1687}
1688
1689static ssize_t
1690store_temp_beep(struct device *dev, struct device_attribute *attr,
1691 const char *buf, size_t count)
1692{
1693 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1694 struct nct6775_data *data = dev_get_drvdata(dev);
1695 int nr, bit, regindex;
1696 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001697 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001698
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001699 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001700 if (err < 0)
1701 return err;
1702 if (val > 1)
1703 return -EINVAL;
1704
1705 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1706 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001707 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001708
1709 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1710 regindex = bit >> 3;
1711
1712 mutex_lock(&data->update_lock);
1713 if (val)
1714 data->beeps |= (1ULL << bit);
1715 else
1716 data->beeps &= ~(1ULL << bit);
1717 nct6775_write_value(data, data->REG_BEEP[regindex],
1718 (data->beeps >> (regindex << 3)) & 0xff);
1719 mutex_unlock(&data->update_lock);
1720
1721 return count;
1722}
1723
Guenter Roeckf73cf632013-03-18 09:22:50 -07001724static umode_t nct6775_in_is_visible(struct kobject *kobj,
1725 struct attribute *attr, int index)
1726{
1727 struct device *dev = container_of(kobj, struct device, kobj);
1728 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001729 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001730
Guenter Roeckf73cf632013-03-18 09:22:50 -07001731 if (!(data->have_in & (1 << in)))
1732 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001733
Guenter Roeckf73cf632013-03-18 09:22:50 -07001734 return attr->mode;
1735}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001736
Guenter Roeckf73cf632013-03-18 09:22:50 -07001737SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1738SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001739SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1740 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001741SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1742 store_in_reg, 0, 1);
1743SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1744 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001745
Guenter Roeckf73cf632013-03-18 09:22:50 -07001746/*
1747 * nct6775_in_is_visible uses the index into the following array
1748 * to determine if attributes should be created or not.
1749 * Any change in order or content must be matched.
1750 */
1751static struct sensor_device_template *nct6775_attributes_in_template[] = {
1752 &sensor_dev_template_in_input,
1753 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001754 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001755 &sensor_dev_template_in_min,
1756 &sensor_dev_template_in_max,
1757 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001758};
1759
Guenter Roeckf73cf632013-03-18 09:22:50 -07001760static struct sensor_template_group nct6775_in_template_group = {
1761 .templates = nct6775_attributes_in_template,
1762 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001763};
1764
1765static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001766show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1767{
1768 struct nct6775_data *data = nct6775_update_device(dev);
1769 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1770 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001771
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001772 return sprintf(buf, "%d\n", data->rpm[nr]);
1773}
1774
1775static ssize_t
1776show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1777{
1778 struct nct6775_data *data = nct6775_update_device(dev);
1779 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1780 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001781
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001782 return sprintf(buf, "%d\n",
1783 data->fan_from_reg_min(data->fan_min[nr],
1784 data->fan_div[nr]));
1785}
1786
1787static ssize_t
1788show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1789{
1790 struct nct6775_data *data = nct6775_update_device(dev);
1791 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1792 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001793
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001794 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1795}
1796
1797static ssize_t
1798store_fan_min(struct device *dev, struct device_attribute *attr,
1799 const char *buf, size_t count)
1800{
1801 struct nct6775_data *data = dev_get_drvdata(dev);
1802 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1803 int nr = sattr->index;
1804 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001805 unsigned int reg;
1806 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001807 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001808
1809 err = kstrtoul(buf, 10, &val);
1810 if (err < 0)
1811 return err;
1812
1813 mutex_lock(&data->update_lock);
1814 if (!data->has_fan_div) {
1815 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1816 if (!val) {
1817 val = 0xff1f;
1818 } else {
1819 if (val > 1350000U)
1820 val = 135000U;
1821 val = 1350000U / val;
1822 val = (val & 0x1f) | ((val << 3) & 0xff00);
1823 }
1824 data->fan_min[nr] = val;
1825 goto write_min; /* Leave fan divider alone */
1826 }
1827 if (!val) {
1828 /* No min limit, alarm disabled */
1829 data->fan_min[nr] = 255;
1830 new_div = data->fan_div[nr]; /* No change */
1831 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1832 goto write_div;
1833 }
1834 reg = 1350000U / val;
1835 if (reg >= 128 * 255) {
1836 /*
1837 * Speed below this value cannot possibly be represented,
1838 * even with the highest divider (128)
1839 */
1840 data->fan_min[nr] = 254;
1841 new_div = 7; /* 128 == (1 << 7) */
1842 dev_warn(dev,
1843 "fan%u low limit %lu below minimum %u, set to minimum\n",
1844 nr + 1, val, data->fan_from_reg_min(254, 7));
1845 } else if (!reg) {
1846 /*
1847 * Speed above this value cannot possibly be represented,
1848 * even with the lowest divider (1)
1849 */
1850 data->fan_min[nr] = 1;
1851 new_div = 0; /* 1 == (1 << 0) */
1852 dev_warn(dev,
1853 "fan%u low limit %lu above maximum %u, set to maximum\n",
1854 nr + 1, val, data->fan_from_reg_min(1, 0));
1855 } else {
1856 /*
1857 * Automatically pick the best divider, i.e. the one such
1858 * that the min limit will correspond to a register value
1859 * in the 96..192 range
1860 */
1861 new_div = 0;
1862 while (reg > 192 && new_div < 7) {
1863 reg >>= 1;
1864 new_div++;
1865 }
1866 data->fan_min[nr] = reg;
1867 }
1868
1869write_div:
1870 /*
1871 * Write both the fan clock divider (if it changed) and the new
1872 * fan min (unconditionally)
1873 */
1874 if (new_div != data->fan_div[nr]) {
1875 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1876 nr + 1, div_from_reg(data->fan_div[nr]),
1877 div_from_reg(new_div));
1878 data->fan_div[nr] = new_div;
1879 nct6775_write_fan_div_common(data, nr);
1880 /* Give the chip time to sample a new speed value */
1881 data->last_updated = jiffies;
1882 }
1883
1884write_min:
1885 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1886 mutex_unlock(&data->update_lock);
1887
1888 return count;
1889}
1890
Guenter Roeck5c25d952012-12-11 07:29:06 -08001891static ssize_t
1892show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1893{
1894 struct nct6775_data *data = nct6775_update_device(dev);
1895 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1896 int p = data->fan_pulses[sattr->index];
1897
1898 return sprintf(buf, "%d\n", p ? : 4);
1899}
1900
1901static ssize_t
1902store_fan_pulses(struct device *dev, struct device_attribute *attr,
1903 const char *buf, size_t count)
1904{
1905 struct nct6775_data *data = dev_get_drvdata(dev);
1906 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1907 int nr = sattr->index;
1908 unsigned long val;
1909 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001910 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001911
1912 err = kstrtoul(buf, 10, &val);
1913 if (err < 0)
1914 return err;
1915
1916 if (val > 4)
1917 return -EINVAL;
1918
1919 mutex_lock(&data->update_lock);
1920 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001921 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1922 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1923 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1924 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001925 mutex_unlock(&data->update_lock);
1926
1927 return count;
1928}
1929
Guenter Roeckf73cf632013-03-18 09:22:50 -07001930static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1931 struct attribute *attr, int index)
1932{
1933 struct device *dev = container_of(kobj, struct device, kobj);
1934 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001935 int fan = index / 6; /* fan index */
1936 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001937
1938 if (!(data->has_fan & (1 << fan)))
1939 return 0;
1940
1941 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1942 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001943 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001944 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001945 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1946 return 0;
1947 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001948 return 0;
1949
1950 return attr->mode;
1951}
1952
1953SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1954SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1955 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001956SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1957 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001958SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1959 store_fan_pulses, 0);
1960SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1961 store_fan_min, 0);
1962SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1963
1964/*
1965 * nct6775_fan_is_visible uses the index into the following array
1966 * to determine if attributes should be created or not.
1967 * Any change in order or content must be matched.
1968 */
1969static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1970 &sensor_dev_template_fan_input,
1971 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001972 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001973 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001974 &sensor_dev_template_fan_min, /* 4 */
1975 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001976 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001977};
1978
Guenter Roeckf73cf632013-03-18 09:22:50 -07001979static struct sensor_template_group nct6775_fan_template_group = {
1980 .templates = nct6775_attributes_fan_template,
1981 .is_visible = nct6775_fan_is_visible,
1982 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001983};
1984
1985static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001986show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1987{
1988 struct nct6775_data *data = nct6775_update_device(dev);
1989 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1990 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001991
Guenter Roeckaa136e52012-12-04 03:26:05 -08001992 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1993}
1994
1995static ssize_t
1996show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1997{
1998 struct nct6775_data *data = nct6775_update_device(dev);
1999 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2000 int nr = sattr->nr;
2001 int index = sattr->index;
2002
2003 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2004}
2005
2006static ssize_t
2007store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2008 size_t count)
2009{
2010 struct nct6775_data *data = dev_get_drvdata(dev);
2011 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2012 int nr = sattr->nr;
2013 int index = sattr->index;
2014 int err;
2015 long val;
2016
2017 err = kstrtol(buf, 10, &val);
2018 if (err < 0)
2019 return err;
2020
2021 mutex_lock(&data->update_lock);
2022 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2023 nct6775_write_temp(data, data->reg_temp[index][nr],
2024 data->temp[index][nr]);
2025 mutex_unlock(&data->update_lock);
2026 return count;
2027}
2028
2029static ssize_t
2030show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2031{
2032 struct nct6775_data *data = nct6775_update_device(dev);
2033 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2034
2035 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2036}
2037
2038static ssize_t
2039store_temp_offset(struct device *dev, struct device_attribute *attr,
2040 const char *buf, size_t count)
2041{
2042 struct nct6775_data *data = dev_get_drvdata(dev);
2043 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2044 int nr = sattr->index;
2045 long val;
2046 int err;
2047
2048 err = kstrtol(buf, 10, &val);
2049 if (err < 0)
2050 return err;
2051
2052 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2053
2054 mutex_lock(&data->update_lock);
2055 data->temp_offset[nr] = val;
2056 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2057 mutex_unlock(&data->update_lock);
2058
2059 return count;
2060}
2061
2062static ssize_t
2063show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2064{
2065 struct nct6775_data *data = nct6775_update_device(dev);
2066 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2067 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002068
Guenter Roeckaa136e52012-12-04 03:26:05 -08002069 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2070}
2071
2072static ssize_t
2073store_temp_type(struct device *dev, struct device_attribute *attr,
2074 const char *buf, size_t count)
2075{
2076 struct nct6775_data *data = nct6775_update_device(dev);
2077 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2078 int nr = sattr->index;
2079 unsigned long val;
2080 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002081 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002082
2083 err = kstrtoul(buf, 10, &val);
2084 if (err < 0)
2085 return err;
2086
2087 if (val != 1 && val != 3 && val != 4)
2088 return -EINVAL;
2089
2090 mutex_lock(&data->update_lock);
2091
2092 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002093 vbit = 0x02 << nr;
2094 dbit = data->DIODE_MASK << nr;
2095 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2096 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002097 switch (val) {
2098 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002099 vbat |= vbit;
2100 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002101 break;
2102 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002103 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002104 break;
2105 case 4: /* thermistor */
2106 break;
2107 }
2108 nct6775_write_value(data, data->REG_VBAT, vbat);
2109 nct6775_write_value(data, data->REG_DIODE, diode);
2110
2111 mutex_unlock(&data->update_lock);
2112 return count;
2113}
2114
Guenter Roeckf73cf632013-03-18 09:22:50 -07002115static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2116 struct attribute *attr, int index)
2117{
2118 struct device *dev = container_of(kobj, struct device, kobj);
2119 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002120 int temp = index / 10; /* temp index */
2121 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002122
2123 if (!(data->have_temp & (1 << temp)))
2124 return 0;
2125
2126 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2127 return 0; /* alarm */
2128
Guenter Roeck30846992013-06-24 22:21:59 -07002129 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2130 return 0; /* beep */
2131
2132 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002133 return 0;
2134
Guenter Roeck30846992013-06-24 22:21:59 -07002135 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002136 return 0;
2137
Guenter Roeck30846992013-06-24 22:21:59 -07002138 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002139 return 0;
2140
Guenter Roeck30846992013-06-24 22:21:59 -07002141 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002142 return 0;
2143
2144 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002145 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002146 return 0;
2147
2148 return attr->mode;
2149}
2150
2151SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2152SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2153SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2154 store_temp, 0, 1);
2155SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2156 show_temp, store_temp, 0, 2);
2157SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2158 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002159SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2160 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002161SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2162 show_temp_offset, store_temp_offset, 0);
2163SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2164 store_temp_type, 0);
2165SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002166SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2167 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002168
2169/*
2170 * nct6775_temp_is_visible uses the index into the following array
2171 * to determine if attributes should be created or not.
2172 * Any change in order or content must be matched.
2173 */
2174static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2175 &sensor_dev_template_temp_input,
2176 &sensor_dev_template_temp_label,
2177 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002178 &sensor_dev_template_temp_beep, /* 3 */
2179 &sensor_dev_template_temp_max, /* 4 */
2180 &sensor_dev_template_temp_max_hyst, /* 5 */
2181 &sensor_dev_template_temp_crit, /* 6 */
2182 &sensor_dev_template_temp_lcrit, /* 7 */
2183 &sensor_dev_template_temp_offset, /* 8 */
2184 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002185 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002186};
2187
Guenter Roeckf73cf632013-03-18 09:22:50 -07002188static struct sensor_template_group nct6775_temp_template_group = {
2189 .templates = nct6775_attributes_temp_template,
2190 .is_visible = nct6775_temp_is_visible,
2191 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002192};
2193
Guenter Roeckaa136e52012-12-04 03:26:05 -08002194static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002195show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2196{
2197 struct nct6775_data *data = nct6775_update_device(dev);
2198 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2199
2200 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2201}
2202
2203static ssize_t
2204store_pwm_mode(struct device *dev, struct device_attribute *attr,
2205 const char *buf, size_t count)
2206{
2207 struct nct6775_data *data = dev_get_drvdata(dev);
2208 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2209 int nr = sattr->index;
2210 unsigned long val;
2211 int err;
2212 u8 reg;
2213
2214 err = kstrtoul(buf, 10, &val);
2215 if (err < 0)
2216 return err;
2217
2218 if (val > 1)
2219 return -EINVAL;
2220
2221 /* Setting DC mode is not supported for all chips/channels */
2222 if (data->REG_PWM_MODE[nr] == 0) {
2223 if (val)
2224 return -EINVAL;
2225 return count;
2226 }
2227
2228 mutex_lock(&data->update_lock);
2229 data->pwm_mode[nr] = val;
2230 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2231 reg &= ~data->PWM_MODE_MASK[nr];
2232 if (val)
2233 reg |= data->PWM_MODE_MASK[nr];
2234 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2235 mutex_unlock(&data->update_lock);
2236 return count;
2237}
2238
2239static ssize_t
2240show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2241{
2242 struct nct6775_data *data = nct6775_update_device(dev);
2243 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2244 int nr = sattr->nr;
2245 int index = sattr->index;
2246 int pwm;
2247
2248 /*
2249 * For automatic fan control modes, show current pwm readings.
2250 * Otherwise, show the configured value.
2251 */
2252 if (index == 0 && data->pwm_enable[nr] > manual)
2253 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2254 else
2255 pwm = data->pwm[index][nr];
2256
2257 return sprintf(buf, "%d\n", pwm);
2258}
2259
2260static ssize_t
2261store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2262 size_t count)
2263{
2264 struct nct6775_data *data = dev_get_drvdata(dev);
2265 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2266 int nr = sattr->nr;
2267 int index = sattr->index;
2268 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002269 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2270 int maxval[7]
2271 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002272 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002273 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002274
2275 err = kstrtoul(buf, 10, &val);
2276 if (err < 0)
2277 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002278 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002279
2280 mutex_lock(&data->update_lock);
2281 data->pwm[index][nr] = val;
2282 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002283 if (index == 2) { /* floor: disable if val == 0 */
2284 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2285 reg &= 0x7f;
2286 if (val)
2287 reg |= 0x80;
2288 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2289 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002290 mutex_unlock(&data->update_lock);
2291 return count;
2292}
2293
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002294/* Returns 0 if OK, -EINVAL otherwise */
2295static int check_trip_points(struct nct6775_data *data, int nr)
2296{
2297 int i;
2298
2299 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2300 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2301 return -EINVAL;
2302 }
2303 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2304 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2305 return -EINVAL;
2306 }
2307 /* validate critical temperature and pwm if enabled (pwm > 0) */
2308 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2309 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2310 data->auto_temp[nr][data->auto_pwm_num] ||
2311 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2312 data->auto_pwm[nr][data->auto_pwm_num])
2313 return -EINVAL;
2314 }
2315 return 0;
2316}
2317
2318static void pwm_update_registers(struct nct6775_data *data, int nr)
2319{
2320 u8 reg;
2321
2322 switch (data->pwm_enable[nr]) {
2323 case off:
2324 case manual:
2325 break;
2326 case speed_cruise:
2327 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2328 reg = (reg & ~data->tolerance_mask) |
2329 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2330 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2331 nct6775_write_value(data, data->REG_TARGET[nr],
2332 data->target_speed[nr] & 0xff);
2333 if (data->REG_TOLERANCE_H) {
2334 reg = (data->target_speed[nr] >> 8) & 0x0f;
2335 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2336 nct6775_write_value(data,
2337 data->REG_TOLERANCE_H[nr],
2338 reg);
2339 }
2340 break;
2341 case thermal_cruise:
2342 nct6775_write_value(data, data->REG_TARGET[nr],
2343 data->target_temp[nr]);
2344 /* intentional */
2345 default:
2346 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2347 reg = (reg & ~data->tolerance_mask) |
2348 data->temp_tolerance[0][nr];
2349 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2350 break;
2351 }
2352}
2353
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002354static ssize_t
2355show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2356{
2357 struct nct6775_data *data = nct6775_update_device(dev);
2358 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2359
2360 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2361}
2362
2363static ssize_t
2364store_pwm_enable(struct device *dev, struct device_attribute *attr,
2365 const char *buf, size_t count)
2366{
2367 struct nct6775_data *data = dev_get_drvdata(dev);
2368 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2369 int nr = sattr->index;
2370 unsigned long val;
2371 int err;
2372 u16 reg;
2373
2374 err = kstrtoul(buf, 10, &val);
2375 if (err < 0)
2376 return err;
2377
2378 if (val > sf4)
2379 return -EINVAL;
2380
2381 if (val == sf3 && data->kind != nct6775)
2382 return -EINVAL;
2383
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002384 if (val == sf4 && check_trip_points(data, nr)) {
2385 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2386 dev_err(dev, "Adjust trip points and try again\n");
2387 return -EINVAL;
2388 }
2389
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002390 mutex_lock(&data->update_lock);
2391 data->pwm_enable[nr] = val;
2392 if (val == off) {
2393 /*
2394 * turn off pwm control: select manual mode, set pwm to maximum
2395 */
2396 data->pwm[0][nr] = 255;
2397 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2398 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002399 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002400 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2401 reg &= 0x0f;
2402 reg |= pwm_enable_to_reg(val) << 4;
2403 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2404 mutex_unlock(&data->update_lock);
2405 return count;
2406}
2407
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002408static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002409show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002410{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002411 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002412
2413 for (i = 0; i < NUM_TEMP; i++) {
2414 if (!(data->have_temp & (1 << i)))
2415 continue;
2416 if (src == data->temp_src[i]) {
2417 sel = i + 1;
2418 break;
2419 }
2420 }
2421
2422 return sprintf(buf, "%d\n", sel);
2423}
2424
2425static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002426show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2427{
2428 struct nct6775_data *data = nct6775_update_device(dev);
2429 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2430 int index = sattr->index;
2431
2432 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2433}
2434
2435static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002436store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2437 const char *buf, size_t count)
2438{
2439 struct nct6775_data *data = nct6775_update_device(dev);
2440 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2441 int nr = sattr->index;
2442 unsigned long val;
2443 int err, reg, src;
2444
2445 err = kstrtoul(buf, 10, &val);
2446 if (err < 0)
2447 return err;
2448 if (val == 0 || val > NUM_TEMP)
2449 return -EINVAL;
2450 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2451 return -EINVAL;
2452
2453 mutex_lock(&data->update_lock);
2454 src = data->temp_src[val - 1];
2455 data->pwm_temp_sel[nr] = src;
2456 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2457 reg &= 0xe0;
2458 reg |= src;
2459 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2460 mutex_unlock(&data->update_lock);
2461
2462 return count;
2463}
2464
2465static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002466show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2467 char *buf)
2468{
2469 struct nct6775_data *data = nct6775_update_device(dev);
2470 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2471 int index = sattr->index;
2472
2473 return show_pwm_temp_sel_common(data, buf,
2474 data->pwm_weight_temp_sel[index]);
2475}
2476
2477static ssize_t
2478store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2479 const char *buf, size_t count)
2480{
2481 struct nct6775_data *data = nct6775_update_device(dev);
2482 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2483 int nr = sattr->index;
2484 unsigned long val;
2485 int err, reg, src;
2486
2487 err = kstrtoul(buf, 10, &val);
2488 if (err < 0)
2489 return err;
2490 if (val > NUM_TEMP)
2491 return -EINVAL;
2492 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2493 !data->temp_src[val - 1]))
2494 return -EINVAL;
2495
2496 mutex_lock(&data->update_lock);
2497 if (val) {
2498 src = data->temp_src[val - 1];
2499 data->pwm_weight_temp_sel[nr] = src;
2500 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2501 reg &= 0xe0;
2502 reg |= (src | 0x80);
2503 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2504 } else {
2505 data->pwm_weight_temp_sel[nr] = 0;
2506 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2507 reg &= 0x7f;
2508 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2509 }
2510 mutex_unlock(&data->update_lock);
2511
2512 return count;
2513}
2514
2515static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002516show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2517{
2518 struct nct6775_data *data = nct6775_update_device(dev);
2519 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2520
2521 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2522}
2523
2524static ssize_t
2525store_target_temp(struct device *dev, struct device_attribute *attr,
2526 const char *buf, size_t count)
2527{
2528 struct nct6775_data *data = dev_get_drvdata(dev);
2529 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2530 int nr = sattr->index;
2531 unsigned long val;
2532 int err;
2533
2534 err = kstrtoul(buf, 10, &val);
2535 if (err < 0)
2536 return err;
2537
2538 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2539 data->target_temp_mask);
2540
2541 mutex_lock(&data->update_lock);
2542 data->target_temp[nr] = val;
2543 pwm_update_registers(data, nr);
2544 mutex_unlock(&data->update_lock);
2545 return count;
2546}
2547
2548static ssize_t
2549show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2550{
2551 struct nct6775_data *data = nct6775_update_device(dev);
2552 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2553 int nr = sattr->index;
2554
2555 return sprintf(buf, "%d\n",
2556 fan_from_reg16(data->target_speed[nr],
2557 data->fan_div[nr]));
2558}
2559
2560static ssize_t
2561store_target_speed(struct device *dev, struct device_attribute *attr,
2562 const char *buf, size_t count)
2563{
2564 struct nct6775_data *data = dev_get_drvdata(dev);
2565 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2566 int nr = sattr->index;
2567 unsigned long val;
2568 int err;
2569 u16 speed;
2570
2571 err = kstrtoul(buf, 10, &val);
2572 if (err < 0)
2573 return err;
2574
2575 val = clamp_val(val, 0, 1350000U);
2576 speed = fan_to_reg(val, data->fan_div[nr]);
2577
2578 mutex_lock(&data->update_lock);
2579 data->target_speed[nr] = speed;
2580 pwm_update_registers(data, nr);
2581 mutex_unlock(&data->update_lock);
2582 return count;
2583}
2584
2585static ssize_t
2586show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2587 char *buf)
2588{
2589 struct nct6775_data *data = nct6775_update_device(dev);
2590 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2591 int nr = sattr->nr;
2592 int index = sattr->index;
2593
2594 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2595}
2596
2597static ssize_t
2598store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2599 const char *buf, size_t count)
2600{
2601 struct nct6775_data *data = dev_get_drvdata(dev);
2602 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2603 int nr = sattr->nr;
2604 int index = sattr->index;
2605 unsigned long val;
2606 int err;
2607
2608 err = kstrtoul(buf, 10, &val);
2609 if (err < 0)
2610 return err;
2611
2612 /* Limit tolerance as needed */
2613 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2614
2615 mutex_lock(&data->update_lock);
2616 data->temp_tolerance[index][nr] = val;
2617 if (index)
2618 pwm_update_registers(data, nr);
2619 else
2620 nct6775_write_value(data,
2621 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2622 val);
2623 mutex_unlock(&data->update_lock);
2624 return count;
2625}
2626
2627/*
2628 * Fan speed tolerance is a tricky beast, since the associated register is
2629 * a tick counter, but the value is reported and configured as rpm.
2630 * Compute resulting low and high rpm values and report the difference.
2631 */
2632static ssize_t
2633show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2634 char *buf)
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 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2640 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2641 int tolerance;
2642
2643 if (low <= 0)
2644 low = 1;
2645 if (high > 0xffff)
2646 high = 0xffff;
2647 if (high < low)
2648 high = low;
2649
2650 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2651 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2652
2653 return sprintf(buf, "%d\n", tolerance);
2654}
2655
2656static ssize_t
2657store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2658 const char *buf, size_t count)
2659{
2660 struct nct6775_data *data = dev_get_drvdata(dev);
2661 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2662 int nr = sattr->index;
2663 unsigned long val;
2664 int err;
2665 int low, high;
2666
2667 err = kstrtoul(buf, 10, &val);
2668 if (err < 0)
2669 return err;
2670
2671 high = fan_from_reg16(data->target_speed[nr],
2672 data->fan_div[nr]) + val;
2673 low = fan_from_reg16(data->target_speed[nr],
2674 data->fan_div[nr]) - val;
2675 if (low <= 0)
2676 low = 1;
2677 if (high < low)
2678 high = low;
2679
2680 val = (fan_to_reg(low, data->fan_div[nr]) -
2681 fan_to_reg(high, data->fan_div[nr])) / 2;
2682
2683 /* Limit tolerance as needed */
2684 val = clamp_val(val, 0, data->speed_tolerance_limit);
2685
2686 mutex_lock(&data->update_lock);
2687 data->target_speed_tolerance[nr] = val;
2688 pwm_update_registers(data, nr);
2689 mutex_unlock(&data->update_lock);
2690 return count;
2691}
2692
Guenter Roeckf73cf632013-03-18 09:22:50 -07002693SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2694SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2695 store_pwm_mode, 0);
2696SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2697 store_pwm_enable, 0);
2698SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2699 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2700SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2701 show_target_temp, store_target_temp, 0);
2702SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2703 show_target_speed, store_target_speed, 0);
2704SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2705 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002706
2707/* Smart Fan registers */
2708
2709static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002710show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2711{
2712 struct nct6775_data *data = nct6775_update_device(dev);
2713 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2714 int nr = sattr->nr;
2715 int index = sattr->index;
2716
2717 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2718}
2719
2720static ssize_t
2721store_weight_temp(struct device *dev, struct device_attribute *attr,
2722 const char *buf, size_t count)
2723{
2724 struct nct6775_data *data = dev_get_drvdata(dev);
2725 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2726 int nr = sattr->nr;
2727 int index = sattr->index;
2728 unsigned long val;
2729 int err;
2730
2731 err = kstrtoul(buf, 10, &val);
2732 if (err < 0)
2733 return err;
2734
2735 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2736
2737 mutex_lock(&data->update_lock);
2738 data->weight_temp[index][nr] = val;
2739 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2740 mutex_unlock(&data->update_lock);
2741 return count;
2742}
2743
Guenter Roeckf73cf632013-03-18 09:22:50 -07002744SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2745 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2746SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2747 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2748SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2749 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2750SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2751 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2752SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2753 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2754SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2755 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002756
2757static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002758show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2759{
2760 struct nct6775_data *data = nct6775_update_device(dev);
2761 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2762 int nr = sattr->nr;
2763 int index = sattr->index;
2764
2765 return sprintf(buf, "%d\n",
2766 step_time_from_reg(data->fan_time[index][nr],
2767 data->pwm_mode[nr]));
2768}
2769
2770static ssize_t
2771store_fan_time(struct device *dev, struct device_attribute *attr,
2772 const char *buf, size_t count)
2773{
2774 struct nct6775_data *data = dev_get_drvdata(dev);
2775 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2776 int nr = sattr->nr;
2777 int index = sattr->index;
2778 unsigned long val;
2779 int err;
2780
2781 err = kstrtoul(buf, 10, &val);
2782 if (err < 0)
2783 return err;
2784
2785 val = step_time_to_reg(val, data->pwm_mode[nr]);
2786 mutex_lock(&data->update_lock);
2787 data->fan_time[index][nr] = val;
2788 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2789 mutex_unlock(&data->update_lock);
2790 return count;
2791}
2792
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002793static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002794show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2795{
2796 struct nct6775_data *data = nct6775_update_device(dev);
2797 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2798
2799 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2800}
2801
2802static ssize_t
2803store_auto_pwm(struct device *dev, struct device_attribute *attr,
2804 const char *buf, size_t count)
2805{
2806 struct nct6775_data *data = dev_get_drvdata(dev);
2807 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2808 int nr = sattr->nr;
2809 int point = sattr->index;
2810 unsigned long val;
2811 int err;
2812 u8 reg;
2813
2814 err = kstrtoul(buf, 10, &val);
2815 if (err < 0)
2816 return err;
2817 if (val > 255)
2818 return -EINVAL;
2819
2820 if (point == data->auto_pwm_num) {
2821 if (data->kind != nct6775 && !val)
2822 return -EINVAL;
2823 if (data->kind != nct6779 && val)
2824 val = 0xff;
2825 }
2826
2827 mutex_lock(&data->update_lock);
2828 data->auto_pwm[nr][point] = val;
2829 if (point < data->auto_pwm_num) {
2830 nct6775_write_value(data,
2831 NCT6775_AUTO_PWM(data, nr, point),
2832 data->auto_pwm[nr][point]);
2833 } else {
2834 switch (data->kind) {
2835 case nct6775:
2836 /* disable if needed (pwm == 0) */
2837 reg = nct6775_read_value(data,
2838 NCT6775_REG_CRITICAL_ENAB[nr]);
2839 if (val)
2840 reg |= 0x02;
2841 else
2842 reg &= ~0x02;
2843 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2844 reg);
2845 break;
2846 case nct6776:
2847 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002848 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002849 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002850 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002851 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002852 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002853 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002854 val);
2855 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002856 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002857 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002858 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002859 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002860 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002861 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002862 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002863 reg);
2864 break;
2865 }
2866 }
2867 mutex_unlock(&data->update_lock);
2868 return count;
2869}
2870
2871static ssize_t
2872show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2873{
2874 struct nct6775_data *data = nct6775_update_device(dev);
2875 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2876 int nr = sattr->nr;
2877 int point = sattr->index;
2878
2879 /*
2880 * We don't know for sure if the temperature is signed or unsigned.
2881 * Assume it is unsigned.
2882 */
2883 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2884}
2885
2886static ssize_t
2887store_auto_temp(struct device *dev, struct device_attribute *attr,
2888 const char *buf, size_t count)
2889{
2890 struct nct6775_data *data = dev_get_drvdata(dev);
2891 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2892 int nr = sattr->nr;
2893 int point = sattr->index;
2894 unsigned long val;
2895 int err;
2896
2897 err = kstrtoul(buf, 10, &val);
2898 if (err)
2899 return err;
2900 if (val > 255000)
2901 return -EINVAL;
2902
2903 mutex_lock(&data->update_lock);
2904 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2905 if (point < data->auto_pwm_num) {
2906 nct6775_write_value(data,
2907 NCT6775_AUTO_TEMP(data, nr, point),
2908 data->auto_temp[nr][point]);
2909 } else {
2910 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2911 data->auto_temp[nr][point]);
2912 }
2913 mutex_unlock(&data->update_lock);
2914 return count;
2915}
2916
Guenter Roeckf73cf632013-03-18 09:22:50 -07002917static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2918 struct attribute *attr, int index)
2919{
2920 struct device *dev = container_of(kobj, struct device, kobj);
2921 struct nct6775_data *data = dev_get_drvdata(dev);
2922 int pwm = index / 36; /* pwm index */
2923 int nr = index % 36; /* attribute index */
2924
2925 if (!(data->has_pwm & (1 << pwm)))
2926 return 0;
2927
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002928 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2929 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2930 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002931 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2932 return 0;
2933 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2934 return 0;
2935 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2936 return 0;
2937
2938 if (nr >= 22 && nr <= 35) { /* auto point */
2939 int api = (nr - 22) / 2; /* auto point index */
2940
2941 if (api > data->auto_pwm_num)
2942 return 0;
2943 }
2944 return attr->mode;
2945}
2946
2947SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2948 show_fan_time, store_fan_time, 0, 0);
2949SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2950 show_fan_time, store_fan_time, 0, 1);
2951SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2952 show_fan_time, store_fan_time, 0, 2);
2953SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2954 store_pwm, 0, 1);
2955SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2956 store_pwm, 0, 2);
2957SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2958 show_temp_tolerance, store_temp_tolerance, 0, 0);
2959SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2960 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2961 0, 1);
2962
2963SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2964 0, 3);
2965
2966SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2967 store_pwm, 0, 4);
2968
2969SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2970 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2971SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2972 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2973
2974SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2975 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2976SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2977 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2978
2979SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2980 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2981SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2982 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2983
2984SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2985 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2986SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2987 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2988
2989SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2990 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2991SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2992 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2993
2994SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2995 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2996SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2997 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2998
2999SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3000 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3001SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3002 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3003
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003004/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003005 * nct6775_pwm_is_visible uses the index into the following array
3006 * to determine if attributes should be created or not.
3007 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003008 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003009static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3010 &sensor_dev_template_pwm,
3011 &sensor_dev_template_pwm_mode,
3012 &sensor_dev_template_pwm_enable,
3013 &sensor_dev_template_pwm_temp_sel,
3014 &sensor_dev_template_pwm_temp_tolerance,
3015 &sensor_dev_template_pwm_crit_temp_tolerance,
3016 &sensor_dev_template_pwm_target_temp,
3017 &sensor_dev_template_fan_target,
3018 &sensor_dev_template_fan_tolerance,
3019 &sensor_dev_template_pwm_stop_time,
3020 &sensor_dev_template_pwm_step_up_time,
3021 &sensor_dev_template_pwm_step_down_time,
3022 &sensor_dev_template_pwm_start,
3023 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003024 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003025 &sensor_dev_template_pwm_weight_temp_step,
3026 &sensor_dev_template_pwm_weight_temp_step_tol,
3027 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003028 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003029 &sensor_dev_template_pwm_max, /* 19 */
3030 &sensor_dev_template_pwm_step, /* 20 */
3031 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3032 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3033 &sensor_dev_template_pwm_auto_point1_temp,
3034 &sensor_dev_template_pwm_auto_point2_pwm,
3035 &sensor_dev_template_pwm_auto_point2_temp,
3036 &sensor_dev_template_pwm_auto_point3_pwm,
3037 &sensor_dev_template_pwm_auto_point3_temp,
3038 &sensor_dev_template_pwm_auto_point4_pwm,
3039 &sensor_dev_template_pwm_auto_point4_temp,
3040 &sensor_dev_template_pwm_auto_point5_pwm,
3041 &sensor_dev_template_pwm_auto_point5_temp,
3042 &sensor_dev_template_pwm_auto_point6_pwm,
3043 &sensor_dev_template_pwm_auto_point6_temp,
3044 &sensor_dev_template_pwm_auto_point7_pwm,
3045 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003046
Guenter Roeckf73cf632013-03-18 09:22:50 -07003047 NULL
3048};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003049
Guenter Roeckf73cf632013-03-18 09:22:50 -07003050static struct sensor_template_group nct6775_pwm_template_group = {
3051 .templates = nct6775_attributes_pwm_template,
3052 .is_visible = nct6775_pwm_is_visible,
3053 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003054};
3055
3056static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003057show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3058{
3059 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003060
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003061 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3062}
3063
3064static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3065
Guenter Roecka6bd5872012-12-04 03:13:34 -08003066/* Case open detection */
3067
3068static ssize_t
3069clear_caseopen(struct device *dev, struct device_attribute *attr,
3070 const char *buf, size_t count)
3071{
3072 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003073 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3074 unsigned long val;
3075 u8 reg;
3076 int ret;
3077
3078 if (kstrtoul(buf, 10, &val) || val != 0)
3079 return -EINVAL;
3080
3081 mutex_lock(&data->update_lock);
3082
3083 /*
3084 * Use CR registers to clear caseopen status.
3085 * The CR registers are the same for all chips, and not all chips
3086 * support clearing the caseopen status through "regular" registers.
3087 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003088 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003089 if (ret) {
3090 count = ret;
3091 goto error;
3092 }
3093
Guenter Roeckdf612d52013-07-08 13:15:04 -07003094 superio_select(data->sioreg, NCT6775_LD_ACPI);
3095 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003096 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003097 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003098 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003099 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3100 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003101
3102 data->valid = false; /* Force cache refresh */
3103error:
3104 mutex_unlock(&data->update_lock);
3105 return count;
3106}
3107
Guenter Roeckf73cf632013-03-18 09:22:50 -07003108static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3109 clear_caseopen, INTRUSION_ALARM_BASE);
3110static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3111 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003112static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3113 store_beep, INTRUSION_ALARM_BASE);
3114static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3115 store_beep, INTRUSION_ALARM_BASE + 1);
3116static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3117 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003118
3119static umode_t nct6775_other_is_visible(struct kobject *kobj,
3120 struct attribute *attr, int index)
3121{
3122 struct device *dev = container_of(kobj, struct device, kobj);
3123 struct nct6775_data *data = dev_get_drvdata(dev);
3124
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003125 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003126 return 0;
3127
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003128 if (index == 1 || index == 2) {
3129 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003130 return 0;
3131 }
3132
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003133 if (index == 3 || index == 4) {
3134 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003135 return 0;
3136 }
3137
Guenter Roeckf73cf632013-03-18 09:22:50 -07003138 return attr->mode;
3139}
3140
3141/*
3142 * nct6775_other_is_visible uses the index into the following array
3143 * to determine if attributes should be created or not.
3144 * Any change in order or content must be matched.
3145 */
3146static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003147 &dev_attr_cpu0_vid.attr, /* 0 */
3148 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3149 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3150 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3151 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3152 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003153
3154 NULL
3155};
3156
3157static const struct attribute_group nct6775_group_other = {
3158 .attrs = nct6775_attributes_other,
3159 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003160};
3161
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003162static inline void nct6775_init_device(struct nct6775_data *data)
3163{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003164 int i;
3165 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003166
3167 /* Start monitoring if needed */
3168 if (data->REG_CONFIG) {
3169 tmp = nct6775_read_value(data, data->REG_CONFIG);
3170 if (!(tmp & 0x01))
3171 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3172 }
3173
Guenter Roeckaa136e52012-12-04 03:26:05 -08003174 /* Enable temperature sensors if needed */
3175 for (i = 0; i < NUM_TEMP; i++) {
3176 if (!(data->have_temp & (1 << i)))
3177 continue;
3178 if (!data->reg_temp_config[i])
3179 continue;
3180 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3181 if (tmp & 0x01)
3182 nct6775_write_value(data, data->reg_temp_config[i],
3183 tmp & 0xfe);
3184 }
3185
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003186 /* Enable VBAT monitoring if needed */
3187 tmp = nct6775_read_value(data, data->REG_VBAT);
3188 if (!(tmp & 0x01))
3189 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003190
3191 diode = nct6775_read_value(data, data->REG_DIODE);
3192
3193 for (i = 0; i < data->temp_fixed_num; i++) {
3194 if (!(data->have_temp_fixed & (1 << i)))
3195 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003196 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3197 data->temp_type[i]
3198 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003199 else /* thermistor */
3200 data->temp_type[i] = 4;
3201 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003202}
3203
Guenter Roeckf73cf632013-03-18 09:22:50 -07003204static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003205nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003206{
David Bartley578ab5f2013-06-24 22:28:28 -07003207 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3208 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003209 int sioreg = data->sioreg;
3210 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003211
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003212 /* Store SIO_REG_ENABLE for use during resume */
3213 superio_select(sioreg, NCT6775_LD_HWM);
3214 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3215
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003216 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3217 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003218 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003219
3220 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003221 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003222
3223 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003224 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003225 fan4min = false;
3226 fan5pin = false;
3227 fan6pin = false;
3228 pwm4pin = false;
3229 pwm5pin = false;
3230 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003231 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003232 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003233 const char *board_vendor, *board_name;
3234
3235 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3236 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3237
3238 if (board_name && board_vendor &&
3239 !strcmp(board_vendor, "ASRock")) {
3240 /*
3241 * Auxiliary fan monitoring is not enabled on ASRock
3242 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3243 * Observed with BIOS version 2.00.
3244 */
3245 if (!strcmp(board_name, "Z77 Pro4-M")) {
3246 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3247 data->sio_reg_enable |= 0xe0;
3248 superio_outb(sioreg, SIO_REG_ENABLE,
3249 data->sio_reg_enable);
3250 }
3251 }
3252 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003253
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003254 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003255 fan3pin = gpok;
3256 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003257 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003258
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003259 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003260 fan4pin = gpok;
3261 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003262 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003263
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003264 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003265 fan5pin = gpok;
3266 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003267 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003268
3269 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003270 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003271 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003272 pwm4pin = false;
3273 pwm5pin = false;
3274 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003275 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003276 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003277 fan3pin = !(regval & 0x80);
3278 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003279
3280 fan4pin = false;
3281 fan4min = false;
3282 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003283 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003284 pwm4pin = false;
3285 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003286 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003287 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003288 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003289
3290 fan3pin = !(regval & (1 << 5));
3291 fan4pin = !(regval & (1 << 6));
3292 fan5pin = !(regval & (1 << 7));
3293
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003294 pwm3pin = !(regval & (1 << 0));
3295 pwm4pin = !(regval & (1 << 1));
3296 pwm5pin = !(regval & (1 << 2));
3297
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003298 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003299
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003300 if (data->kind == nct6791 || data->kind == nct6792 ||
3301 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003302 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003303 fan6pin = (regval & (1 << 1));
3304 pwm6pin = (regval & (1 << 0));
3305 } else { /* NCT6779D */
3306 fan6pin = false;
3307 pwm6pin = false;
3308 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003309 }
3310
David Bartley578ab5f2013-06-24 22:28:28 -07003311 /* fan 1 and 2 (0x03) are always present */
3312 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3313 (fan5pin << 4) | (fan6pin << 5);
3314 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3315 (fan5pin << 4);
3316 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3317 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003318}
3319
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003320static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3321 int *available, int *mask)
3322{
3323 int i;
3324 u8 src;
3325
3326 for (i = 0; i < data->pwm_num && *available; i++) {
3327 int index;
3328
3329 if (!regp[i])
3330 continue;
3331 src = nct6775_read_value(data, regp[i]);
3332 src &= 0x1f;
3333 if (!src || (*mask & (1 << src)))
3334 continue;
3335 if (src >= data->temp_label_num ||
3336 !strlen(data->temp_label[src]))
3337 continue;
3338
3339 index = __ffs(*available);
3340 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3341 *available &= ~(1 << index);
3342 *mask |= 1 << src;
3343 }
3344}
3345
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003346static int nct6775_probe(struct platform_device *pdev)
3347{
3348 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003349 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003350 struct nct6775_data *data;
3351 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003352 int i, s, err = 0;
3353 int src, mask, available;
3354 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003355 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003356 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003357 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003358 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003359 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003360 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003361 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003362
3363 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3364 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3365 DRVNAME))
3366 return -EBUSY;
3367
3368 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3369 GFP_KERNEL);
3370 if (!data)
3371 return -ENOMEM;
3372
3373 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003374 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003375 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003376 mutex_init(&data->update_lock);
3377 data->name = nct6775_device_names[data->kind];
3378 data->bank = 0xff; /* Force initial bank selection */
3379 platform_set_drvdata(pdev, data);
3380
3381 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003382 case nct6106:
3383 data->in_num = 9;
3384 data->pwm_num = 3;
3385 data->auto_pwm_num = 4;
3386 data->temp_fixed_num = 3;
3387 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003388 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003389
3390 data->fan_from_reg = fan_from_reg13;
3391 data->fan_from_reg_min = fan_from_reg13;
3392
3393 data->temp_label = nct6776_temp_label;
3394 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3395
3396 data->REG_VBAT = NCT6106_REG_VBAT;
3397 data->REG_DIODE = NCT6106_REG_DIODE;
3398 data->DIODE_MASK = NCT6106_DIODE_MASK;
3399 data->REG_VIN = NCT6106_REG_IN;
3400 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3401 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3402 data->REG_TARGET = NCT6106_REG_TARGET;
3403 data->REG_FAN = NCT6106_REG_FAN;
3404 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3405 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3406 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3407 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3408 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3409 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3410 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3411 data->REG_PWM[0] = NCT6106_REG_PWM;
3412 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3413 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3414 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3415 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3416 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3417 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3418 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3419 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3420 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3421 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3422 data->REG_CRITICAL_TEMP_TOLERANCE
3423 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3424 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3425 data->CRITICAL_PWM_ENABLE_MASK
3426 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3427 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3428 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3429 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3430 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3431 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3432 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3433 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3434 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3435 data->REG_ALARM = NCT6106_REG_ALARM;
3436 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003437 data->REG_BEEP = NCT6106_REG_BEEP;
3438 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003439
3440 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003441 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003442 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003443 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003444 reg_temp_over = NCT6106_REG_TEMP_OVER;
3445 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3446 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3447 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3448 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003449 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3450 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003451
3452 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003453 case nct6775:
3454 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003455 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003456 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003457 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003458 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003459 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003460 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003461
3462 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003463 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003464
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003465 data->fan_from_reg = fan_from_reg16;
3466 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003467 data->target_temp_mask = 0x7f;
3468 data->tolerance_mask = 0x0f;
3469 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003470
Guenter Roeckaa136e52012-12-04 03:26:05 -08003471 data->temp_label = nct6775_temp_label;
3472 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3473
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003474 data->REG_CONFIG = NCT6775_REG_CONFIG;
3475 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003476 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003477 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003478 data->REG_VIN = NCT6775_REG_IN;
3479 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3480 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003481 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003482 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003483 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003484 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003485 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003486 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003487 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3488 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3489 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003490 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003491 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3492 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3493 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3494 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003495 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003496 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3497 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3498 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003499 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3500 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3501 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3502 data->REG_CRITICAL_TEMP_TOLERANCE
3503 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003504 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3505 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003506 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003507 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3508 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3509 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3510 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003511 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003512 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003513
3514 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003515 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003516 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003517 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003518 reg_temp_over = NCT6775_REG_TEMP_OVER;
3519 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3520 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3521 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3522 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3523
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003524 break;
3525 case nct6776:
3526 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003527 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003528 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003529 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003530 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003531 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003532 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003533
3534 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003535 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003536
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003537 data->fan_from_reg = fan_from_reg13;
3538 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003539 data->target_temp_mask = 0xff;
3540 data->tolerance_mask = 0x07;
3541 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003542
Guenter Roeckaa136e52012-12-04 03:26:05 -08003543 data->temp_label = nct6776_temp_label;
3544 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3545
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003546 data->REG_CONFIG = NCT6775_REG_CONFIG;
3547 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003548 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003549 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003550 data->REG_VIN = NCT6775_REG_IN;
3551 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3552 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003553 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003554 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003555 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003556 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003557 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003558 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003559 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003560 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3561 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003562 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003563 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003564 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3565 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003566 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3567 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003568 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3569 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3570 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003571 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3572 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3573 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3574 data->REG_CRITICAL_TEMP_TOLERANCE
3575 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003576 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3577 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003578 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003579 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3580 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3581 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3582 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003583 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003584 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003585
3586 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003587 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003588 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003589 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003590 reg_temp_over = NCT6775_REG_TEMP_OVER;
3591 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3592 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3593 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3594 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3595
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003596 break;
3597 case nct6779:
3598 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003599 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003600 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003601 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003602 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003603 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003604 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003605
3606 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003607 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003608
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003609 data->fan_from_reg = fan_from_reg13;
3610 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003611 data->target_temp_mask = 0xff;
3612 data->tolerance_mask = 0x07;
3613 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003614
Guenter Roeckaa136e52012-12-04 03:26:05 -08003615 data->temp_label = nct6779_temp_label;
Guenter Roeck9a383712015-08-29 15:29:25 -07003616 data->temp_label_num = NCT6779_NUM_LABELS;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003617
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003618 data->REG_CONFIG = NCT6775_REG_CONFIG;
3619 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003620 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003621 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003622 data->REG_VIN = NCT6779_REG_IN;
3623 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3624 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003625 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003626 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003627 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003628 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003629 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003630 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003631 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003632 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3633 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003634 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003635 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003636 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3637 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003638 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3639 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003640 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3641 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3642 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003643 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3644 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3645 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3646 data->REG_CRITICAL_TEMP_TOLERANCE
3647 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003648 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3649 data->CRITICAL_PWM_ENABLE_MASK
3650 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3651 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003652 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3653 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003654 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003655 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3656 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3657 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3658 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003659 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003660 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003661
3662 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003663 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003664 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003665 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003666 reg_temp_over = NCT6779_REG_TEMP_OVER;
3667 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3668 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3669 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3670 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3671
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003672 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003673 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003674 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003675 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003676 data->in_num = 15;
3677 data->pwm_num = 6;
3678 data->auto_pwm_num = 4;
3679 data->has_fan_div = false;
3680 data->temp_fixed_num = 6;
3681 data->num_temp_alarms = 2;
3682 data->num_temp_beeps = 2;
3683
3684 data->ALARM_BITS = NCT6791_ALARM_BITS;
3685 data->BEEP_BITS = NCT6779_BEEP_BITS;
3686
3687 data->fan_from_reg = fan_from_reg13;
3688 data->fan_from_reg_min = fan_from_reg13;
3689 data->target_temp_mask = 0xff;
3690 data->tolerance_mask = 0x07;
3691 data->speed_tolerance_limit = 63;
3692
3693 data->temp_label = nct6779_temp_label;
Guenter Roeck9a383712015-08-29 15:29:25 -07003694 data->temp_label_num = NCT6791_NUM_LABELS;
David Bartley578ab5f2013-06-24 22:28:28 -07003695
3696 data->REG_CONFIG = NCT6775_REG_CONFIG;
3697 data->REG_VBAT = NCT6775_REG_VBAT;
3698 data->REG_DIODE = NCT6775_REG_DIODE;
3699 data->DIODE_MASK = NCT6775_DIODE_MASK;
3700 data->REG_VIN = NCT6779_REG_IN;
3701 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3702 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3703 data->REG_TARGET = NCT6775_REG_TARGET;
3704 data->REG_FAN = NCT6779_REG_FAN;
3705 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3706 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3707 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3708 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3709 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003710 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3711 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003712 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3713 data->REG_PWM[0] = NCT6775_REG_PWM;
3714 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3715 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003716 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3717 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003718 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3719 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3720 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3721 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3722 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3723 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3724 data->REG_CRITICAL_TEMP_TOLERANCE
3725 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3726 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3727 data->CRITICAL_PWM_ENABLE_MASK
3728 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3729 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3730 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3731 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3732 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003733 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3734 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3735 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3736 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003737 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003738 if (data->kind == nct6791)
3739 data->REG_BEEP = NCT6776_REG_BEEP;
3740 else
3741 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003742
3743 reg_temp = NCT6779_REG_TEMP;
3744 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003745 if (data->kind == nct6791) {
3746 reg_temp_mon = NCT6779_REG_TEMP_MON;
3747 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3748 } else {
3749 reg_temp_mon = NCT6792_REG_TEMP_MON;
3750 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3751 }
David Bartley578ab5f2013-06-24 22:28:28 -07003752 reg_temp_over = NCT6779_REG_TEMP_OVER;
3753 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3754 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3755 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3756 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3757
3758 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003759 default:
3760 return -ENODEV;
3761 }
3762 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003763 data->have_temp = 0;
3764
3765 /*
3766 * On some boards, not all available temperature sources are monitored,
3767 * even though some of the monitoring registers are unused.
3768 * Get list of unused monitoring registers, then detect if any fan
3769 * controls are configured to use unmonitored temperature sources.
3770 * If so, assign the unmonitored temperature sources to available
3771 * monitoring registers.
3772 */
3773 mask = 0;
3774 available = 0;
3775 for (i = 0; i < num_reg_temp; i++) {
3776 if (reg_temp[i] == 0)
3777 continue;
3778
3779 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3780 if (!src || (mask & (1 << src)))
3781 available |= 1 << i;
3782
3783 mask |= 1 << src;
3784 }
3785
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003786 /*
3787 * Now find unmonitored temperature registers and enable monitoring
3788 * if additional monitoring registers are available.
3789 */
3790 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3791 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3792
Guenter Roeckaa136e52012-12-04 03:26:05 -08003793 mask = 0;
3794 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3795 for (i = 0; i < num_reg_temp; i++) {
3796 if (reg_temp[i] == 0)
3797 continue;
3798
3799 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3800 if (!src || (mask & (1 << src)))
3801 continue;
3802
3803 if (src >= data->temp_label_num ||
3804 !strlen(data->temp_label[src])) {
3805 dev_info(dev,
3806 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3807 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3808 continue;
3809 }
3810
3811 mask |= 1 << src;
3812
3813 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3814 if (src <= data->temp_fixed_num) {
3815 data->have_temp |= 1 << (src - 1);
3816 data->have_temp_fixed |= 1 << (src - 1);
3817 data->reg_temp[0][src - 1] = reg_temp[i];
3818 data->reg_temp[1][src - 1] = reg_temp_over[i];
3819 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003820 if (reg_temp_crit_h && reg_temp_crit_h[i])
3821 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3822 else if (reg_temp_crit[src - 1])
3823 data->reg_temp[3][src - 1]
3824 = reg_temp_crit[src - 1];
3825 if (reg_temp_crit_l && reg_temp_crit_l[i])
3826 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003827 data->reg_temp_config[src - 1] = reg_temp_config[i];
3828 data->temp_src[src - 1] = src;
3829 continue;
3830 }
3831
3832 if (s >= NUM_TEMP)
3833 continue;
3834
3835 /* Use dynamic index for other sources */
3836 data->have_temp |= 1 << s;
3837 data->reg_temp[0][s] = reg_temp[i];
3838 data->reg_temp[1][s] = reg_temp_over[i];
3839 data->reg_temp[2][s] = reg_temp_hyst[i];
3840 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003841 if (reg_temp_crit_h && reg_temp_crit_h[i])
3842 data->reg_temp[3][s] = reg_temp_crit_h[i];
3843 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003844 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003845 if (reg_temp_crit_l && reg_temp_crit_l[i])
3846 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003847
3848 data->temp_src[s] = src;
3849 s++;
3850 }
3851
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003852 /*
3853 * Repeat with temperatures used for fan control.
3854 * This set of registers does not support limits.
3855 */
3856 for (i = 0; i < num_reg_temp_mon; i++) {
3857 if (reg_temp_mon[i] == 0)
3858 continue;
3859
3860 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3861 if (!src || (mask & (1 << src)))
3862 continue;
3863
3864 if (src >= data->temp_label_num ||
3865 !strlen(data->temp_label[src])) {
3866 dev_info(dev,
3867 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3868 src, i, data->REG_TEMP_SEL[i],
3869 reg_temp_mon[i]);
3870 continue;
3871 }
3872
3873 mask |= 1 << src;
3874
3875 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3876 if (src <= data->temp_fixed_num) {
3877 if (data->have_temp & (1 << (src - 1)))
3878 continue;
3879 data->have_temp |= 1 << (src - 1);
3880 data->have_temp_fixed |= 1 << (src - 1);
3881 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3882 data->temp_src[src - 1] = src;
3883 continue;
3884 }
3885
3886 if (s >= NUM_TEMP)
3887 continue;
3888
3889 /* Use dynamic index for other sources */
3890 data->have_temp |= 1 << s;
3891 data->reg_temp[0][s] = reg_temp_mon[i];
3892 data->temp_src[s] = src;
3893 s++;
3894 }
3895
Guenter Roeckaa136e52012-12-04 03:26:05 -08003896#ifdef USE_ALTERNATE
3897 /*
3898 * Go through the list of alternate temp registers and enable
3899 * if possible.
3900 * The temperature is already monitored if the respective bit in <mask>
3901 * is set.
3902 */
3903 for (i = 0; i < data->temp_label_num - 1; i++) {
3904 if (!reg_temp_alternate[i])
3905 continue;
3906 if (mask & (1 << (i + 1)))
3907 continue;
3908 if (i < data->temp_fixed_num) {
3909 if (data->have_temp & (1 << i))
3910 continue;
3911 data->have_temp |= 1 << i;
3912 data->have_temp_fixed |= 1 << i;
3913 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003914 if (i < num_reg_temp) {
3915 data->reg_temp[1][i] = reg_temp_over[i];
3916 data->reg_temp[2][i] = reg_temp_hyst[i];
3917 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003918 data->temp_src[i] = i + 1;
3919 continue;
3920 }
3921
3922 if (s >= NUM_TEMP) /* Abort if no more space */
3923 break;
3924
3925 data->have_temp |= 1 << s;
3926 data->reg_temp[0][s] = reg_temp_alternate[i];
3927 data->temp_src[s] = i + 1;
3928 s++;
3929 }
3930#endif /* USE_ALTERNATE */
3931
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003932 /* Initialize the chip */
3933 nct6775_init_device(data);
3934
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003935 err = superio_enter(sio_data->sioreg);
3936 if (err)
3937 return err;
3938
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003939 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3940 switch (data->kind) {
3941 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003942 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003943 break;
3944 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003945 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003946 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003947 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003948 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003949 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003950 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003951 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003952 break;
3953 }
3954
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003955 /*
3956 * Read VID value
3957 * We can get the VID input values directly at logical device D 0xe3.
3958 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003959 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003960 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3961 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3962 data->vrm = vid_which_vrm();
3963 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003964
3965 if (fan_debounce) {
3966 u8 tmp;
3967
3968 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3969 tmp = superio_inb(sio_data->sioreg,
3970 NCT6775_REG_CR_FAN_DEBOUNCE);
3971 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003972 case nct6106:
3973 tmp |= 0xe0;
3974 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003975 case nct6775:
3976 tmp |= 0x1e;
3977 break;
3978 case nct6776:
3979 case nct6779:
3980 tmp |= 0x3e;
3981 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003982 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003983 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003984 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003985 tmp |= 0x7e;
3986 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003987 }
3988 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3989 tmp);
3990 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3991 data->name);
3992 }
3993
Guenter Roeckdf612d52013-07-08 13:15:04 -07003994 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003995
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003996 superio_exit(sio_data->sioreg);
3997
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003998 /* Read fan clock dividers immediately */
3999 nct6775_init_fan_common(dev, data);
4000
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004001 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004002 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4003 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004004 if (IS_ERR(group))
4005 return PTR_ERR(group);
4006
Axel Lin55bdee62014-07-24 08:59:34 +08004007 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004008
Guenter Roeckf73cf632013-03-18 09:22:50 -07004009 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4010 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004011 if (IS_ERR(group))
4012 return PTR_ERR(group);
4013
Axel Lin55bdee62014-07-24 08:59:34 +08004014 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004015
Guenter Roeckf73cf632013-03-18 09:22:50 -07004016 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4017 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004018 if (IS_ERR(group))
4019 return PTR_ERR(group);
4020
Axel Lin55bdee62014-07-24 08:59:34 +08004021 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004022
Guenter Roeckf73cf632013-03-18 09:22:50 -07004023 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4024 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004025 if (IS_ERR(group))
4026 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004027
Axel Lin55bdee62014-07-24 08:59:34 +08004028 data->groups[num_attr_groups++] = group;
4029 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004030
Guenter Roecka150d952013-07-11 22:55:22 -07004031 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4032 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004033 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004034}
4035
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004036static void nct6791_enable_io_mapping(int sioaddr)
4037{
4038 int val;
4039
4040 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4041 if (val & 0x10) {
4042 pr_info("Enabling hardware monitor logical device mappings.\n");
4043 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4044 val & ~0x10);
4045 }
4046}
4047
Guenter Roeck48e93182015-02-07 08:48:49 -08004048static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004049{
4050 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004051
4052 mutex_lock(&data->update_lock);
4053 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004054 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004055 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4056 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4057 }
4058 mutex_unlock(&data->update_lock);
4059
4060 return 0;
4061}
4062
Guenter Roeck48e93182015-02-07 08:48:49 -08004063static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004064{
4065 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004066 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004067 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004068 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004069
4070 mutex_lock(&data->update_lock);
4071 data->bank = 0xff; /* Force initial bank selection */
4072
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004073 err = superio_enter(sioreg);
4074 if (err)
4075 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004076
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004077 superio_select(sioreg, NCT6775_LD_HWM);
4078 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4079 if (reg != data->sio_reg_enable)
4080 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4081
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004082 if (data->kind == nct6791 || data->kind == nct6792 ||
4083 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004084 nct6791_enable_io_mapping(sioreg);
4085
4086 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004087
Guenter Roeck84d19d92012-12-04 08:01:39 -08004088 /* Restore limits */
4089 for (i = 0; i < data->in_num; i++) {
4090 if (!(data->have_in & (1 << i)))
4091 continue;
4092
4093 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4094 data->in[i][1]);
4095 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4096 data->in[i][2]);
4097 }
4098
Guenter Roeckc409fd42013-04-09 05:04:00 -07004099 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004100 if (!(data->has_fan_min & (1 << i)))
4101 continue;
4102
4103 nct6775_write_value(data, data->REG_FAN_MIN[i],
4104 data->fan_min[i]);
4105 }
4106
4107 for (i = 0; i < NUM_TEMP; i++) {
4108 if (!(data->have_temp & (1 << i)))
4109 continue;
4110
Guenter Roeckc409fd42013-04-09 05:04:00 -07004111 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004112 if (data->reg_temp[j][i])
4113 nct6775_write_temp(data, data->reg_temp[j][i],
4114 data->temp[j][i]);
4115 }
4116
4117 /* Restore other settings */
4118 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004119 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004120 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4121 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4122 }
4123
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004124abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004125 /* Force re-reading all values */
4126 data->valid = false;
4127 mutex_unlock(&data->update_lock);
4128
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004129 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004130}
4131
Guenter Roeck48e93182015-02-07 08:48:49 -08004132static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004133
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004134static struct platform_driver nct6775_driver = {
4135 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004136 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004137 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004138 },
4139 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004140};
4141
4142/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004143static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004144{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004145 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004146 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004147 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004148
4149 err = superio_enter(sioaddr);
4150 if (err)
4151 return err;
4152
4153 if (force_id)
4154 val = force_id;
4155 else
4156 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4157 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4158 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004159 case SIO_NCT6106_ID:
4160 sio_data->kind = nct6106;
4161 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004162 case SIO_NCT6775_ID:
4163 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004164 break;
4165 case SIO_NCT6776_ID:
4166 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004167 break;
4168 case SIO_NCT6779_ID:
4169 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004170 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004171 case SIO_NCT6791_ID:
4172 sio_data->kind = nct6791;
4173 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004174 case SIO_NCT6792_ID:
4175 sio_data->kind = nct6792;
4176 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004177 case SIO_NCT6793_ID:
4178 sio_data->kind = nct6793;
4179 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004180 default:
4181 if (val != 0xffff)
4182 pr_debug("unsupported chip ID: 0x%04x\n", val);
4183 superio_exit(sioaddr);
4184 return -ENODEV;
4185 }
4186
4187 /* We have a known chip, find the HWM I/O address */
4188 superio_select(sioaddr, NCT6775_LD_HWM);
4189 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4190 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004191 addr = val & IOREGION_ALIGNMENT;
4192 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004193 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4194 superio_exit(sioaddr);
4195 return -ENODEV;
4196 }
4197
4198 /* Activate logical device if needed */
4199 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4200 if (!(val & 0x01)) {
4201 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4202 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4203 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004204
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004205 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4206 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004207 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004208
4209 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004210 pr_info("Found %s or compatible chip at %#x:%#x\n",
4211 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004212 sio_data->sioreg = sioaddr;
4213
Guenter Roeck698a7c22013-04-05 07:35:25 -07004214 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004215}
4216
4217/*
4218 * when Super-I/O functions move to a separate file, the Super-I/O
4219 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004220 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004221 * must keep track of the device
4222 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004223static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004224
4225static int __init sensors_nct6775_init(void)
4226{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004227 int i, err;
4228 bool found = false;
4229 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230 struct resource res;
4231 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004232 int sioaddr[2] = { 0x2e, 0x4e };
4233
4234 err = platform_driver_register(&nct6775_driver);
4235 if (err)
4236 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004237
4238 /*
4239 * initialize sio_data->kind and sio_data->sioreg.
4240 *
4241 * when Super-I/O functions move to a separate file, the Super-I/O
4242 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4243 * nct6775 hardware monitor, and call probe()
4244 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004245 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4246 address = nct6775_find(sioaddr[i], &sio_data);
4247 if (address <= 0)
4248 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004249
Guenter Roeck698a7c22013-04-05 07:35:25 -07004250 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004251
Guenter Roeck698a7c22013-04-05 07:35:25 -07004252 pdev[i] = platform_device_alloc(DRVNAME, address);
4253 if (!pdev[i]) {
4254 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004255 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004256 }
4257
4258 err = platform_device_add_data(pdev[i], &sio_data,
4259 sizeof(struct nct6775_sio_data));
4260 if (err)
4261 goto exit_device_put;
4262
4263 memset(&res, 0, sizeof(res));
4264 res.name = DRVNAME;
4265 res.start = address + IOREGION_OFFSET;
4266 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4267 res.flags = IORESOURCE_IO;
4268
4269 err = acpi_check_resource_conflict(&res);
4270 if (err) {
4271 platform_device_put(pdev[i]);
4272 pdev[i] = NULL;
4273 continue;
4274 }
4275
4276 err = platform_device_add_resources(pdev[i], &res, 1);
4277 if (err)
4278 goto exit_device_put;
4279
4280 /* platform_device_add calls probe() */
4281 err = platform_device_add(pdev[i]);
4282 if (err)
4283 goto exit_device_put;
4284 }
4285 if (!found) {
4286 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004287 goto exit_unregister;
4288 }
4289
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004290 return 0;
4291
4292exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004293 platform_device_put(pdev[i]);
4294exit_device_unregister:
4295 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004296 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004297 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004298 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004299exit_unregister:
4300 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004301 return err;
4302}
4303
4304static void __exit sensors_nct6775_exit(void)
4305{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004306 int i;
4307
4308 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4309 if (pdev[i])
4310 platform_device_unregister(pdev[i]);
4311 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004312 platform_driver_unregister(&nct6775_driver);
4313}
4314
4315MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004316MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004317MODULE_LICENSE("GPL");
4318
4319module_init(sensors_nct6775_init);
4320module_exit(sensors_nct6775_exit);