blob: 8b4fa55e46c6afceb3895515bc0df0cb3b8a4b85 [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",
518 "BYTE_TEMP"
519};
520
521static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
522 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
523 0, 0, 0, 0, 0, 0, 0, 0,
524 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
525 0x408, 0 };
526
527static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
528 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
529
David Bartley578ab5f2013-06-24 22:28:28 -0700530/* NCT6791 specific data */
531
532#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
533
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800534static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
535static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
536static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
537static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
538static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
539static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
540
David Bartley578ab5f2013-06-24 22:28:28 -0700541static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
542 0x459, 0x45A, 0x45B, 0x568, 0x45D };
543
544static const s8 NCT6791_ALARM_BITS[] = {
545 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
546 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
547 -1, /* unused */
548 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
549 -1, -1, /* unused */
550 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
551 12, 9 }; /* intrusion0, intrusion1 */
552
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700553/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800554
555static const u16 NCT6792_REG_TEMP_MON[] = {
556 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
557static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
558 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700559
Guenter Roeck6c009502012-07-01 08:23:15 -0700560/* NCT6102D/NCT6106D specific data */
561
562#define NCT6106_REG_VBAT 0x318
563#define NCT6106_REG_DIODE 0x319
564#define NCT6106_DIODE_MASK 0x01
565
566static const u16 NCT6106_REG_IN_MAX[] = {
567 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
568static const u16 NCT6106_REG_IN_MIN[] = {
569 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
570static const u16 NCT6106_REG_IN[] = {
571 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
572
573static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800574static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700575static const u16 NCT6106_REG_TEMP_HYST[] = {
576 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
577static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700578 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
579static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
580 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
581static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
582 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700583static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
584static const u16 NCT6106_REG_TEMP_CONFIG[] = {
585 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
586
587static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
588static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
589static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
590static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
591
592static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
593static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
594static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
595static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
596static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
597static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
598static const u16 NCT6106_REG_TEMP_SOURCE[] = {
599 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
600
601static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
602static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
603 0x11b, 0x12b, 0x13b };
604
605static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
606#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
607static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
608
609static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
610static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
611static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
612static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
613static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
614static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
615
616static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
617
618static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
619static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
620static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
621static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
622static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
623static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
624
625static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
626static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
627
628static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
629 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
630
631static const s8 NCT6106_ALARM_BITS[] = {
632 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
633 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
634 -1, /* unused */
635 32, 33, 34, -1, -1, /* fan1..fan5 */
636 -1, -1, -1, /* unused */
637 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
638 48, -1 /* intrusion0, intrusion1 */
639};
640
Guenter Roeck30846992013-06-24 22:21:59 -0700641static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
642 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
643
644static const s8 NCT6106_BEEP_BITS[] = {
645 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
646 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
647 32, /* global beep enable */
648 24, 25, 26, 27, 28, /* fan1..fan5 */
649 -1, -1, -1, /* unused */
650 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
651 34, -1 /* intrusion0, intrusion1 */
652};
653
Guenter Roeck6c009502012-07-01 08:23:15 -0700654static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
655 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
656
657static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
658 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
659
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800660static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
661{
662 if (mode == 0 && pwm == 255)
663 return off;
664 return mode + 1;
665}
666
667static int pwm_enable_to_reg(enum pwm_enable mode)
668{
669 if (mode == off)
670 return 0;
671 return mode - 1;
672}
673
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700674/*
675 * Conversions
676 */
677
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800678/* 1 is DC mode, output in ms */
679static unsigned int step_time_from_reg(u8 reg, u8 mode)
680{
681 return mode ? 400 * reg : 100 * reg;
682}
683
684static u8 step_time_to_reg(unsigned int msec, u8 mode)
685{
686 return clamp_val((mode ? (msec + 200) / 400 :
687 (msec + 50) / 100), 1, 255);
688}
689
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800690static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
691{
692 if (reg == 0 || reg == 255)
693 return 0;
694 return 1350000U / (reg << divreg);
695}
696
697static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
698{
699 if ((reg & 0xff1f) == 0xff1f)
700 return 0;
701
702 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
703
704 if (reg == 0)
705 return 0;
706
707 return 1350000U / reg;
708}
709
710static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
711{
712 if (reg == 0 || reg == 0xffff)
713 return 0;
714
715 /*
716 * Even though the registers are 16 bit wide, the fan divisor
717 * still applies.
718 */
719 return 1350000U / (reg << divreg);
720}
721
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800722static u16 fan_to_reg(u32 fan, unsigned int divreg)
723{
724 if (!fan)
725 return 0;
726
727 return (1350000U / fan) >> divreg;
728}
729
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800730static inline unsigned int
731div_from_reg(u8 reg)
732{
733 return 1 << reg;
734}
735
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700736/*
737 * Some of the voltage inputs have internal scaling, the tables below
738 * contain 8 (the ADC LSB in mV) * scaling factor * 100
739 */
740static const u16 scale_in[15] = {
741 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
742 800, 800
743};
744
745static inline long in_from_reg(u8 reg, u8 nr)
746{
747 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
748}
749
750static inline u8 in_to_reg(u32 val, u8 nr)
751{
752 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
753}
754
755/*
756 * Data structures and manipulation thereof
757 */
758
759struct nct6775_data {
760 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700761 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700762 enum kinds kind;
763 const char *name;
764
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700765 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700766
Guenter Roeckb7a61352013-04-02 22:14:06 -0700767 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
768 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800769 */
770 u8 temp_src[NUM_TEMP];
771 u16 reg_temp_config[NUM_TEMP];
772 const char * const *temp_label;
773 int temp_label_num;
774
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700775 u16 REG_CONFIG;
776 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800777 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700778 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700779
780 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700781 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700782
783 const u16 *REG_VIN;
784 const u16 *REG_IN_MINMAX[2];
785
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800786 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800787 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800788 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800789 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800790 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700791 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800792 const u16 *REG_FAN_TIME[3];
793
794 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800795
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800796 const u8 *REG_PWM_MODE;
797 const u8 *PWM_MODE_MASK;
798
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800799 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
800 * [3]=pwm_max, [4]=pwm_step,
801 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800802 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800803 const u16 *REG_PWM_READ;
804
Guenter Roeck6c009502012-07-01 08:23:15 -0700805 const u16 *REG_CRITICAL_PWM_ENABLE;
806 u8 CRITICAL_PWM_ENABLE_MASK;
807 const u16 *REG_CRITICAL_PWM;
808
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800809 const u16 *REG_AUTO_TEMP;
810 const u16 *REG_AUTO_PWM;
811
812 const u16 *REG_CRITICAL_TEMP;
813 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
814
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800815 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800816 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800817 const u16 *REG_WEIGHT_TEMP_SEL;
818 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
819
Guenter Roeckaa136e52012-12-04 03:26:05 -0800820 const u16 *REG_TEMP_OFFSET;
821
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700822 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700823 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700824
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800825 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
826 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
827
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700828 struct mutex update_lock;
829 bool valid; /* true if following fields are valid */
830 unsigned long last_updated; /* In jiffies */
831
832 /* Register values */
833 u8 bank; /* current register bank */
834 u8 in_num; /* number of in inputs we have */
835 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700836 unsigned int rpm[NUM_FAN];
837 u16 fan_min[NUM_FAN];
838 u8 fan_pulses[NUM_FAN];
839 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800840 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800841 u8 has_fan; /* some fan inputs can be disabled */
842 u8 has_fan_min; /* some fans don't have min register */
843 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700844
Guenter Roeck6c009502012-07-01 08:23:15 -0700845 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700846 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800847 u8 temp_fixed_num; /* 3 or 6 */
848 u8 temp_type[NUM_TEMP_FIXED];
849 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300850 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
851 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700852 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700853 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700854
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800855 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700856 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
857 * 0->PWM variable duty cycle
858 */
859 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800860 /* 0->off
861 * 1->manual
862 * 2->thermal cruise mode (also called SmartFan I)
863 * 3->fan speed cruise mode
864 * 4->SmartFan III
865 * 5->enhanced variable thermal cruise (SmartFan IV)
866 */
David Bartley578ab5f2013-06-24 22:28:28 -0700867 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
868 * [3]=pwm_max, [4]=pwm_step,
869 * [5]=weight_duty_step, [6]=weight_duty_base
870 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800871
David Bartley578ab5f2013-06-24 22:28:28 -0700872 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800873 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700874 u32 target_speed[NUM_FAN];
875 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800876 u8 speed_tolerance_limit;
877
David Bartley578ab5f2013-06-24 22:28:28 -0700878 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800879 u8 tolerance_mask;
880
David Bartley578ab5f2013-06-24 22:28:28 -0700881 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800882
883 /* Automatic fan speed control registers */
884 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700885 u8 auto_pwm[NUM_FAN][7];
886 u8 auto_temp[NUM_FAN][7];
887 u8 pwm_temp_sel[NUM_FAN];
888 u8 pwm_weight_temp_sel[NUM_FAN];
889 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
890 * 2->temp_base
891 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800892
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700893 u8 vid;
894 u8 vrm;
895
Guenter Roeckf73cf632013-03-18 09:22:50 -0700896 bool have_vid;
897
Guenter Roeckaa136e52012-12-04 03:26:05 -0800898 u16 have_temp;
899 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700900 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -0800901
Guenter Roeck84d19d92012-12-04 08:01:39 -0800902 /* Remember extra register values over suspend/resume */
903 u8 vbat;
904 u8 fandiv1;
905 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -0800906 u8 sio_reg_enable;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700907};
908
909struct nct6775_sio_data {
910 int sioreg;
911 enum kinds kind;
912};
913
Guenter Roeckf73cf632013-03-18 09:22:50 -0700914struct sensor_device_template {
915 struct device_attribute dev_attr;
916 union {
917 struct {
918 u8 nr;
919 u8 index;
920 } s;
921 int index;
922 } u;
923 bool s2; /* true if both index and nr are used */
924};
925
926struct sensor_device_attr_u {
927 union {
928 struct sensor_device_attribute a1;
929 struct sensor_device_attribute_2 a2;
930 } u;
931 char name[32];
932};
933
934#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
935 .attr = {.name = _template, .mode = _mode }, \
936 .show = _show, \
937 .store = _store, \
938}
939
940#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
941 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
942 .u.index = _index, \
943 .s2 = false }
944
945#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
946 _nr, _index) \
947 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
948 .u.s.index = _index, \
949 .u.s.nr = _nr, \
950 .s2 = true }
951
952#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
953static struct sensor_device_template sensor_dev_template_##_name \
954 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
955 _index)
956
957#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
958 _nr, _index) \
959static struct sensor_device_template sensor_dev_template_##_name \
960 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
961 _nr, _index)
962
963struct sensor_template_group {
964 struct sensor_device_template **templates;
965 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
966 int base;
967};
968
969static struct attribute_group *
970nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
971 int repeat)
972{
973 struct attribute_group *group;
974 struct sensor_device_attr_u *su;
975 struct sensor_device_attribute *a;
976 struct sensor_device_attribute_2 *a2;
977 struct attribute **attrs;
978 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300979 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700980
981 if (repeat <= 0)
982 return ERR_PTR(-EINVAL);
983
984 t = tg->templates;
985 for (count = 0; *t; t++, count++)
986 ;
987
988 if (count == 0)
989 return ERR_PTR(-EINVAL);
990
991 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
992 if (group == NULL)
993 return ERR_PTR(-ENOMEM);
994
995 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
996 GFP_KERNEL);
997 if (attrs == NULL)
998 return ERR_PTR(-ENOMEM);
999
1000 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
1001 GFP_KERNEL);
1002 if (su == NULL)
1003 return ERR_PTR(-ENOMEM);
1004
1005 group->attrs = attrs;
1006 group->is_visible = tg->is_visible;
1007
1008 for (i = 0; i < repeat; i++) {
1009 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001010 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001011 snprintf(su->name, sizeof(su->name),
1012 (*t)->dev_attr.attr.name, tg->base + i);
1013 if ((*t)->s2) {
1014 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001015 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001016 a2->dev_attr.attr.name = su->name;
1017 a2->nr = (*t)->u.s.nr + i;
1018 a2->index = (*t)->u.s.index;
1019 a2->dev_attr.attr.mode =
1020 (*t)->dev_attr.attr.mode;
1021 a2->dev_attr.show = (*t)->dev_attr.show;
1022 a2->dev_attr.store = (*t)->dev_attr.store;
1023 *attrs = &a2->dev_attr.attr;
1024 } else {
1025 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001026 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001027 a->dev_attr.attr.name = su->name;
1028 a->index = (*t)->u.index + i;
1029 a->dev_attr.attr.mode =
1030 (*t)->dev_attr.attr.mode;
1031 a->dev_attr.show = (*t)->dev_attr.show;
1032 a->dev_attr.store = (*t)->dev_attr.store;
1033 *attrs = &a->dev_attr.attr;
1034 }
1035 attrs++;
1036 su++;
1037 t++;
1038 }
1039 }
1040
Guenter Roeckf73cf632013-03-18 09:22:50 -07001041 return group;
1042}
1043
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001044static bool is_word_sized(struct nct6775_data *data, u16 reg)
1045{
1046 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001047 case nct6106:
1048 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1049 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1050 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001051 case nct6775:
1052 return (((reg & 0xff00) == 0x100 ||
1053 (reg & 0xff00) == 0x200) &&
1054 ((reg & 0x00ff) == 0x50 ||
1055 (reg & 0x00ff) == 0x53 ||
1056 (reg & 0x00ff) == 0x55)) ||
1057 (reg & 0xfff0) == 0x630 ||
1058 reg == 0x640 || reg == 0x642 ||
1059 reg == 0x662 ||
1060 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1061 reg == 0x73 || reg == 0x75 || reg == 0x77;
1062 case nct6776:
1063 return (((reg & 0xff00) == 0x100 ||
1064 (reg & 0xff00) == 0x200) &&
1065 ((reg & 0x00ff) == 0x50 ||
1066 (reg & 0x00ff) == 0x53 ||
1067 (reg & 0x00ff) == 0x55)) ||
1068 (reg & 0xfff0) == 0x630 ||
1069 reg == 0x402 ||
1070 reg == 0x640 || reg == 0x642 ||
1071 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1072 reg == 0x73 || reg == 0x75 || reg == 0x77;
1073 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001074 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001075 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001076 case nct6793:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001077 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001078 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001079 reg == 0x402 ||
1080 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1081 reg == 0x640 || reg == 0x642 ||
1082 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001083 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001084 }
1085 return false;
1086}
1087
1088/*
1089 * On older chips, only registers 0x50-0x5f are banked.
1090 * On more recent chips, all registers are banked.
1091 * Assume that is the case and set the bank number for each access.
1092 * Cache the bank number so it only needs to be set if it changes.
1093 */
1094static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1095{
1096 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001097
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001098 if (data->bank != bank) {
1099 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1100 outb_p(bank, data->addr + DATA_REG_OFFSET);
1101 data->bank = bank;
1102 }
1103}
1104
1105static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1106{
1107 int res, word_sized = is_word_sized(data, reg);
1108
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001109 nct6775_set_bank(data, reg);
1110 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1111 res = inb_p(data->addr + DATA_REG_OFFSET);
1112 if (word_sized) {
1113 outb_p((reg & 0xff) + 1,
1114 data->addr + ADDR_REG_OFFSET);
1115 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1116 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001117 return res;
1118}
1119
1120static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1121{
1122 int word_sized = is_word_sized(data, reg);
1123
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001124 nct6775_set_bank(data, reg);
1125 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1126 if (word_sized) {
1127 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1128 outb_p((reg & 0xff) + 1,
1129 data->addr + ADDR_REG_OFFSET);
1130 }
1131 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001132 return 0;
1133}
1134
Guenter Roeckaa136e52012-12-04 03:26:05 -08001135/* We left-align 8-bit temperature values to make the code simpler */
1136static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1137{
1138 u16 res;
1139
1140 res = nct6775_read_value(data, reg);
1141 if (!is_word_sized(data, reg))
1142 res <<= 8;
1143
1144 return res;
1145}
1146
1147static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1148{
1149 if (!is_word_sized(data, reg))
1150 value >>= 8;
1151 return nct6775_write_value(data, reg, value);
1152}
1153
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001154/* This function assumes that the caller holds data->update_lock */
1155static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1156{
1157 u8 reg;
1158
1159 switch (nr) {
1160 case 0:
1161 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1162 | (data->fan_div[0] & 0x7);
1163 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1164 break;
1165 case 1:
1166 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1167 | ((data->fan_div[1] << 4) & 0x70);
1168 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1169 break;
1170 case 2:
1171 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1172 | (data->fan_div[2] & 0x7);
1173 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1174 break;
1175 case 3:
1176 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1177 | ((data->fan_div[3] << 4) & 0x70);
1178 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1179 break;
1180 }
1181}
1182
1183static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1184{
1185 if (data->kind == nct6775)
1186 nct6775_write_fan_div(data, nr);
1187}
1188
1189static void nct6775_update_fan_div(struct nct6775_data *data)
1190{
1191 u8 i;
1192
1193 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1194 data->fan_div[0] = i & 0x7;
1195 data->fan_div[1] = (i & 0x70) >> 4;
1196 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1197 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001198 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001199 data->fan_div[3] = (i & 0x70) >> 4;
1200}
1201
1202static void nct6775_update_fan_div_common(struct nct6775_data *data)
1203{
1204 if (data->kind == nct6775)
1205 nct6775_update_fan_div(data);
1206}
1207
1208static void nct6775_init_fan_div(struct nct6775_data *data)
1209{
1210 int i;
1211
1212 nct6775_update_fan_div_common(data);
1213 /*
1214 * For all fans, start with highest divider value if the divider
1215 * register is not initialized. This ensures that we get a
1216 * reading from the fan count register, even if it is not optimal.
1217 * We'll compute a better divider later on.
1218 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001219 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001220 if (!(data->has_fan & (1 << i)))
1221 continue;
1222 if (data->fan_div[i] == 0) {
1223 data->fan_div[i] = 7;
1224 nct6775_write_fan_div_common(data, i);
1225 }
1226 }
1227}
1228
1229static void nct6775_init_fan_common(struct device *dev,
1230 struct nct6775_data *data)
1231{
1232 int i;
1233 u8 reg;
1234
1235 if (data->has_fan_div)
1236 nct6775_init_fan_div(data);
1237
1238 /*
1239 * If fan_min is not set (0), set it to 0xff to disable it. This
1240 * prevents the unnecessary warning when fanX_min is reported as 0.
1241 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001242 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001243 if (data->has_fan_min & (1 << i)) {
1244 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1245 if (!reg)
1246 nct6775_write_value(data, data->REG_FAN_MIN[i],
1247 data->has_fan_div ? 0xff
1248 : 0xff1f);
1249 }
1250 }
1251}
1252
1253static void nct6775_select_fan_div(struct device *dev,
1254 struct nct6775_data *data, int nr, u16 reg)
1255{
1256 u8 fan_div = data->fan_div[nr];
1257 u16 fan_min;
1258
1259 if (!data->has_fan_div)
1260 return;
1261
1262 /*
1263 * If we failed to measure the fan speed, or the reported value is not
1264 * in the optimal range, and the clock divider can be modified,
1265 * let's try that for next time.
1266 */
1267 if (reg == 0x00 && fan_div < 0x07)
1268 fan_div++;
1269 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1270 fan_div--;
1271
1272 if (fan_div != data->fan_div[nr]) {
1273 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1274 nr + 1, div_from_reg(data->fan_div[nr]),
1275 div_from_reg(fan_div));
1276
1277 /* Preserve min limit if possible */
1278 if (data->has_fan_min & (1 << nr)) {
1279 fan_min = data->fan_min[nr];
1280 if (fan_div > data->fan_div[nr]) {
1281 if (fan_min != 255 && fan_min > 1)
1282 fan_min >>= 1;
1283 } else {
1284 if (fan_min != 255) {
1285 fan_min <<= 1;
1286 if (fan_min > 254)
1287 fan_min = 254;
1288 }
1289 }
1290 if (fan_min != data->fan_min[nr]) {
1291 data->fan_min[nr] = fan_min;
1292 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1293 fan_min);
1294 }
1295 }
1296 data->fan_div[nr] = fan_div;
1297 nct6775_write_fan_div_common(data, nr);
1298 }
1299}
1300
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001301static void nct6775_update_pwm(struct device *dev)
1302{
1303 struct nct6775_data *data = dev_get_drvdata(dev);
1304 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001305 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001306 bool duty_is_dc;
1307
1308 for (i = 0; i < data->pwm_num; i++) {
1309 if (!(data->has_pwm & (1 << i)))
1310 continue;
1311
1312 duty_is_dc = data->REG_PWM_MODE[i] &&
1313 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1314 & data->PWM_MODE_MASK[i]);
1315 data->pwm_mode[i] = duty_is_dc;
1316
1317 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1318 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1319 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1320 data->pwm[j][i]
1321 = nct6775_read_value(data,
1322 data->REG_PWM[j][i]);
1323 }
1324 }
1325
1326 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1327 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001328
1329 if (!data->temp_tolerance[0][i] ||
1330 data->pwm_enable[i] != speed_cruise)
1331 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1332 if (!data->target_speed_tolerance[i] ||
1333 data->pwm_enable[i] == speed_cruise) {
1334 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001335
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001336 if (data->REG_TOLERANCE_H) {
1337 t |= (nct6775_read_value(data,
1338 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1339 }
1340 data->target_speed_tolerance[i] = t;
1341 }
1342
1343 data->temp_tolerance[1][i] =
1344 nct6775_read_value(data,
1345 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1346
1347 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1348 data->pwm_temp_sel[i] = reg & 0x1f;
1349 /* If fan can stop, report floor as 0 */
1350 if (reg & 0x80)
1351 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001352
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001353 if (!data->REG_WEIGHT_TEMP_SEL[i])
1354 continue;
1355
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001356 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1357 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1358 /* If weight is disabled, report weight source as 0 */
1359 if (j == 1 && !(reg & 0x80))
1360 data->pwm_weight_temp_sel[i] = 0;
1361
1362 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001363 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001364 data->weight_temp[j][i]
1365 = nct6775_read_value(data,
1366 data->REG_WEIGHT_TEMP[j][i]);
1367 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001368 }
1369}
1370
1371static void nct6775_update_pwm_limits(struct device *dev)
1372{
1373 struct nct6775_data *data = dev_get_drvdata(dev);
1374 int i, j;
1375 u8 reg;
1376 u16 reg_t;
1377
1378 for (i = 0; i < data->pwm_num; i++) {
1379 if (!(data->has_pwm & (1 << i)))
1380 continue;
1381
Guenter Roeckc409fd42013-04-09 05:04:00 -07001382 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001383 data->fan_time[j][i] =
1384 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1385 }
1386
1387 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1388 /* Update only in matching mode or if never updated */
1389 if (!data->target_temp[i] ||
1390 data->pwm_enable[i] == thermal_cruise)
1391 data->target_temp[i] = reg_t & data->target_temp_mask;
1392 if (!data->target_speed[i] ||
1393 data->pwm_enable[i] == speed_cruise) {
1394 if (data->REG_TOLERANCE_H) {
1395 reg_t |= (nct6775_read_value(data,
1396 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1397 }
1398 data->target_speed[i] = reg_t;
1399 }
1400
1401 for (j = 0; j < data->auto_pwm_num; j++) {
1402 data->auto_pwm[i][j] =
1403 nct6775_read_value(data,
1404 NCT6775_AUTO_PWM(data, i, j));
1405 data->auto_temp[i][j] =
1406 nct6775_read_value(data,
1407 NCT6775_AUTO_TEMP(data, i, j));
1408 }
1409
1410 /* critical auto_pwm temperature data */
1411 data->auto_temp[i][data->auto_pwm_num] =
1412 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1413
1414 switch (data->kind) {
1415 case nct6775:
1416 reg = nct6775_read_value(data,
1417 NCT6775_REG_CRITICAL_ENAB[i]);
1418 data->auto_pwm[i][data->auto_pwm_num] =
1419 (reg & 0x02) ? 0xff : 0x00;
1420 break;
1421 case nct6776:
1422 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1423 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001424 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001425 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001426 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001427 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001428 case nct6793:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001429 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001430 data->REG_CRITICAL_PWM_ENABLE[i]);
1431 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1432 reg = nct6775_read_value(data,
1433 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001434 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001435 reg = 0xff;
1436 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001437 break;
1438 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001439 }
1440}
1441
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001442static struct nct6775_data *nct6775_update_device(struct device *dev)
1443{
1444 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001445 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001446
1447 mutex_lock(&data->update_lock);
1448
Guenter Roeck6445e662013-04-21 09:13:28 -07001449 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001450 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001451 /* Fan clock dividers */
1452 nct6775_update_fan_div_common(data);
1453
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001454 /* Measured voltages and limits */
1455 for (i = 0; i < data->in_num; i++) {
1456 if (!(data->have_in & (1 << i)))
1457 continue;
1458
1459 data->in[i][0] = nct6775_read_value(data,
1460 data->REG_VIN[i]);
1461 data->in[i][1] = nct6775_read_value(data,
1462 data->REG_IN_MINMAX[0][i]);
1463 data->in[i][2] = nct6775_read_value(data,
1464 data->REG_IN_MINMAX[1][i]);
1465 }
1466
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001467 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001468 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001469 u16 reg;
1470
1471 if (!(data->has_fan & (1 << i)))
1472 continue;
1473
1474 reg = nct6775_read_value(data, data->REG_FAN[i]);
1475 data->rpm[i] = data->fan_from_reg(reg,
1476 data->fan_div[i]);
1477
1478 if (data->has_fan_min & (1 << i))
1479 data->fan_min[i] = nct6775_read_value(data,
1480 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001481 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001482 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1483 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001484
1485 nct6775_select_fan_div(dev, data, i, reg);
1486 }
1487
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001488 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001489 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001490
Guenter Roeckaa136e52012-12-04 03:26:05 -08001491 /* Measured temperatures and limits */
1492 for (i = 0; i < NUM_TEMP; i++) {
1493 if (!(data->have_temp & (1 << i)))
1494 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001495 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001496 if (data->reg_temp[j][i])
1497 data->temp[j][i]
1498 = nct6775_read_temp(data,
1499 data->reg_temp[j][i]);
1500 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001501 if (i >= NUM_TEMP_FIXED ||
1502 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001503 continue;
1504 data->temp_offset[i]
1505 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1506 }
1507
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001508 data->alarms = 0;
1509 for (i = 0; i < NUM_REG_ALARM; i++) {
1510 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001511
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001512 if (!data->REG_ALARM[i])
1513 continue;
1514 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1515 data->alarms |= ((u64)alarm) << (i << 3);
1516 }
1517
Guenter Roeck30846992013-06-24 22:21:59 -07001518 data->beeps = 0;
1519 for (i = 0; i < NUM_REG_BEEP; i++) {
1520 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001521
Guenter Roeck30846992013-06-24 22:21:59 -07001522 if (!data->REG_BEEP[i])
1523 continue;
1524 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1525 data->beeps |= ((u64)beep) << (i << 3);
1526 }
1527
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001528 data->last_updated = jiffies;
1529 data->valid = true;
1530 }
1531
1532 mutex_unlock(&data->update_lock);
1533 return data;
1534}
1535
1536/*
1537 * Sysfs callback functions
1538 */
1539static ssize_t
1540show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1541{
1542 struct nct6775_data *data = nct6775_update_device(dev);
1543 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001544 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001545 int nr = sattr->nr;
1546
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001547 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1548}
1549
1550static ssize_t
1551store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1552 size_t count)
1553{
1554 struct nct6775_data *data = dev_get_drvdata(dev);
1555 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001556 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001557 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001558 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001559 int err;
1560
1561 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001562 if (err < 0)
1563 return err;
1564 mutex_lock(&data->update_lock);
1565 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001566 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001567 data->in[nr][index]);
1568 mutex_unlock(&data->update_lock);
1569 return count;
1570}
1571
1572static ssize_t
1573show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1574{
1575 struct nct6775_data *data = nct6775_update_device(dev);
1576 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1577 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001578
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001579 return sprintf(buf, "%u\n",
1580 (unsigned int)((data->alarms >> nr) & 0x01));
1581}
1582
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001583static int find_temp_source(struct nct6775_data *data, int index, int count)
1584{
1585 int source = data->temp_src[index];
1586 int nr;
1587
1588 for (nr = 0; nr < count; nr++) {
1589 int src;
1590
1591 src = nct6775_read_value(data,
1592 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1593 if (src == source)
1594 return nr;
1595 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001596 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001597}
1598
1599static ssize_t
1600show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1601{
1602 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1603 struct nct6775_data *data = nct6775_update_device(dev);
1604 unsigned int alarm = 0;
1605 int nr;
1606
1607 /*
1608 * For temperatures, there is no fixed mapping from registers to alarm
1609 * bits. Alarm bits are determined by the temperature source mapping.
1610 */
1611 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1612 if (nr >= 0) {
1613 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001614
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001615 alarm = (data->alarms >> bit) & 0x01;
1616 }
1617 return sprintf(buf, "%u\n", alarm);
1618}
1619
Guenter Roeck30846992013-06-24 22:21:59 -07001620static ssize_t
1621show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1622{
1623 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1624 struct nct6775_data *data = nct6775_update_device(dev);
1625 int nr = data->BEEP_BITS[sattr->index];
1626
1627 return sprintf(buf, "%u\n",
1628 (unsigned int)((data->beeps >> nr) & 0x01));
1629}
1630
1631static ssize_t
1632store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1633 size_t count)
1634{
1635 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1636 struct nct6775_data *data = dev_get_drvdata(dev);
1637 int nr = data->BEEP_BITS[sattr->index];
1638 int regindex = nr >> 3;
1639 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001640 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001641
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001642 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001643 if (err < 0)
1644 return err;
1645 if (val > 1)
1646 return -EINVAL;
1647
1648 mutex_lock(&data->update_lock);
1649 if (val)
1650 data->beeps |= (1ULL << nr);
1651 else
1652 data->beeps &= ~(1ULL << nr);
1653 nct6775_write_value(data, data->REG_BEEP[regindex],
1654 (data->beeps >> (regindex << 3)) & 0xff);
1655 mutex_unlock(&data->update_lock);
1656 return count;
1657}
1658
1659static ssize_t
1660show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1661{
1662 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1663 struct nct6775_data *data = nct6775_update_device(dev);
1664 unsigned int beep = 0;
1665 int nr;
1666
1667 /*
1668 * For temperatures, there is no fixed mapping from registers to beep
1669 * enable bits. Beep enable bits are determined by the temperature
1670 * source mapping.
1671 */
1672 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1673 if (nr >= 0) {
1674 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001675
Guenter Roeck30846992013-06-24 22:21:59 -07001676 beep = (data->beeps >> bit) & 0x01;
1677 }
1678 return sprintf(buf, "%u\n", beep);
1679}
1680
1681static ssize_t
1682store_temp_beep(struct device *dev, struct device_attribute *attr,
1683 const char *buf, size_t count)
1684{
1685 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1686 struct nct6775_data *data = dev_get_drvdata(dev);
1687 int nr, bit, regindex;
1688 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001689 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001690
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001691 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001692 if (err < 0)
1693 return err;
1694 if (val > 1)
1695 return -EINVAL;
1696
1697 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1698 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001699 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001700
1701 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1702 regindex = bit >> 3;
1703
1704 mutex_lock(&data->update_lock);
1705 if (val)
1706 data->beeps |= (1ULL << bit);
1707 else
1708 data->beeps &= ~(1ULL << bit);
1709 nct6775_write_value(data, data->REG_BEEP[regindex],
1710 (data->beeps >> (regindex << 3)) & 0xff);
1711 mutex_unlock(&data->update_lock);
1712
1713 return count;
1714}
1715
Guenter Roeckf73cf632013-03-18 09:22:50 -07001716static umode_t nct6775_in_is_visible(struct kobject *kobj,
1717 struct attribute *attr, int index)
1718{
1719 struct device *dev = container_of(kobj, struct device, kobj);
1720 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001721 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001722
Guenter Roeckf73cf632013-03-18 09:22:50 -07001723 if (!(data->have_in & (1 << in)))
1724 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001725
Guenter Roeckf73cf632013-03-18 09:22:50 -07001726 return attr->mode;
1727}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001728
Guenter Roeckf73cf632013-03-18 09:22:50 -07001729SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1730SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001731SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1732 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001733SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1734 store_in_reg, 0, 1);
1735SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1736 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001737
Guenter Roeckf73cf632013-03-18 09:22:50 -07001738/*
1739 * nct6775_in_is_visible uses the index into the following array
1740 * to determine if attributes should be created or not.
1741 * Any change in order or content must be matched.
1742 */
1743static struct sensor_device_template *nct6775_attributes_in_template[] = {
1744 &sensor_dev_template_in_input,
1745 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001746 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001747 &sensor_dev_template_in_min,
1748 &sensor_dev_template_in_max,
1749 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001750};
1751
Guenter Roeckf73cf632013-03-18 09:22:50 -07001752static struct sensor_template_group nct6775_in_template_group = {
1753 .templates = nct6775_attributes_in_template,
1754 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001755};
1756
1757static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001758show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1759{
1760 struct nct6775_data *data = nct6775_update_device(dev);
1761 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1762 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001763
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001764 return sprintf(buf, "%d\n", data->rpm[nr]);
1765}
1766
1767static ssize_t
1768show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1769{
1770 struct nct6775_data *data = nct6775_update_device(dev);
1771 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1772 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001773
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001774 return sprintf(buf, "%d\n",
1775 data->fan_from_reg_min(data->fan_min[nr],
1776 data->fan_div[nr]));
1777}
1778
1779static ssize_t
1780show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1781{
1782 struct nct6775_data *data = nct6775_update_device(dev);
1783 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1784 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001785
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001786 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1787}
1788
1789static ssize_t
1790store_fan_min(struct device *dev, struct device_attribute *attr,
1791 const char *buf, size_t count)
1792{
1793 struct nct6775_data *data = dev_get_drvdata(dev);
1794 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1795 int nr = sattr->index;
1796 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001797 unsigned int reg;
1798 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001799 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001800
1801 err = kstrtoul(buf, 10, &val);
1802 if (err < 0)
1803 return err;
1804
1805 mutex_lock(&data->update_lock);
1806 if (!data->has_fan_div) {
1807 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1808 if (!val) {
1809 val = 0xff1f;
1810 } else {
1811 if (val > 1350000U)
1812 val = 135000U;
1813 val = 1350000U / val;
1814 val = (val & 0x1f) | ((val << 3) & 0xff00);
1815 }
1816 data->fan_min[nr] = val;
1817 goto write_min; /* Leave fan divider alone */
1818 }
1819 if (!val) {
1820 /* No min limit, alarm disabled */
1821 data->fan_min[nr] = 255;
1822 new_div = data->fan_div[nr]; /* No change */
1823 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1824 goto write_div;
1825 }
1826 reg = 1350000U / val;
1827 if (reg >= 128 * 255) {
1828 /*
1829 * Speed below this value cannot possibly be represented,
1830 * even with the highest divider (128)
1831 */
1832 data->fan_min[nr] = 254;
1833 new_div = 7; /* 128 == (1 << 7) */
1834 dev_warn(dev,
1835 "fan%u low limit %lu below minimum %u, set to minimum\n",
1836 nr + 1, val, data->fan_from_reg_min(254, 7));
1837 } else if (!reg) {
1838 /*
1839 * Speed above this value cannot possibly be represented,
1840 * even with the lowest divider (1)
1841 */
1842 data->fan_min[nr] = 1;
1843 new_div = 0; /* 1 == (1 << 0) */
1844 dev_warn(dev,
1845 "fan%u low limit %lu above maximum %u, set to maximum\n",
1846 nr + 1, val, data->fan_from_reg_min(1, 0));
1847 } else {
1848 /*
1849 * Automatically pick the best divider, i.e. the one such
1850 * that the min limit will correspond to a register value
1851 * in the 96..192 range
1852 */
1853 new_div = 0;
1854 while (reg > 192 && new_div < 7) {
1855 reg >>= 1;
1856 new_div++;
1857 }
1858 data->fan_min[nr] = reg;
1859 }
1860
1861write_div:
1862 /*
1863 * Write both the fan clock divider (if it changed) and the new
1864 * fan min (unconditionally)
1865 */
1866 if (new_div != data->fan_div[nr]) {
1867 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1868 nr + 1, div_from_reg(data->fan_div[nr]),
1869 div_from_reg(new_div));
1870 data->fan_div[nr] = new_div;
1871 nct6775_write_fan_div_common(data, nr);
1872 /* Give the chip time to sample a new speed value */
1873 data->last_updated = jiffies;
1874 }
1875
1876write_min:
1877 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1878 mutex_unlock(&data->update_lock);
1879
1880 return count;
1881}
1882
Guenter Roeck5c25d952012-12-11 07:29:06 -08001883static ssize_t
1884show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1885{
1886 struct nct6775_data *data = nct6775_update_device(dev);
1887 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1888 int p = data->fan_pulses[sattr->index];
1889
1890 return sprintf(buf, "%d\n", p ? : 4);
1891}
1892
1893static ssize_t
1894store_fan_pulses(struct device *dev, struct device_attribute *attr,
1895 const char *buf, size_t count)
1896{
1897 struct nct6775_data *data = dev_get_drvdata(dev);
1898 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1899 int nr = sattr->index;
1900 unsigned long val;
1901 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001902 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001903
1904 err = kstrtoul(buf, 10, &val);
1905 if (err < 0)
1906 return err;
1907
1908 if (val > 4)
1909 return -EINVAL;
1910
1911 mutex_lock(&data->update_lock);
1912 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001913 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1914 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1915 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1916 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001917 mutex_unlock(&data->update_lock);
1918
1919 return count;
1920}
1921
Guenter Roeckf73cf632013-03-18 09:22:50 -07001922static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1923 struct attribute *attr, int index)
1924{
1925 struct device *dev = container_of(kobj, struct device, kobj);
1926 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001927 int fan = index / 6; /* fan index */
1928 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001929
1930 if (!(data->has_fan & (1 << fan)))
1931 return 0;
1932
1933 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1934 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001935 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001936 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001937 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1938 return 0;
1939 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001940 return 0;
1941
1942 return attr->mode;
1943}
1944
1945SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1946SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1947 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001948SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1949 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001950SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1951 store_fan_pulses, 0);
1952SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1953 store_fan_min, 0);
1954SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1955
1956/*
1957 * nct6775_fan_is_visible uses the index into the following array
1958 * to determine if attributes should be created or not.
1959 * Any change in order or content must be matched.
1960 */
1961static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1962 &sensor_dev_template_fan_input,
1963 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001964 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001965 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001966 &sensor_dev_template_fan_min, /* 4 */
1967 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001968 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001969};
1970
Guenter Roeckf73cf632013-03-18 09:22:50 -07001971static struct sensor_template_group nct6775_fan_template_group = {
1972 .templates = nct6775_attributes_fan_template,
1973 .is_visible = nct6775_fan_is_visible,
1974 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001975};
1976
1977static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001978show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1979{
1980 struct nct6775_data *data = nct6775_update_device(dev);
1981 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1982 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001983
Guenter Roeckaa136e52012-12-04 03:26:05 -08001984 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1985}
1986
1987static ssize_t
1988show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1989{
1990 struct nct6775_data *data = nct6775_update_device(dev);
1991 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1992 int nr = sattr->nr;
1993 int index = sattr->index;
1994
1995 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1996}
1997
1998static ssize_t
1999store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2000 size_t count)
2001{
2002 struct nct6775_data *data = dev_get_drvdata(dev);
2003 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2004 int nr = sattr->nr;
2005 int index = sattr->index;
2006 int err;
2007 long val;
2008
2009 err = kstrtol(buf, 10, &val);
2010 if (err < 0)
2011 return err;
2012
2013 mutex_lock(&data->update_lock);
2014 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2015 nct6775_write_temp(data, data->reg_temp[index][nr],
2016 data->temp[index][nr]);
2017 mutex_unlock(&data->update_lock);
2018 return count;
2019}
2020
2021static ssize_t
2022show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2023{
2024 struct nct6775_data *data = nct6775_update_device(dev);
2025 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2026
2027 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2028}
2029
2030static ssize_t
2031store_temp_offset(struct device *dev, struct device_attribute *attr,
2032 const char *buf, size_t count)
2033{
2034 struct nct6775_data *data = dev_get_drvdata(dev);
2035 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2036 int nr = sattr->index;
2037 long val;
2038 int err;
2039
2040 err = kstrtol(buf, 10, &val);
2041 if (err < 0)
2042 return err;
2043
2044 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2045
2046 mutex_lock(&data->update_lock);
2047 data->temp_offset[nr] = val;
2048 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2049 mutex_unlock(&data->update_lock);
2050
2051 return count;
2052}
2053
2054static ssize_t
2055show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2056{
2057 struct nct6775_data *data = nct6775_update_device(dev);
2058 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2059 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002060
Guenter Roeckaa136e52012-12-04 03:26:05 -08002061 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2062}
2063
2064static ssize_t
2065store_temp_type(struct device *dev, struct device_attribute *attr,
2066 const char *buf, size_t count)
2067{
2068 struct nct6775_data *data = nct6775_update_device(dev);
2069 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2070 int nr = sattr->index;
2071 unsigned long val;
2072 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002073 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002074
2075 err = kstrtoul(buf, 10, &val);
2076 if (err < 0)
2077 return err;
2078
2079 if (val != 1 && val != 3 && val != 4)
2080 return -EINVAL;
2081
2082 mutex_lock(&data->update_lock);
2083
2084 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002085 vbit = 0x02 << nr;
2086 dbit = data->DIODE_MASK << nr;
2087 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2088 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002089 switch (val) {
2090 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002091 vbat |= vbit;
2092 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002093 break;
2094 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002095 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002096 break;
2097 case 4: /* thermistor */
2098 break;
2099 }
2100 nct6775_write_value(data, data->REG_VBAT, vbat);
2101 nct6775_write_value(data, data->REG_DIODE, diode);
2102
2103 mutex_unlock(&data->update_lock);
2104 return count;
2105}
2106
Guenter Roeckf73cf632013-03-18 09:22:50 -07002107static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2108 struct attribute *attr, int index)
2109{
2110 struct device *dev = container_of(kobj, struct device, kobj);
2111 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002112 int temp = index / 10; /* temp index */
2113 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002114
2115 if (!(data->have_temp & (1 << temp)))
2116 return 0;
2117
2118 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2119 return 0; /* alarm */
2120
Guenter Roeck30846992013-06-24 22:21:59 -07002121 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2122 return 0; /* beep */
2123
2124 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002125 return 0;
2126
Guenter Roeck30846992013-06-24 22:21:59 -07002127 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002128 return 0;
2129
Guenter Roeck30846992013-06-24 22:21:59 -07002130 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002131 return 0;
2132
Guenter Roeck30846992013-06-24 22:21:59 -07002133 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002134 return 0;
2135
2136 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002137 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002138 return 0;
2139
2140 return attr->mode;
2141}
2142
2143SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2144SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2145SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2146 store_temp, 0, 1);
2147SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2148 show_temp, store_temp, 0, 2);
2149SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2150 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002151SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2152 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002153SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2154 show_temp_offset, store_temp_offset, 0);
2155SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2156 store_temp_type, 0);
2157SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002158SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2159 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002160
2161/*
2162 * nct6775_temp_is_visible uses the index into the following array
2163 * to determine if attributes should be created or not.
2164 * Any change in order or content must be matched.
2165 */
2166static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2167 &sensor_dev_template_temp_input,
2168 &sensor_dev_template_temp_label,
2169 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002170 &sensor_dev_template_temp_beep, /* 3 */
2171 &sensor_dev_template_temp_max, /* 4 */
2172 &sensor_dev_template_temp_max_hyst, /* 5 */
2173 &sensor_dev_template_temp_crit, /* 6 */
2174 &sensor_dev_template_temp_lcrit, /* 7 */
2175 &sensor_dev_template_temp_offset, /* 8 */
2176 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002177 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002178};
2179
Guenter Roeckf73cf632013-03-18 09:22:50 -07002180static struct sensor_template_group nct6775_temp_template_group = {
2181 .templates = nct6775_attributes_temp_template,
2182 .is_visible = nct6775_temp_is_visible,
2183 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002184};
2185
Guenter Roeckaa136e52012-12-04 03:26:05 -08002186static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002187show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2188{
2189 struct nct6775_data *data = nct6775_update_device(dev);
2190 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2191
2192 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2193}
2194
2195static ssize_t
2196store_pwm_mode(struct device *dev, struct device_attribute *attr,
2197 const char *buf, size_t count)
2198{
2199 struct nct6775_data *data = dev_get_drvdata(dev);
2200 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2201 int nr = sattr->index;
2202 unsigned long val;
2203 int err;
2204 u8 reg;
2205
2206 err = kstrtoul(buf, 10, &val);
2207 if (err < 0)
2208 return err;
2209
2210 if (val > 1)
2211 return -EINVAL;
2212
2213 /* Setting DC mode is not supported for all chips/channels */
2214 if (data->REG_PWM_MODE[nr] == 0) {
2215 if (val)
2216 return -EINVAL;
2217 return count;
2218 }
2219
2220 mutex_lock(&data->update_lock);
2221 data->pwm_mode[nr] = val;
2222 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2223 reg &= ~data->PWM_MODE_MASK[nr];
2224 if (val)
2225 reg |= data->PWM_MODE_MASK[nr];
2226 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2227 mutex_unlock(&data->update_lock);
2228 return count;
2229}
2230
2231static ssize_t
2232show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2233{
2234 struct nct6775_data *data = nct6775_update_device(dev);
2235 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2236 int nr = sattr->nr;
2237 int index = sattr->index;
2238 int pwm;
2239
2240 /*
2241 * For automatic fan control modes, show current pwm readings.
2242 * Otherwise, show the configured value.
2243 */
2244 if (index == 0 && data->pwm_enable[nr] > manual)
2245 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2246 else
2247 pwm = data->pwm[index][nr];
2248
2249 return sprintf(buf, "%d\n", pwm);
2250}
2251
2252static ssize_t
2253store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2254 size_t count)
2255{
2256 struct nct6775_data *data = dev_get_drvdata(dev);
2257 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2258 int nr = sattr->nr;
2259 int index = sattr->index;
2260 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002261 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2262 int maxval[7]
2263 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002264 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002265 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002266
2267 err = kstrtoul(buf, 10, &val);
2268 if (err < 0)
2269 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002270 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002271
2272 mutex_lock(&data->update_lock);
2273 data->pwm[index][nr] = val;
2274 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002275 if (index == 2) { /* floor: disable if val == 0 */
2276 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2277 reg &= 0x7f;
2278 if (val)
2279 reg |= 0x80;
2280 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2281 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002282 mutex_unlock(&data->update_lock);
2283 return count;
2284}
2285
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002286/* Returns 0 if OK, -EINVAL otherwise */
2287static int check_trip_points(struct nct6775_data *data, int nr)
2288{
2289 int i;
2290
2291 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2292 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2293 return -EINVAL;
2294 }
2295 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2296 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2297 return -EINVAL;
2298 }
2299 /* validate critical temperature and pwm if enabled (pwm > 0) */
2300 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2301 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2302 data->auto_temp[nr][data->auto_pwm_num] ||
2303 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2304 data->auto_pwm[nr][data->auto_pwm_num])
2305 return -EINVAL;
2306 }
2307 return 0;
2308}
2309
2310static void pwm_update_registers(struct nct6775_data *data, int nr)
2311{
2312 u8 reg;
2313
2314 switch (data->pwm_enable[nr]) {
2315 case off:
2316 case manual:
2317 break;
2318 case speed_cruise:
2319 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2320 reg = (reg & ~data->tolerance_mask) |
2321 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2322 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2323 nct6775_write_value(data, data->REG_TARGET[nr],
2324 data->target_speed[nr] & 0xff);
2325 if (data->REG_TOLERANCE_H) {
2326 reg = (data->target_speed[nr] >> 8) & 0x0f;
2327 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2328 nct6775_write_value(data,
2329 data->REG_TOLERANCE_H[nr],
2330 reg);
2331 }
2332 break;
2333 case thermal_cruise:
2334 nct6775_write_value(data, data->REG_TARGET[nr],
2335 data->target_temp[nr]);
2336 /* intentional */
2337 default:
2338 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2339 reg = (reg & ~data->tolerance_mask) |
2340 data->temp_tolerance[0][nr];
2341 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2342 break;
2343 }
2344}
2345
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002346static ssize_t
2347show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2348{
2349 struct nct6775_data *data = nct6775_update_device(dev);
2350 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2351
2352 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2353}
2354
2355static ssize_t
2356store_pwm_enable(struct device *dev, struct device_attribute *attr,
2357 const char *buf, size_t count)
2358{
2359 struct nct6775_data *data = dev_get_drvdata(dev);
2360 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2361 int nr = sattr->index;
2362 unsigned long val;
2363 int err;
2364 u16 reg;
2365
2366 err = kstrtoul(buf, 10, &val);
2367 if (err < 0)
2368 return err;
2369
2370 if (val > sf4)
2371 return -EINVAL;
2372
2373 if (val == sf3 && data->kind != nct6775)
2374 return -EINVAL;
2375
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002376 if (val == sf4 && check_trip_points(data, nr)) {
2377 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2378 dev_err(dev, "Adjust trip points and try again\n");
2379 return -EINVAL;
2380 }
2381
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002382 mutex_lock(&data->update_lock);
2383 data->pwm_enable[nr] = val;
2384 if (val == off) {
2385 /*
2386 * turn off pwm control: select manual mode, set pwm to maximum
2387 */
2388 data->pwm[0][nr] = 255;
2389 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2390 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002391 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002392 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2393 reg &= 0x0f;
2394 reg |= pwm_enable_to_reg(val) << 4;
2395 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2396 mutex_unlock(&data->update_lock);
2397 return count;
2398}
2399
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002400static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002401show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002402{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002403 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002404
2405 for (i = 0; i < NUM_TEMP; i++) {
2406 if (!(data->have_temp & (1 << i)))
2407 continue;
2408 if (src == data->temp_src[i]) {
2409 sel = i + 1;
2410 break;
2411 }
2412 }
2413
2414 return sprintf(buf, "%d\n", sel);
2415}
2416
2417static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002418show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2419{
2420 struct nct6775_data *data = nct6775_update_device(dev);
2421 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2422 int index = sattr->index;
2423
2424 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2425}
2426
2427static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002428store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2429 const char *buf, size_t count)
2430{
2431 struct nct6775_data *data = nct6775_update_device(dev);
2432 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2433 int nr = sattr->index;
2434 unsigned long val;
2435 int err, reg, src;
2436
2437 err = kstrtoul(buf, 10, &val);
2438 if (err < 0)
2439 return err;
2440 if (val == 0 || val > NUM_TEMP)
2441 return -EINVAL;
2442 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2443 return -EINVAL;
2444
2445 mutex_lock(&data->update_lock);
2446 src = data->temp_src[val - 1];
2447 data->pwm_temp_sel[nr] = src;
2448 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2449 reg &= 0xe0;
2450 reg |= src;
2451 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2452 mutex_unlock(&data->update_lock);
2453
2454 return count;
2455}
2456
2457static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002458show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2459 char *buf)
2460{
2461 struct nct6775_data *data = nct6775_update_device(dev);
2462 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2463 int index = sattr->index;
2464
2465 return show_pwm_temp_sel_common(data, buf,
2466 data->pwm_weight_temp_sel[index]);
2467}
2468
2469static ssize_t
2470store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2471 const char *buf, size_t count)
2472{
2473 struct nct6775_data *data = nct6775_update_device(dev);
2474 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2475 int nr = sattr->index;
2476 unsigned long val;
2477 int err, reg, src;
2478
2479 err = kstrtoul(buf, 10, &val);
2480 if (err < 0)
2481 return err;
2482 if (val > NUM_TEMP)
2483 return -EINVAL;
2484 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2485 !data->temp_src[val - 1]))
2486 return -EINVAL;
2487
2488 mutex_lock(&data->update_lock);
2489 if (val) {
2490 src = data->temp_src[val - 1];
2491 data->pwm_weight_temp_sel[nr] = src;
2492 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2493 reg &= 0xe0;
2494 reg |= (src | 0x80);
2495 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2496 } else {
2497 data->pwm_weight_temp_sel[nr] = 0;
2498 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2499 reg &= 0x7f;
2500 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2501 }
2502 mutex_unlock(&data->update_lock);
2503
2504 return count;
2505}
2506
2507static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002508show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2509{
2510 struct nct6775_data *data = nct6775_update_device(dev);
2511 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2512
2513 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2514}
2515
2516static ssize_t
2517store_target_temp(struct device *dev, struct device_attribute *attr,
2518 const char *buf, size_t count)
2519{
2520 struct nct6775_data *data = dev_get_drvdata(dev);
2521 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2522 int nr = sattr->index;
2523 unsigned long val;
2524 int err;
2525
2526 err = kstrtoul(buf, 10, &val);
2527 if (err < 0)
2528 return err;
2529
2530 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2531 data->target_temp_mask);
2532
2533 mutex_lock(&data->update_lock);
2534 data->target_temp[nr] = val;
2535 pwm_update_registers(data, nr);
2536 mutex_unlock(&data->update_lock);
2537 return count;
2538}
2539
2540static ssize_t
2541show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2542{
2543 struct nct6775_data *data = nct6775_update_device(dev);
2544 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2545 int nr = sattr->index;
2546
2547 return sprintf(buf, "%d\n",
2548 fan_from_reg16(data->target_speed[nr],
2549 data->fan_div[nr]));
2550}
2551
2552static ssize_t
2553store_target_speed(struct device *dev, struct device_attribute *attr,
2554 const char *buf, size_t count)
2555{
2556 struct nct6775_data *data = dev_get_drvdata(dev);
2557 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2558 int nr = sattr->index;
2559 unsigned long val;
2560 int err;
2561 u16 speed;
2562
2563 err = kstrtoul(buf, 10, &val);
2564 if (err < 0)
2565 return err;
2566
2567 val = clamp_val(val, 0, 1350000U);
2568 speed = fan_to_reg(val, data->fan_div[nr]);
2569
2570 mutex_lock(&data->update_lock);
2571 data->target_speed[nr] = speed;
2572 pwm_update_registers(data, nr);
2573 mutex_unlock(&data->update_lock);
2574 return count;
2575}
2576
2577static ssize_t
2578show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2579 char *buf)
2580{
2581 struct nct6775_data *data = nct6775_update_device(dev);
2582 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2583 int nr = sattr->nr;
2584 int index = sattr->index;
2585
2586 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2587}
2588
2589static ssize_t
2590store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2591 const char *buf, size_t count)
2592{
2593 struct nct6775_data *data = dev_get_drvdata(dev);
2594 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2595 int nr = sattr->nr;
2596 int index = sattr->index;
2597 unsigned long val;
2598 int err;
2599
2600 err = kstrtoul(buf, 10, &val);
2601 if (err < 0)
2602 return err;
2603
2604 /* Limit tolerance as needed */
2605 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2606
2607 mutex_lock(&data->update_lock);
2608 data->temp_tolerance[index][nr] = val;
2609 if (index)
2610 pwm_update_registers(data, nr);
2611 else
2612 nct6775_write_value(data,
2613 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2614 val);
2615 mutex_unlock(&data->update_lock);
2616 return count;
2617}
2618
2619/*
2620 * Fan speed tolerance is a tricky beast, since the associated register is
2621 * a tick counter, but the value is reported and configured as rpm.
2622 * Compute resulting low and high rpm values and report the difference.
2623 */
2624static ssize_t
2625show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2626 char *buf)
2627{
2628 struct nct6775_data *data = nct6775_update_device(dev);
2629 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2630 int nr = sattr->index;
2631 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2632 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2633 int tolerance;
2634
2635 if (low <= 0)
2636 low = 1;
2637 if (high > 0xffff)
2638 high = 0xffff;
2639 if (high < low)
2640 high = low;
2641
2642 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2643 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2644
2645 return sprintf(buf, "%d\n", tolerance);
2646}
2647
2648static ssize_t
2649store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2650 const char *buf, size_t count)
2651{
2652 struct nct6775_data *data = dev_get_drvdata(dev);
2653 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2654 int nr = sattr->index;
2655 unsigned long val;
2656 int err;
2657 int low, high;
2658
2659 err = kstrtoul(buf, 10, &val);
2660 if (err < 0)
2661 return err;
2662
2663 high = fan_from_reg16(data->target_speed[nr],
2664 data->fan_div[nr]) + val;
2665 low = fan_from_reg16(data->target_speed[nr],
2666 data->fan_div[nr]) - val;
2667 if (low <= 0)
2668 low = 1;
2669 if (high < low)
2670 high = low;
2671
2672 val = (fan_to_reg(low, data->fan_div[nr]) -
2673 fan_to_reg(high, data->fan_div[nr])) / 2;
2674
2675 /* Limit tolerance as needed */
2676 val = clamp_val(val, 0, data->speed_tolerance_limit);
2677
2678 mutex_lock(&data->update_lock);
2679 data->target_speed_tolerance[nr] = val;
2680 pwm_update_registers(data, nr);
2681 mutex_unlock(&data->update_lock);
2682 return count;
2683}
2684
Guenter Roeckf73cf632013-03-18 09:22:50 -07002685SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2686SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2687 store_pwm_mode, 0);
2688SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2689 store_pwm_enable, 0);
2690SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2691 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2692SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2693 show_target_temp, store_target_temp, 0);
2694SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2695 show_target_speed, store_target_speed, 0);
2696SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2697 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002698
2699/* Smart Fan registers */
2700
2701static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002702show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2703{
2704 struct nct6775_data *data = nct6775_update_device(dev);
2705 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2706 int nr = sattr->nr;
2707 int index = sattr->index;
2708
2709 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2710}
2711
2712static ssize_t
2713store_weight_temp(struct device *dev, struct device_attribute *attr,
2714 const char *buf, size_t count)
2715{
2716 struct nct6775_data *data = dev_get_drvdata(dev);
2717 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2718 int nr = sattr->nr;
2719 int index = sattr->index;
2720 unsigned long val;
2721 int err;
2722
2723 err = kstrtoul(buf, 10, &val);
2724 if (err < 0)
2725 return err;
2726
2727 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2728
2729 mutex_lock(&data->update_lock);
2730 data->weight_temp[index][nr] = val;
2731 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2732 mutex_unlock(&data->update_lock);
2733 return count;
2734}
2735
Guenter Roeckf73cf632013-03-18 09:22:50 -07002736SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2737 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2738SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2739 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2740SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2741 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2742SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2743 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2744SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2745 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2746SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2747 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002748
2749static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002750show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2751{
2752 struct nct6775_data *data = nct6775_update_device(dev);
2753 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2754 int nr = sattr->nr;
2755 int index = sattr->index;
2756
2757 return sprintf(buf, "%d\n",
2758 step_time_from_reg(data->fan_time[index][nr],
2759 data->pwm_mode[nr]));
2760}
2761
2762static ssize_t
2763store_fan_time(struct device *dev, struct device_attribute *attr,
2764 const char *buf, size_t count)
2765{
2766 struct nct6775_data *data = dev_get_drvdata(dev);
2767 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2768 int nr = sattr->nr;
2769 int index = sattr->index;
2770 unsigned long val;
2771 int err;
2772
2773 err = kstrtoul(buf, 10, &val);
2774 if (err < 0)
2775 return err;
2776
2777 val = step_time_to_reg(val, data->pwm_mode[nr]);
2778 mutex_lock(&data->update_lock);
2779 data->fan_time[index][nr] = val;
2780 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2781 mutex_unlock(&data->update_lock);
2782 return count;
2783}
2784
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002785static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002786show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2787{
2788 struct nct6775_data *data = nct6775_update_device(dev);
2789 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2790
2791 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2792}
2793
2794static ssize_t
2795store_auto_pwm(struct device *dev, struct device_attribute *attr,
2796 const char *buf, size_t count)
2797{
2798 struct nct6775_data *data = dev_get_drvdata(dev);
2799 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2800 int nr = sattr->nr;
2801 int point = sattr->index;
2802 unsigned long val;
2803 int err;
2804 u8 reg;
2805
2806 err = kstrtoul(buf, 10, &val);
2807 if (err < 0)
2808 return err;
2809 if (val > 255)
2810 return -EINVAL;
2811
2812 if (point == data->auto_pwm_num) {
2813 if (data->kind != nct6775 && !val)
2814 return -EINVAL;
2815 if (data->kind != nct6779 && val)
2816 val = 0xff;
2817 }
2818
2819 mutex_lock(&data->update_lock);
2820 data->auto_pwm[nr][point] = val;
2821 if (point < data->auto_pwm_num) {
2822 nct6775_write_value(data,
2823 NCT6775_AUTO_PWM(data, nr, point),
2824 data->auto_pwm[nr][point]);
2825 } else {
2826 switch (data->kind) {
2827 case nct6775:
2828 /* disable if needed (pwm == 0) */
2829 reg = nct6775_read_value(data,
2830 NCT6775_REG_CRITICAL_ENAB[nr]);
2831 if (val)
2832 reg |= 0x02;
2833 else
2834 reg &= ~0x02;
2835 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2836 reg);
2837 break;
2838 case nct6776:
2839 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002840 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002841 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002842 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002843 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07002844 case nct6793:
Guenter Roeck6c009502012-07-01 08:23:15 -07002845 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002846 val);
2847 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002848 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002849 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002850 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002851 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002852 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002853 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002854 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002855 reg);
2856 break;
2857 }
2858 }
2859 mutex_unlock(&data->update_lock);
2860 return count;
2861}
2862
2863static ssize_t
2864show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2865{
2866 struct nct6775_data *data = nct6775_update_device(dev);
2867 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2868 int nr = sattr->nr;
2869 int point = sattr->index;
2870
2871 /*
2872 * We don't know for sure if the temperature is signed or unsigned.
2873 * Assume it is unsigned.
2874 */
2875 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2876}
2877
2878static ssize_t
2879store_auto_temp(struct device *dev, struct device_attribute *attr,
2880 const char *buf, size_t count)
2881{
2882 struct nct6775_data *data = dev_get_drvdata(dev);
2883 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2884 int nr = sattr->nr;
2885 int point = sattr->index;
2886 unsigned long val;
2887 int err;
2888
2889 err = kstrtoul(buf, 10, &val);
2890 if (err)
2891 return err;
2892 if (val > 255000)
2893 return -EINVAL;
2894
2895 mutex_lock(&data->update_lock);
2896 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2897 if (point < data->auto_pwm_num) {
2898 nct6775_write_value(data,
2899 NCT6775_AUTO_TEMP(data, nr, point),
2900 data->auto_temp[nr][point]);
2901 } else {
2902 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2903 data->auto_temp[nr][point]);
2904 }
2905 mutex_unlock(&data->update_lock);
2906 return count;
2907}
2908
Guenter Roeckf73cf632013-03-18 09:22:50 -07002909static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2910 struct attribute *attr, int index)
2911{
2912 struct device *dev = container_of(kobj, struct device, kobj);
2913 struct nct6775_data *data = dev_get_drvdata(dev);
2914 int pwm = index / 36; /* pwm index */
2915 int nr = index % 36; /* attribute index */
2916
2917 if (!(data->has_pwm & (1 << pwm)))
2918 return 0;
2919
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002920 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2921 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2922 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002923 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2924 return 0;
2925 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2926 return 0;
2927 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2928 return 0;
2929
2930 if (nr >= 22 && nr <= 35) { /* auto point */
2931 int api = (nr - 22) / 2; /* auto point index */
2932
2933 if (api > data->auto_pwm_num)
2934 return 0;
2935 }
2936 return attr->mode;
2937}
2938
2939SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2940 show_fan_time, store_fan_time, 0, 0);
2941SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2942 show_fan_time, store_fan_time, 0, 1);
2943SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2944 show_fan_time, store_fan_time, 0, 2);
2945SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2946 store_pwm, 0, 1);
2947SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2948 store_pwm, 0, 2);
2949SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2950 show_temp_tolerance, store_temp_tolerance, 0, 0);
2951SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2952 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2953 0, 1);
2954
2955SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2956 0, 3);
2957
2958SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2959 store_pwm, 0, 4);
2960
2961SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2962 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2963SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2964 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2965
2966SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2967 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2968SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2969 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2970
2971SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2972 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2973SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2974 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2975
2976SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2977 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2978SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2979 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2980
2981SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2982 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2983SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2984 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2985
2986SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2987 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2988SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2989 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2990
2991SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2992 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2993SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2994 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2995
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002996/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002997 * nct6775_pwm_is_visible uses the index into the following array
2998 * to determine if attributes should be created or not.
2999 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003000 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003001static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3002 &sensor_dev_template_pwm,
3003 &sensor_dev_template_pwm_mode,
3004 &sensor_dev_template_pwm_enable,
3005 &sensor_dev_template_pwm_temp_sel,
3006 &sensor_dev_template_pwm_temp_tolerance,
3007 &sensor_dev_template_pwm_crit_temp_tolerance,
3008 &sensor_dev_template_pwm_target_temp,
3009 &sensor_dev_template_fan_target,
3010 &sensor_dev_template_fan_tolerance,
3011 &sensor_dev_template_pwm_stop_time,
3012 &sensor_dev_template_pwm_step_up_time,
3013 &sensor_dev_template_pwm_step_down_time,
3014 &sensor_dev_template_pwm_start,
3015 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003016 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003017 &sensor_dev_template_pwm_weight_temp_step,
3018 &sensor_dev_template_pwm_weight_temp_step_tol,
3019 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003020 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003021 &sensor_dev_template_pwm_max, /* 19 */
3022 &sensor_dev_template_pwm_step, /* 20 */
3023 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3024 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3025 &sensor_dev_template_pwm_auto_point1_temp,
3026 &sensor_dev_template_pwm_auto_point2_pwm,
3027 &sensor_dev_template_pwm_auto_point2_temp,
3028 &sensor_dev_template_pwm_auto_point3_pwm,
3029 &sensor_dev_template_pwm_auto_point3_temp,
3030 &sensor_dev_template_pwm_auto_point4_pwm,
3031 &sensor_dev_template_pwm_auto_point4_temp,
3032 &sensor_dev_template_pwm_auto_point5_pwm,
3033 &sensor_dev_template_pwm_auto_point5_temp,
3034 &sensor_dev_template_pwm_auto_point6_pwm,
3035 &sensor_dev_template_pwm_auto_point6_temp,
3036 &sensor_dev_template_pwm_auto_point7_pwm,
3037 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003038
Guenter Roeckf73cf632013-03-18 09:22:50 -07003039 NULL
3040};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003041
Guenter Roeckf73cf632013-03-18 09:22:50 -07003042static struct sensor_template_group nct6775_pwm_template_group = {
3043 .templates = nct6775_attributes_pwm_template,
3044 .is_visible = nct6775_pwm_is_visible,
3045 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003046};
3047
3048static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003049show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3050{
3051 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003052
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003053 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3054}
3055
3056static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3057
Guenter Roecka6bd5872012-12-04 03:13:34 -08003058/* Case open detection */
3059
3060static ssize_t
3061clear_caseopen(struct device *dev, struct device_attribute *attr,
3062 const char *buf, size_t count)
3063{
3064 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003065 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3066 unsigned long val;
3067 u8 reg;
3068 int ret;
3069
3070 if (kstrtoul(buf, 10, &val) || val != 0)
3071 return -EINVAL;
3072
3073 mutex_lock(&data->update_lock);
3074
3075 /*
3076 * Use CR registers to clear caseopen status.
3077 * The CR registers are the same for all chips, and not all chips
3078 * support clearing the caseopen status through "regular" registers.
3079 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003080 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003081 if (ret) {
3082 count = ret;
3083 goto error;
3084 }
3085
Guenter Roeckdf612d52013-07-08 13:15:04 -07003086 superio_select(data->sioreg, NCT6775_LD_ACPI);
3087 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003088 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003089 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003090 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003091 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3092 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003093
3094 data->valid = false; /* Force cache refresh */
3095error:
3096 mutex_unlock(&data->update_lock);
3097 return count;
3098}
3099
Guenter Roeckf73cf632013-03-18 09:22:50 -07003100static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3101 clear_caseopen, INTRUSION_ALARM_BASE);
3102static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3103 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003104static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3105 store_beep, INTRUSION_ALARM_BASE);
3106static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3107 store_beep, INTRUSION_ALARM_BASE + 1);
3108static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3109 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003110
3111static umode_t nct6775_other_is_visible(struct kobject *kobj,
3112 struct attribute *attr, int index)
3113{
3114 struct device *dev = container_of(kobj, struct device, kobj);
3115 struct nct6775_data *data = dev_get_drvdata(dev);
3116
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003117 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003118 return 0;
3119
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003120 if (index == 1 || index == 2) {
3121 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003122 return 0;
3123 }
3124
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003125 if (index == 3 || index == 4) {
3126 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003127 return 0;
3128 }
3129
Guenter Roeckf73cf632013-03-18 09:22:50 -07003130 return attr->mode;
3131}
3132
3133/*
3134 * nct6775_other_is_visible uses the index into the following array
3135 * to determine if attributes should be created or not.
3136 * Any change in order or content must be matched.
3137 */
3138static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003139 &dev_attr_cpu0_vid.attr, /* 0 */
3140 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3141 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3142 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3143 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3144 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003145
3146 NULL
3147};
3148
3149static const struct attribute_group nct6775_group_other = {
3150 .attrs = nct6775_attributes_other,
3151 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003152};
3153
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003154static inline void nct6775_init_device(struct nct6775_data *data)
3155{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003156 int i;
3157 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003158
3159 /* Start monitoring if needed */
3160 if (data->REG_CONFIG) {
3161 tmp = nct6775_read_value(data, data->REG_CONFIG);
3162 if (!(tmp & 0x01))
3163 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3164 }
3165
Guenter Roeckaa136e52012-12-04 03:26:05 -08003166 /* Enable temperature sensors if needed */
3167 for (i = 0; i < NUM_TEMP; i++) {
3168 if (!(data->have_temp & (1 << i)))
3169 continue;
3170 if (!data->reg_temp_config[i])
3171 continue;
3172 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3173 if (tmp & 0x01)
3174 nct6775_write_value(data, data->reg_temp_config[i],
3175 tmp & 0xfe);
3176 }
3177
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003178 /* Enable VBAT monitoring if needed */
3179 tmp = nct6775_read_value(data, data->REG_VBAT);
3180 if (!(tmp & 0x01))
3181 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003182
3183 diode = nct6775_read_value(data, data->REG_DIODE);
3184
3185 for (i = 0; i < data->temp_fixed_num; i++) {
3186 if (!(data->have_temp_fixed & (1 << i)))
3187 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003188 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3189 data->temp_type[i]
3190 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003191 else /* thermistor */
3192 data->temp_type[i] = 4;
3193 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003194}
3195
Guenter Roeckf73cf632013-03-18 09:22:50 -07003196static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003197nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003198{
David Bartley578ab5f2013-06-24 22:28:28 -07003199 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3200 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003201 int sioreg = data->sioreg;
3202 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003203
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003204 /* Store SIO_REG_ENABLE for use during resume */
3205 superio_select(sioreg, NCT6775_LD_HWM);
3206 data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE);
3207
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003208 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3209 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003210 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003211
3212 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003213 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003214
3215 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003216 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003217 fan4min = false;
3218 fan5pin = false;
3219 fan6pin = false;
3220 pwm4pin = false;
3221 pwm5pin = false;
3222 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003223 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003224 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003225 const char *board_vendor, *board_name;
3226
3227 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3228 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3229
3230 if (board_name && board_vendor &&
3231 !strcmp(board_vendor, "ASRock")) {
3232 /*
3233 * Auxiliary fan monitoring is not enabled on ASRock
3234 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3235 * Observed with BIOS version 2.00.
3236 */
3237 if (!strcmp(board_name, "Z77 Pro4-M")) {
3238 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3239 data->sio_reg_enable |= 0xe0;
3240 superio_outb(sioreg, SIO_REG_ENABLE,
3241 data->sio_reg_enable);
3242 }
3243 }
3244 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003245
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003246 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003247 fan3pin = gpok;
3248 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003249 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003250
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003251 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003252 fan4pin = gpok;
3253 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003254 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003255
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003256 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003257 fan5pin = gpok;
3258 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003259 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003260
3261 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003262 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003263 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003264 pwm4pin = false;
3265 pwm5pin = false;
3266 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003267 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003268 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003269 fan3pin = !(regval & 0x80);
3270 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003271
3272 fan4pin = false;
3273 fan4min = false;
3274 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003275 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003276 pwm4pin = false;
3277 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003278 pwm6pin = false;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003279 } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003280 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003281
3282 fan3pin = !(regval & (1 << 5));
3283 fan4pin = !(regval & (1 << 6));
3284 fan5pin = !(regval & (1 << 7));
3285
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003286 pwm3pin = !(regval & (1 << 0));
3287 pwm4pin = !(regval & (1 << 1));
3288 pwm5pin = !(regval & (1 << 2));
3289
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003290 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003291
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003292 if (data->kind == nct6791 || data->kind == nct6792 ||
3293 data->kind == nct6793) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003294 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003295 fan6pin = (regval & (1 << 1));
3296 pwm6pin = (regval & (1 << 0));
3297 } else { /* NCT6779D */
3298 fan6pin = false;
3299 pwm6pin = false;
3300 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003301 }
3302
David Bartley578ab5f2013-06-24 22:28:28 -07003303 /* fan 1 and 2 (0x03) are always present */
3304 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3305 (fan5pin << 4) | (fan6pin << 5);
3306 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3307 (fan5pin << 4);
3308 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3309 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003310}
3311
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003312static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3313 int *available, int *mask)
3314{
3315 int i;
3316 u8 src;
3317
3318 for (i = 0; i < data->pwm_num && *available; i++) {
3319 int index;
3320
3321 if (!regp[i])
3322 continue;
3323 src = nct6775_read_value(data, regp[i]);
3324 src &= 0x1f;
3325 if (!src || (*mask & (1 << src)))
3326 continue;
3327 if (src >= data->temp_label_num ||
3328 !strlen(data->temp_label[src]))
3329 continue;
3330
3331 index = __ffs(*available);
3332 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3333 *available &= ~(1 << index);
3334 *mask |= 1 << src;
3335 }
3336}
3337
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003338static int nct6775_probe(struct platform_device *pdev)
3339{
3340 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003341 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003342 struct nct6775_data *data;
3343 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003344 int i, s, err = 0;
3345 int src, mask, available;
3346 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003347 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003348 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003349 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003350 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003351 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003352 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003353 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003354
3355 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3356 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3357 DRVNAME))
3358 return -EBUSY;
3359
3360 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3361 GFP_KERNEL);
3362 if (!data)
3363 return -ENOMEM;
3364
3365 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003366 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003367 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003368 mutex_init(&data->update_lock);
3369 data->name = nct6775_device_names[data->kind];
3370 data->bank = 0xff; /* Force initial bank selection */
3371 platform_set_drvdata(pdev, data);
3372
3373 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003374 case nct6106:
3375 data->in_num = 9;
3376 data->pwm_num = 3;
3377 data->auto_pwm_num = 4;
3378 data->temp_fixed_num = 3;
3379 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003380 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003381
3382 data->fan_from_reg = fan_from_reg13;
3383 data->fan_from_reg_min = fan_from_reg13;
3384
3385 data->temp_label = nct6776_temp_label;
3386 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3387
3388 data->REG_VBAT = NCT6106_REG_VBAT;
3389 data->REG_DIODE = NCT6106_REG_DIODE;
3390 data->DIODE_MASK = NCT6106_DIODE_MASK;
3391 data->REG_VIN = NCT6106_REG_IN;
3392 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3393 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3394 data->REG_TARGET = NCT6106_REG_TARGET;
3395 data->REG_FAN = NCT6106_REG_FAN;
3396 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3397 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3398 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3399 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3400 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3401 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3402 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3403 data->REG_PWM[0] = NCT6106_REG_PWM;
3404 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3405 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3406 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3407 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3408 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3409 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3410 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3411 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3412 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3413 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3414 data->REG_CRITICAL_TEMP_TOLERANCE
3415 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3416 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3417 data->CRITICAL_PWM_ENABLE_MASK
3418 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3419 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3420 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3421 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3422 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3423 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3424 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3425 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3426 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3427 data->REG_ALARM = NCT6106_REG_ALARM;
3428 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003429 data->REG_BEEP = NCT6106_REG_BEEP;
3430 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003431
3432 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003433 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003434 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003435 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003436 reg_temp_over = NCT6106_REG_TEMP_OVER;
3437 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3438 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3439 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3440 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003441 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3442 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003443
3444 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003445 case nct6775:
3446 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003447 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003448 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003449 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003450 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003451 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003452 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003453
3454 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003455 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003456
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003457 data->fan_from_reg = fan_from_reg16;
3458 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003459 data->target_temp_mask = 0x7f;
3460 data->tolerance_mask = 0x0f;
3461 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003462
Guenter Roeckaa136e52012-12-04 03:26:05 -08003463 data->temp_label = nct6775_temp_label;
3464 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3465
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003466 data->REG_CONFIG = NCT6775_REG_CONFIG;
3467 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003468 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003469 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003470 data->REG_VIN = NCT6775_REG_IN;
3471 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3472 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003473 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003474 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003475 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003476 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003477 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003478 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003479 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3480 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3481 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003482 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003483 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3484 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3485 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3486 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003487 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003488 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3489 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3490 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003491 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3492 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3493 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3494 data->REG_CRITICAL_TEMP_TOLERANCE
3495 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003496 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3497 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003498 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003499 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3500 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3501 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3502 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003503 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003504 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003505
3506 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003507 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003508 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003509 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003510 reg_temp_over = NCT6775_REG_TEMP_OVER;
3511 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3512 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3513 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3514 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3515
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003516 break;
3517 case nct6776:
3518 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003519 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003520 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003521 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003522 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003523 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003524 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003525
3526 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003527 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003528
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003529 data->fan_from_reg = fan_from_reg13;
3530 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003531 data->target_temp_mask = 0xff;
3532 data->tolerance_mask = 0x07;
3533 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003534
Guenter Roeckaa136e52012-12-04 03:26:05 -08003535 data->temp_label = nct6776_temp_label;
3536 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3537
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003538 data->REG_CONFIG = NCT6775_REG_CONFIG;
3539 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003540 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003541 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003542 data->REG_VIN = NCT6775_REG_IN;
3543 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3544 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003545 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003546 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003547 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003548 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003549 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003550 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003551 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003552 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3553 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003554 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003555 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003556 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3557 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003558 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3559 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003560 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3561 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3562 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003563 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3564 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3565 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3566 data->REG_CRITICAL_TEMP_TOLERANCE
3567 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003568 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3569 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003570 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003571 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3572 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3573 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3574 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003575 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003576 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003577
3578 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003579 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003580 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003581 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003582 reg_temp_over = NCT6775_REG_TEMP_OVER;
3583 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3584 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3585 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3586 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3587
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003588 break;
3589 case nct6779:
3590 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003591 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003592 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003593 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003594 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003595 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003596 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003597
3598 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003599 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003600
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003601 data->fan_from_reg = fan_from_reg13;
3602 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003603 data->target_temp_mask = 0xff;
3604 data->tolerance_mask = 0x07;
3605 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003606
Guenter Roeckaa136e52012-12-04 03:26:05 -08003607 data->temp_label = nct6779_temp_label;
3608 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3609
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003610 data->REG_CONFIG = NCT6775_REG_CONFIG;
3611 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003612 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003613 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003614 data->REG_VIN = NCT6779_REG_IN;
3615 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3616 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003617 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003618 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003619 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003620 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003621 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003622 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003623 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003624 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3625 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003626 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003627 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003628 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3629 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003630 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3631 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003632 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3633 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3634 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003635 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3636 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3637 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3638 data->REG_CRITICAL_TEMP_TOLERANCE
3639 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003640 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3641 data->CRITICAL_PWM_ENABLE_MASK
3642 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3643 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003644 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3645 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003646 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003647 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3648 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3649 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3650 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003651 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003652 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003653
3654 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003655 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003656 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003657 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003658 reg_temp_over = NCT6779_REG_TEMP_OVER;
3659 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3660 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3661 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3662 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3663
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003664 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003665 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003666 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003667 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003668 data->in_num = 15;
3669 data->pwm_num = 6;
3670 data->auto_pwm_num = 4;
3671 data->has_fan_div = false;
3672 data->temp_fixed_num = 6;
3673 data->num_temp_alarms = 2;
3674 data->num_temp_beeps = 2;
3675
3676 data->ALARM_BITS = NCT6791_ALARM_BITS;
3677 data->BEEP_BITS = NCT6779_BEEP_BITS;
3678
3679 data->fan_from_reg = fan_from_reg13;
3680 data->fan_from_reg_min = fan_from_reg13;
3681 data->target_temp_mask = 0xff;
3682 data->tolerance_mask = 0x07;
3683 data->speed_tolerance_limit = 63;
3684
3685 data->temp_label = nct6779_temp_label;
3686 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3687
3688 data->REG_CONFIG = NCT6775_REG_CONFIG;
3689 data->REG_VBAT = NCT6775_REG_VBAT;
3690 data->REG_DIODE = NCT6775_REG_DIODE;
3691 data->DIODE_MASK = NCT6775_DIODE_MASK;
3692 data->REG_VIN = NCT6779_REG_IN;
3693 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3694 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3695 data->REG_TARGET = NCT6775_REG_TARGET;
3696 data->REG_FAN = NCT6779_REG_FAN;
3697 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3698 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3699 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3700 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3701 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07003702 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
3703 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07003704 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3705 data->REG_PWM[0] = NCT6775_REG_PWM;
3706 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3707 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003708 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3709 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003710 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3711 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3712 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3713 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3714 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3715 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3716 data->REG_CRITICAL_TEMP_TOLERANCE
3717 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3718 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3719 data->CRITICAL_PWM_ENABLE_MASK
3720 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3721 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3722 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3723 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3724 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003725 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3726 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3727 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3728 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003729 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003730 if (data->kind == nct6791)
3731 data->REG_BEEP = NCT6776_REG_BEEP;
3732 else
3733 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003734
3735 reg_temp = NCT6779_REG_TEMP;
3736 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003737 if (data->kind == nct6791) {
3738 reg_temp_mon = NCT6779_REG_TEMP_MON;
3739 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3740 } else {
3741 reg_temp_mon = NCT6792_REG_TEMP_MON;
3742 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3743 }
David Bartley578ab5f2013-06-24 22:28:28 -07003744 reg_temp_over = NCT6779_REG_TEMP_OVER;
3745 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3746 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3747 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3748 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3749
3750 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003751 default:
3752 return -ENODEV;
3753 }
3754 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003755 data->have_temp = 0;
3756
3757 /*
3758 * On some boards, not all available temperature sources are monitored,
3759 * even though some of the monitoring registers are unused.
3760 * Get list of unused monitoring registers, then detect if any fan
3761 * controls are configured to use unmonitored temperature sources.
3762 * If so, assign the unmonitored temperature sources to available
3763 * monitoring registers.
3764 */
3765 mask = 0;
3766 available = 0;
3767 for (i = 0; i < num_reg_temp; i++) {
3768 if (reg_temp[i] == 0)
3769 continue;
3770
3771 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3772 if (!src || (mask & (1 << src)))
3773 available |= 1 << i;
3774
3775 mask |= 1 << src;
3776 }
3777
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003778 /*
3779 * Now find unmonitored temperature registers and enable monitoring
3780 * if additional monitoring registers are available.
3781 */
3782 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3783 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3784
Guenter Roeckaa136e52012-12-04 03:26:05 -08003785 mask = 0;
3786 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3787 for (i = 0; i < num_reg_temp; i++) {
3788 if (reg_temp[i] == 0)
3789 continue;
3790
3791 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3792 if (!src || (mask & (1 << src)))
3793 continue;
3794
3795 if (src >= data->temp_label_num ||
3796 !strlen(data->temp_label[src])) {
3797 dev_info(dev,
3798 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3799 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3800 continue;
3801 }
3802
3803 mask |= 1 << src;
3804
3805 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3806 if (src <= data->temp_fixed_num) {
3807 data->have_temp |= 1 << (src - 1);
3808 data->have_temp_fixed |= 1 << (src - 1);
3809 data->reg_temp[0][src - 1] = reg_temp[i];
3810 data->reg_temp[1][src - 1] = reg_temp_over[i];
3811 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003812 if (reg_temp_crit_h && reg_temp_crit_h[i])
3813 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3814 else if (reg_temp_crit[src - 1])
3815 data->reg_temp[3][src - 1]
3816 = reg_temp_crit[src - 1];
3817 if (reg_temp_crit_l && reg_temp_crit_l[i])
3818 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003819 data->reg_temp_config[src - 1] = reg_temp_config[i];
3820 data->temp_src[src - 1] = src;
3821 continue;
3822 }
3823
3824 if (s >= NUM_TEMP)
3825 continue;
3826
3827 /* Use dynamic index for other sources */
3828 data->have_temp |= 1 << s;
3829 data->reg_temp[0][s] = reg_temp[i];
3830 data->reg_temp[1][s] = reg_temp_over[i];
3831 data->reg_temp[2][s] = reg_temp_hyst[i];
3832 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003833 if (reg_temp_crit_h && reg_temp_crit_h[i])
3834 data->reg_temp[3][s] = reg_temp_crit_h[i];
3835 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003836 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003837 if (reg_temp_crit_l && reg_temp_crit_l[i])
3838 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003839
3840 data->temp_src[s] = src;
3841 s++;
3842 }
3843
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003844 /*
3845 * Repeat with temperatures used for fan control.
3846 * This set of registers does not support limits.
3847 */
3848 for (i = 0; i < num_reg_temp_mon; i++) {
3849 if (reg_temp_mon[i] == 0)
3850 continue;
3851
3852 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3853 if (!src || (mask & (1 << src)))
3854 continue;
3855
3856 if (src >= data->temp_label_num ||
3857 !strlen(data->temp_label[src])) {
3858 dev_info(dev,
3859 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3860 src, i, data->REG_TEMP_SEL[i],
3861 reg_temp_mon[i]);
3862 continue;
3863 }
3864
3865 mask |= 1 << src;
3866
3867 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3868 if (src <= data->temp_fixed_num) {
3869 if (data->have_temp & (1 << (src - 1)))
3870 continue;
3871 data->have_temp |= 1 << (src - 1);
3872 data->have_temp_fixed |= 1 << (src - 1);
3873 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3874 data->temp_src[src - 1] = src;
3875 continue;
3876 }
3877
3878 if (s >= NUM_TEMP)
3879 continue;
3880
3881 /* Use dynamic index for other sources */
3882 data->have_temp |= 1 << s;
3883 data->reg_temp[0][s] = reg_temp_mon[i];
3884 data->temp_src[s] = src;
3885 s++;
3886 }
3887
Guenter Roeckaa136e52012-12-04 03:26:05 -08003888#ifdef USE_ALTERNATE
3889 /*
3890 * Go through the list of alternate temp registers and enable
3891 * if possible.
3892 * The temperature is already monitored if the respective bit in <mask>
3893 * is set.
3894 */
3895 for (i = 0; i < data->temp_label_num - 1; i++) {
3896 if (!reg_temp_alternate[i])
3897 continue;
3898 if (mask & (1 << (i + 1)))
3899 continue;
3900 if (i < data->temp_fixed_num) {
3901 if (data->have_temp & (1 << i))
3902 continue;
3903 data->have_temp |= 1 << i;
3904 data->have_temp_fixed |= 1 << i;
3905 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003906 if (i < num_reg_temp) {
3907 data->reg_temp[1][i] = reg_temp_over[i];
3908 data->reg_temp[2][i] = reg_temp_hyst[i];
3909 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003910 data->temp_src[i] = i + 1;
3911 continue;
3912 }
3913
3914 if (s >= NUM_TEMP) /* Abort if no more space */
3915 break;
3916
3917 data->have_temp |= 1 << s;
3918 data->reg_temp[0][s] = reg_temp_alternate[i];
3919 data->temp_src[s] = i + 1;
3920 s++;
3921 }
3922#endif /* USE_ALTERNATE */
3923
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003924 /* Initialize the chip */
3925 nct6775_init_device(data);
3926
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003927 err = superio_enter(sio_data->sioreg);
3928 if (err)
3929 return err;
3930
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003931 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3932 switch (data->kind) {
3933 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003934 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003935 break;
3936 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003937 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003938 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003939 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003940 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003941 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003942 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003943 case nct6793:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003944 break;
3945 }
3946
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003947 /*
3948 * Read VID value
3949 * We can get the VID input values directly at logical device D 0xe3.
3950 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003951 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003952 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3953 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3954 data->vrm = vid_which_vrm();
3955 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003956
3957 if (fan_debounce) {
3958 u8 tmp;
3959
3960 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3961 tmp = superio_inb(sio_data->sioreg,
3962 NCT6775_REG_CR_FAN_DEBOUNCE);
3963 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003964 case nct6106:
3965 tmp |= 0xe0;
3966 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003967 case nct6775:
3968 tmp |= 0x1e;
3969 break;
3970 case nct6776:
3971 case nct6779:
3972 tmp |= 0x3e;
3973 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003974 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003975 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003976 case nct6793:
David Bartley578ab5f2013-06-24 22:28:28 -07003977 tmp |= 0x7e;
3978 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003979 }
3980 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3981 tmp);
3982 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3983 data->name);
3984 }
3985
Guenter Roeckdf612d52013-07-08 13:15:04 -07003986 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003987
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003988 superio_exit(sio_data->sioreg);
3989
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003990 /* Read fan clock dividers immediately */
3991 nct6775_init_fan_common(dev, data);
3992
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003993 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003994 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3995 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003996 if (IS_ERR(group))
3997 return PTR_ERR(group);
3998
Axel Lin55bdee62014-07-24 08:59:34 +08003999 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004000
Guenter Roeckf73cf632013-03-18 09:22:50 -07004001 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4002 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004003 if (IS_ERR(group))
4004 return PTR_ERR(group);
4005
Axel Lin55bdee62014-07-24 08:59:34 +08004006 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004007
Guenter Roeckf73cf632013-03-18 09:22:50 -07004008 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4009 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004010 if (IS_ERR(group))
4011 return PTR_ERR(group);
4012
Axel Lin55bdee62014-07-24 08:59:34 +08004013 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004014
Guenter Roeckf73cf632013-03-18 09:22:50 -07004015 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4016 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004017 if (IS_ERR(group))
4018 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004019
Axel Lin55bdee62014-07-24 08:59:34 +08004020 data->groups[num_attr_groups++] = group;
4021 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004022
Guenter Roecka150d952013-07-11 22:55:22 -07004023 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4024 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004025 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004026}
4027
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004028static void nct6791_enable_io_mapping(int sioaddr)
4029{
4030 int val;
4031
4032 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
4033 if (val & 0x10) {
4034 pr_info("Enabling hardware monitor logical device mappings.\n");
4035 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4036 val & ~0x10);
4037 }
4038}
4039
Guenter Roeck48e93182015-02-07 08:48:49 -08004040static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004041{
4042 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004043
4044 mutex_lock(&data->update_lock);
4045 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004046 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004047 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4048 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4049 }
4050 mutex_unlock(&data->update_lock);
4051
4052 return 0;
4053}
4054
Guenter Roeck48e93182015-02-07 08:48:49 -08004055static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004056{
4057 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004058 int sioreg = data->sioreg;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004059 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004060 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004061
4062 mutex_lock(&data->update_lock);
4063 data->bank = 0xff; /* Force initial bank selection */
4064
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004065 err = superio_enter(sioreg);
4066 if (err)
4067 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004068
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004069 superio_select(sioreg, NCT6775_LD_HWM);
4070 reg = superio_inb(sioreg, SIO_REG_ENABLE);
4071 if (reg != data->sio_reg_enable)
4072 superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
4073
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004074 if (data->kind == nct6791 || data->kind == nct6792 ||
4075 data->kind == nct6793)
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004076 nct6791_enable_io_mapping(sioreg);
4077
4078 superio_exit(sioreg);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004079
Guenter Roeck84d19d92012-12-04 08:01:39 -08004080 /* Restore limits */
4081 for (i = 0; i < data->in_num; i++) {
4082 if (!(data->have_in & (1 << i)))
4083 continue;
4084
4085 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4086 data->in[i][1]);
4087 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4088 data->in[i][2]);
4089 }
4090
Guenter Roeckc409fd42013-04-09 05:04:00 -07004091 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004092 if (!(data->has_fan_min & (1 << i)))
4093 continue;
4094
4095 nct6775_write_value(data, data->REG_FAN_MIN[i],
4096 data->fan_min[i]);
4097 }
4098
4099 for (i = 0; i < NUM_TEMP; i++) {
4100 if (!(data->have_temp & (1 << i)))
4101 continue;
4102
Guenter Roeckc409fd42013-04-09 05:04:00 -07004103 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004104 if (data->reg_temp[j][i])
4105 nct6775_write_temp(data, data->reg_temp[j][i],
4106 data->temp[j][i]);
4107 }
4108
4109 /* Restore other settings */
4110 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004111 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004112 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4113 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4114 }
4115
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004116abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004117 /* Force re-reading all values */
4118 data->valid = false;
4119 mutex_unlock(&data->update_lock);
4120
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004121 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004122}
4123
Guenter Roeck48e93182015-02-07 08:48:49 -08004124static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004125
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004126static struct platform_driver nct6775_driver = {
4127 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004128 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004129 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004130 },
4131 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004132};
4133
4134/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004135static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004136{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004137 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004138 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004139 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004140
4141 err = superio_enter(sioaddr);
4142 if (err)
4143 return err;
4144
4145 if (force_id)
4146 val = force_id;
4147 else
4148 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4149 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4150 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004151 case SIO_NCT6106_ID:
4152 sio_data->kind = nct6106;
4153 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004154 case SIO_NCT6775_ID:
4155 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004156 break;
4157 case SIO_NCT6776_ID:
4158 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004159 break;
4160 case SIO_NCT6779_ID:
4161 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004162 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004163 case SIO_NCT6791_ID:
4164 sio_data->kind = nct6791;
4165 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004166 case SIO_NCT6792_ID:
4167 sio_data->kind = nct6792;
4168 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004169 case SIO_NCT6793_ID:
4170 sio_data->kind = nct6793;
4171 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004172 default:
4173 if (val != 0xffff)
4174 pr_debug("unsupported chip ID: 0x%04x\n", val);
4175 superio_exit(sioaddr);
4176 return -ENODEV;
4177 }
4178
4179 /* We have a known chip, find the HWM I/O address */
4180 superio_select(sioaddr, NCT6775_LD_HWM);
4181 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4182 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004183 addr = val & IOREGION_ALIGNMENT;
4184 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004185 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4186 superio_exit(sioaddr);
4187 return -ENODEV;
4188 }
4189
4190 /* Activate logical device if needed */
4191 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4192 if (!(val & 0x01)) {
4193 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4194 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4195 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004196
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004197 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
4198 sio_data->kind == nct6793)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004199 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004200
4201 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004202 pr_info("Found %s or compatible chip at %#x:%#x\n",
4203 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004204 sio_data->sioreg = sioaddr;
4205
Guenter Roeck698a7c22013-04-05 07:35:25 -07004206 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004207}
4208
4209/*
4210 * when Super-I/O functions move to a separate file, the Super-I/O
4211 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004212 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004213 * must keep track of the device
4214 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004215static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004216
4217static int __init sensors_nct6775_init(void)
4218{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004219 int i, err;
4220 bool found = false;
4221 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004222 struct resource res;
4223 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004224 int sioaddr[2] = { 0x2e, 0x4e };
4225
4226 err = platform_driver_register(&nct6775_driver);
4227 if (err)
4228 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004229
4230 /*
4231 * initialize sio_data->kind and sio_data->sioreg.
4232 *
4233 * when Super-I/O functions move to a separate file, the Super-I/O
4234 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4235 * nct6775 hardware monitor, and call probe()
4236 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004237 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4238 address = nct6775_find(sioaddr[i], &sio_data);
4239 if (address <= 0)
4240 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004241
Guenter Roeck698a7c22013-04-05 07:35:25 -07004242 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004243
Guenter Roeck698a7c22013-04-05 07:35:25 -07004244 pdev[i] = platform_device_alloc(DRVNAME, address);
4245 if (!pdev[i]) {
4246 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004247 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004248 }
4249
4250 err = platform_device_add_data(pdev[i], &sio_data,
4251 sizeof(struct nct6775_sio_data));
4252 if (err)
4253 goto exit_device_put;
4254
4255 memset(&res, 0, sizeof(res));
4256 res.name = DRVNAME;
4257 res.start = address + IOREGION_OFFSET;
4258 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4259 res.flags = IORESOURCE_IO;
4260
4261 err = acpi_check_resource_conflict(&res);
4262 if (err) {
4263 platform_device_put(pdev[i]);
4264 pdev[i] = NULL;
4265 continue;
4266 }
4267
4268 err = platform_device_add_resources(pdev[i], &res, 1);
4269 if (err)
4270 goto exit_device_put;
4271
4272 /* platform_device_add calls probe() */
4273 err = platform_device_add(pdev[i]);
4274 if (err)
4275 goto exit_device_put;
4276 }
4277 if (!found) {
4278 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004279 goto exit_unregister;
4280 }
4281
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004282 return 0;
4283
4284exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004285 platform_device_put(pdev[i]);
4286exit_device_unregister:
4287 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004288 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004289 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004290 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004291exit_unregister:
4292 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004293 return err;
4294}
4295
4296static void __exit sensors_nct6775_exit(void)
4297{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004298 int i;
4299
4300 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4301 if (pdev[i])
4302 platform_device_unregister(pdev[i]);
4303 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004304 platform_driver_unregister(&nct6775_driver);
4305}
4306
4307MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004308MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004309MODULE_LICENSE("GPL");
4310
4311module_init(sensors_nct6775_init);
4312module_exit(sensors_nct6775_exit);