blob: dc0df57200cdaef276b5e7609b59fd95478b9a83 [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 Delvare7c81c60f2014-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 Roeck9de2e2e2012-05-20 19:29:48 -070042 *
43 * #temp lists the number of monitored temperature sources (first value) plus
44 * the number of directly connectable temperature sensors (second value).
45 */
46
47#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
48
49#include <linux/module.h>
50#include <linux/init.h>
51#include <linux/slab.h>
52#include <linux/jiffies.h>
53#include <linux/platform_device.h>
54#include <linux/hwmon.h>
55#include <linux/hwmon-sysfs.h>
56#include <linux/hwmon-vid.h>
57#include <linux/err.h>
58#include <linux/mutex.h>
59#include <linux/acpi.h>
60#include <linux/io.h>
61#include "lm75.h"
62
Guenter Roeckaa136e52012-12-04 03:26:05 -080063#define USE_ALTERNATE
64
Guenter Roeck8aefb932014-11-16 09:50:04 -080065enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070066
67/* used to set data->name = nct6775_device_names[data->sio_kind] */
68static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070069 "nct6106",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070070 "nct6775",
71 "nct6776",
72 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070073 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080074 "nct6792",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070075};
76
77static unsigned short force_id;
78module_param(force_id, ushort, 0);
79MODULE_PARM_DESC(force_id, "Override the detected device ID");
80
Guenter Roeck47ece962012-12-04 07:59:32 -080081static unsigned short fan_debounce;
82module_param(fan_debounce, ushort, 0);
83MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
84
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070085#define DRVNAME "nct6775"
86
87/*
88 * Super-I/O constants and functions
89 */
90
Guenter Roecka6bd5872012-12-04 03:13:34 -080091#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070092#define NCT6775_LD_HWM 0x0b
93#define NCT6775_LD_VID 0x0d
94
95#define SIO_REG_LDSEL 0x07 /* Logical device select */
96#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
97#define SIO_REG_ENABLE 0x30 /* Logical device enable */
98#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
99
Guenter Roeck6c009502012-07-01 08:23:15 -0700100#define SIO_NCT6106_ID 0xc450
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700101#define SIO_NCT6775_ID 0xb470
102#define SIO_NCT6776_ID 0xc330
103#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700104#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800105#define SIO_NCT6792_ID 0xc910
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700106#define SIO_ID_MASK 0xFFF0
107
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800108enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
109
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700110static inline void
111superio_outb(int ioreg, int reg, int val)
112{
113 outb(reg, ioreg);
114 outb(val, ioreg + 1);
115}
116
117static inline int
118superio_inb(int ioreg, int reg)
119{
120 outb(reg, ioreg);
121 return inb(ioreg + 1);
122}
123
124static inline void
125superio_select(int ioreg, int ld)
126{
127 outb(SIO_REG_LDSEL, ioreg);
128 outb(ld, ioreg + 1);
129}
130
131static inline int
132superio_enter(int ioreg)
133{
134 /*
135 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
136 */
137 if (!request_muxed_region(ioreg, 2, DRVNAME))
138 return -EBUSY;
139
140 outb(0x87, ioreg);
141 outb(0x87, ioreg);
142
143 return 0;
144}
145
146static inline void
147superio_exit(int ioreg)
148{
149 outb(0xaa, ioreg);
150 outb(0x02, ioreg);
151 outb(0x02, ioreg + 1);
152 release_region(ioreg, 2);
153}
154
155/*
156 * ISA constants
157 */
158
159#define IOREGION_ALIGNMENT (~7)
160#define IOREGION_OFFSET 5
161#define IOREGION_LENGTH 2
162#define ADDR_REG_OFFSET 0
163#define DATA_REG_OFFSET 1
164
165#define NCT6775_REG_BANK 0x4E
166#define NCT6775_REG_CONFIG 0x40
167
168/*
169 * Not currently used:
170 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
171 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
172 * REG_MAN_ID is at port 0x4f
173 * REG_CHIP_ID is at port 0x58
174 */
175
Guenter Roeckaa136e52012-12-04 03:26:05 -0800176#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
177#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
178
Guenter Roeck6c009502012-07-01 08:23:15 -0700179#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700180#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700181
David Bartley578ab5f2013-06-24 22:28:28 -0700182#define NUM_FAN 6
183
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700184/* Common and NCT6775 specific data */
185
186/* Voltage min/max registers for nr=7..14 are in bank 5 */
187
188static const u16 NCT6775_REG_IN_MAX[] = {
189 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
190 0x55c, 0x55e, 0x560, 0x562 };
191static const u16 NCT6775_REG_IN_MIN[] = {
192 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
193 0x55d, 0x55f, 0x561, 0x563 };
194static const u16 NCT6775_REG_IN[] = {
195 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
196};
197
198#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800199#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700200#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700201
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800202#define NCT6775_REG_FANDIV1 0x506
203#define NCT6775_REG_FANDIV2 0x507
204
Guenter Roeck47ece962012-12-04 07:59:32 -0800205#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
206
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700207static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
208
Guenter Roeck30846992013-06-24 22:21:59 -0700209/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700210
211static const s8 NCT6775_ALARM_BITS[] = {
212 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
213 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
214 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700215 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700216 -1, -1, -1, /* unused */
217 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
218 12, -1 }; /* intrusion0, intrusion1 */
219
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800220#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800221#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800222#define INTRUSION_ALARM_BASE 30
223
Guenter Roeck30846992013-06-24 22:21:59 -0700224static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
225
226/*
227 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
228 * 30..31 intrusion
229 */
230static const s8 NCT6775_BEEP_BITS[] = {
231 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
232 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
233 21, /* global beep enable */
234 6, 7, 11, 28, -1, /* fan1..fan5 */
235 -1, -1, -1, /* unused */
236 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
237 12, -1 }; /* intrusion0, intrusion1 */
238
239#define BEEP_ENABLE_BASE 15
240
Guenter Roecka6bd5872012-12-04 03:13:34 -0800241static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
242static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
243
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800244/* DC or PWM output fan configuration */
245static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
246static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
247
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800248/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800249
David Bartley578ab5f2013-06-24 22:28:28 -0700250static const u16 NCT6775_REG_TARGET[] = {
251 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
252static const u16 NCT6775_REG_FAN_MODE[] = {
253 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800254static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700255 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800256static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700257 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800258static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700259 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
260static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
261 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800262static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
263static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
264
265static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700266 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
267static const u16 NCT6775_REG_PWM[] = {
268 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
269static const u16 NCT6775_REG_PWM_READ[] = {
270 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800271
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800272static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
273static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800274static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
David Bartley578ab5f2013-06-24 22:28:28 -0700275static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800276
Guenter Roeckaa136e52012-12-04 03:26:05 -0800277static const u16 NCT6775_REG_TEMP[] = {
278 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
279
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800280static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
281
Guenter Roeckaa136e52012-12-04 03:26:05 -0800282static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
283 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
284static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
285 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
286static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
287 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
288
289static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
290 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
291
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800292static const u16 NCT6775_REG_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700293 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800294
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800295static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700296 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800297static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700298 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800299static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700300 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800301static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700302 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800303static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700304 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800305
Guenter Roeckaa136e52012-12-04 03:26:05 -0800306static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
307
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800308static const u16 NCT6775_REG_AUTO_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700309 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800310static const u16 NCT6775_REG_AUTO_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700311 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800312
313#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
314#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
315
316static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
317
318static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700319 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800320static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700321 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800322
Guenter Roeckaa136e52012-12-04 03:26:05 -0800323static const char *const nct6775_temp_label[] = {
324 "",
325 "SYSTIN",
326 "CPUTIN",
327 "AUXTIN",
328 "AMD SB-TSI",
329 "PECI Agent 0",
330 "PECI Agent 1",
331 "PECI Agent 2",
332 "PECI Agent 3",
333 "PECI Agent 4",
334 "PECI Agent 5",
335 "PECI Agent 6",
336 "PECI Agent 7",
337 "PCH_CHIP_CPU_MAX_TEMP",
338 "PCH_CHIP_TEMP",
339 "PCH_CPU_TEMP",
340 "PCH_MCH_TEMP",
341 "PCH_DIM0_TEMP",
342 "PCH_DIM1_TEMP",
343 "PCH_DIM2_TEMP",
344 "PCH_DIM3_TEMP"
345};
346
347static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
348 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
349
350static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
351 = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
352 0xa07 };
353
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700354/* NCT6776 specific data */
355
356static const s8 NCT6776_ALARM_BITS[] = {
357 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
358 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
359 -1, /* unused */
360 6, 7, 11, 10, 23, /* fan1..fan5 */
361 -1, -1, -1, /* unused */
362 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
363 12, 9 }; /* intrusion0, intrusion1 */
364
Guenter Roeck30846992013-06-24 22:21:59 -0700365static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
366
367static const s8 NCT6776_BEEP_BITS[] = {
368 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
369 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
370 24, /* global beep enable */
371 25, 26, 27, 28, 29, /* fan1..fan5 */
372 -1, -1, -1, /* unused */
373 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
374 30, 31 }; /* intrusion0, intrusion1 */
375
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800376static const u16 NCT6776_REG_TOLERANCE_H[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700377 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800378
David Bartley578ab5f2013-06-24 22:28:28 -0700379static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
380static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800381
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800382static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800383static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800384
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800385static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700386 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800387
Guenter Roeckaa136e52012-12-04 03:26:05 -0800388static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
389 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
390
391static const char *const nct6776_temp_label[] = {
392 "",
393 "SYSTIN",
394 "CPUTIN",
395 "AUXTIN",
396 "SMBUSMASTER 0",
397 "SMBUSMASTER 1",
398 "SMBUSMASTER 2",
399 "SMBUSMASTER 3",
400 "SMBUSMASTER 4",
401 "SMBUSMASTER 5",
402 "SMBUSMASTER 6",
403 "SMBUSMASTER 7",
404 "PECI Agent 0",
405 "PECI Agent 1",
406 "PCH_CHIP_CPU_MAX_TEMP",
407 "PCH_CHIP_TEMP",
408 "PCH_CPU_TEMP",
409 "PCH_MCH_TEMP",
410 "PCH_DIM0_TEMP",
411 "PCH_DIM1_TEMP",
412 "PCH_DIM2_TEMP",
413 "PCH_DIM3_TEMP",
414 "BYTE_TEMP"
415};
416
417static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
418 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
419
420static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
421 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
422
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700423/* NCT6779 specific data */
424
425static const u16 NCT6779_REG_IN[] = {
426 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
427 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
428
429static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
430 0x459, 0x45A, 0x45B, 0x568 };
431
432static const s8 NCT6779_ALARM_BITS[] = {
433 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
434 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
435 -1, /* unused */
436 6, 7, 11, 10, 23, /* fan1..fan5 */
437 -1, -1, -1, /* unused */
438 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
439 12, 9 }; /* intrusion0, intrusion1 */
440
Guenter Roeck30846992013-06-24 22:21:59 -0700441static const s8 NCT6779_BEEP_BITS[] = {
442 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
443 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
444 24, /* global beep enable */
445 25, 26, 27, 28, 29, /* fan1..fan5 */
446 -1, -1, -1, /* unused */
447 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
448 30, 31 }; /* intrusion0, intrusion1 */
449
David Bartley578ab5f2013-06-24 22:28:28 -0700450static const u16 NCT6779_REG_FAN[] = {
451 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
Guenter Roeck5c25d952012-12-11 07:29:06 -0800452static const u16 NCT6779_REG_FAN_PULSES[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700453 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800454
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800455static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700456 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700457#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800458static const u16 NCT6779_REG_CRITICAL_PWM[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700459 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800460
Guenter Roeckaa136e52012-12-04 03:26:05 -0800461static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800462static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800463static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
464 0x18, 0x152 };
465static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
466 0x3a, 0x153 };
467static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
468 0x39, 0x155 };
469
470static const u16 NCT6779_REG_TEMP_OFFSET[] = {
471 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
472
473static const char *const nct6779_temp_label[] = {
474 "",
475 "SYSTIN",
476 "CPUTIN",
477 "AUXTIN0",
478 "AUXTIN1",
479 "AUXTIN2",
480 "AUXTIN3",
481 "",
482 "SMBUSMASTER 0",
483 "SMBUSMASTER 1",
484 "SMBUSMASTER 2",
485 "SMBUSMASTER 3",
486 "SMBUSMASTER 4",
487 "SMBUSMASTER 5",
488 "SMBUSMASTER 6",
489 "SMBUSMASTER 7",
490 "PECI Agent 0",
491 "PECI Agent 1",
492 "PCH_CHIP_CPU_MAX_TEMP",
493 "PCH_CHIP_TEMP",
494 "PCH_CPU_TEMP",
495 "PCH_MCH_TEMP",
496 "PCH_DIM0_TEMP",
497 "PCH_DIM1_TEMP",
498 "PCH_DIM2_TEMP",
499 "PCH_DIM3_TEMP",
500 "BYTE_TEMP"
501};
502
503static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
504 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
505 0, 0, 0, 0, 0, 0, 0, 0,
506 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
507 0x408, 0 };
508
509static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
510 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
511
David Bartley578ab5f2013-06-24 22:28:28 -0700512/* NCT6791 specific data */
513
514#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
515
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800516static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 };
517static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a };
518static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
519static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
520static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
521static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
522
David Bartley578ab5f2013-06-24 22:28:28 -0700523static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
524 0x459, 0x45A, 0x45B, 0x568, 0x45D };
525
526static const s8 NCT6791_ALARM_BITS[] = {
527 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
528 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
529 -1, /* unused */
530 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
531 -1, -1, /* unused */
532 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
533 12, 9 }; /* intrusion0, intrusion1 */
534
Guenter Roeck8aefb932014-11-16 09:50:04 -0800535/* NCT6792 specific data */
536
537static const u16 NCT6792_REG_TEMP_MON[] = {
538 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
539static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
540 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700541
Guenter Roeck6c009502012-07-01 08:23:15 -0700542/* NCT6102D/NCT6106D specific data */
543
544#define NCT6106_REG_VBAT 0x318
545#define NCT6106_REG_DIODE 0x319
546#define NCT6106_DIODE_MASK 0x01
547
548static const u16 NCT6106_REG_IN_MAX[] = {
549 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
550static const u16 NCT6106_REG_IN_MIN[] = {
551 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
552static const u16 NCT6106_REG_IN[] = {
553 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
554
555static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800556static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700557static const u16 NCT6106_REG_TEMP_HYST[] = {
558 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
559static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700560 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
561static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
562 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
563static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
564 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700565static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
566static const u16 NCT6106_REG_TEMP_CONFIG[] = {
567 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
568
569static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
570static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
571static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
572static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
573
574static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
575static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
576static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
577static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
578static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
579static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
580static const u16 NCT6106_REG_TEMP_SOURCE[] = {
581 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
582
583static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
584static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
585 0x11b, 0x12b, 0x13b };
586
587static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
588#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
589static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
590
591static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
592static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
593static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
594static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
595static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
596static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
597
598static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
599
600static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
601static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
602static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
603static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
604static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
605static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
606
607static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
608static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
609
610static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
611 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
612
613static const s8 NCT6106_ALARM_BITS[] = {
614 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
615 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
616 -1, /* unused */
617 32, 33, 34, -1, -1, /* fan1..fan5 */
618 -1, -1, -1, /* unused */
619 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
620 48, -1 /* intrusion0, intrusion1 */
621};
622
Guenter Roeck30846992013-06-24 22:21:59 -0700623static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
624 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
625
626static const s8 NCT6106_BEEP_BITS[] = {
627 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
628 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
629 32, /* global beep enable */
630 24, 25, 26, 27, 28, /* fan1..fan5 */
631 -1, -1, -1, /* unused */
632 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
633 34, -1 /* intrusion0, intrusion1 */
634};
635
Guenter Roeck6c009502012-07-01 08:23:15 -0700636static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
637 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
638
639static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
640 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
641
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800642static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
643{
644 if (mode == 0 && pwm == 255)
645 return off;
646 return mode + 1;
647}
648
649static int pwm_enable_to_reg(enum pwm_enable mode)
650{
651 if (mode == off)
652 return 0;
653 return mode - 1;
654}
655
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700656/*
657 * Conversions
658 */
659
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800660/* 1 is DC mode, output in ms */
661static unsigned int step_time_from_reg(u8 reg, u8 mode)
662{
663 return mode ? 400 * reg : 100 * reg;
664}
665
666static u8 step_time_to_reg(unsigned int msec, u8 mode)
667{
668 return clamp_val((mode ? (msec + 200) / 400 :
669 (msec + 50) / 100), 1, 255);
670}
671
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800672static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
673{
674 if (reg == 0 || reg == 255)
675 return 0;
676 return 1350000U / (reg << divreg);
677}
678
679static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
680{
681 if ((reg & 0xff1f) == 0xff1f)
682 return 0;
683
684 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
685
686 if (reg == 0)
687 return 0;
688
689 return 1350000U / reg;
690}
691
692static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
693{
694 if (reg == 0 || reg == 0xffff)
695 return 0;
696
697 /*
698 * Even though the registers are 16 bit wide, the fan divisor
699 * still applies.
700 */
701 return 1350000U / (reg << divreg);
702}
703
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800704static u16 fan_to_reg(u32 fan, unsigned int divreg)
705{
706 if (!fan)
707 return 0;
708
709 return (1350000U / fan) >> divreg;
710}
711
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800712static inline unsigned int
713div_from_reg(u8 reg)
714{
715 return 1 << reg;
716}
717
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700718/*
719 * Some of the voltage inputs have internal scaling, the tables below
720 * contain 8 (the ADC LSB in mV) * scaling factor * 100
721 */
722static const u16 scale_in[15] = {
723 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
724 800, 800
725};
726
727static inline long in_from_reg(u8 reg, u8 nr)
728{
729 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
730}
731
732static inline u8 in_to_reg(u32 val, u8 nr)
733{
734 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
735}
736
737/*
738 * Data structures and manipulation thereof
739 */
740
741struct nct6775_data {
742 int addr; /* IO base of hw monitor block */
Guenter Roeckdf612d52013-07-08 13:15:04 -0700743 int sioreg; /* SIO register address */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700744 enum kinds kind;
745 const char *name;
746
Guenter Roeck615fc8c2013-07-06 09:43:30 -0700747 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700748
Guenter Roeckb7a61352013-04-02 22:14:06 -0700749 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
750 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -0800751 */
752 u8 temp_src[NUM_TEMP];
753 u16 reg_temp_config[NUM_TEMP];
754 const char * const *temp_label;
755 int temp_label_num;
756
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700757 u16 REG_CONFIG;
758 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800759 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -0700760 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700761
762 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -0700763 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700764
765 const u16 *REG_VIN;
766 const u16 *REG_IN_MINMAX[2];
767
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800768 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800769 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800770 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800771 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -0800772 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -0700773 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800774 const u16 *REG_FAN_TIME[3];
775
776 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -0800777
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800778 const u8 *REG_PWM_MODE;
779 const u8 *PWM_MODE_MASK;
780
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800781 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
782 * [3]=pwm_max, [4]=pwm_step,
783 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800784 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800785 const u16 *REG_PWM_READ;
786
Guenter Roeck6c009502012-07-01 08:23:15 -0700787 const u16 *REG_CRITICAL_PWM_ENABLE;
788 u8 CRITICAL_PWM_ENABLE_MASK;
789 const u16 *REG_CRITICAL_PWM;
790
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800791 const u16 *REG_AUTO_TEMP;
792 const u16 *REG_AUTO_PWM;
793
794 const u16 *REG_CRITICAL_TEMP;
795 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
796
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800797 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800798 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800799 const u16 *REG_WEIGHT_TEMP_SEL;
800 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
801
Guenter Roeckaa136e52012-12-04 03:26:05 -0800802 const u16 *REG_TEMP_OFFSET;
803
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700804 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -0700805 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700806
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800807 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
808 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
809
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700810 struct mutex update_lock;
811 bool valid; /* true if following fields are valid */
812 unsigned long last_updated; /* In jiffies */
813
814 /* Register values */
815 u8 bank; /* current register bank */
816 u8 in_num; /* number of in inputs we have */
817 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -0700818 unsigned int rpm[NUM_FAN];
819 u16 fan_min[NUM_FAN];
820 u8 fan_pulses[NUM_FAN];
821 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800822 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800823 u8 has_fan; /* some fan inputs can be disabled */
824 u8 has_fan_min; /* some fans don't have min register */
825 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700826
Guenter Roeck6c009502012-07-01 08:23:15 -0700827 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -0700828 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -0800829 u8 temp_fixed_num; /* 3 or 6 */
830 u8 temp_type[NUM_TEMP_FIXED];
831 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +0300832 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
833 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700834 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -0700835 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700836
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800837 u8 pwm_num; /* number of pwm */
David Bartley578ab5f2013-06-24 22:28:28 -0700838 u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
839 * 0->PWM variable duty cycle
840 */
841 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800842 /* 0->off
843 * 1->manual
844 * 2->thermal cruise mode (also called SmartFan I)
845 * 3->fan speed cruise mode
846 * 4->SmartFan III
847 * 5->enhanced variable thermal cruise (SmartFan IV)
848 */
David Bartley578ab5f2013-06-24 22:28:28 -0700849 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
850 * [3]=pwm_max, [4]=pwm_step,
851 * [5]=weight_duty_step, [6]=weight_duty_base
852 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800853
David Bartley578ab5f2013-06-24 22:28:28 -0700854 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800855 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -0700856 u32 target_speed[NUM_FAN];
857 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800858 u8 speed_tolerance_limit;
859
David Bartley578ab5f2013-06-24 22:28:28 -0700860 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800861 u8 tolerance_mask;
862
David Bartley578ab5f2013-06-24 22:28:28 -0700863 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800864
865 /* Automatic fan speed control registers */
866 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -0700867 u8 auto_pwm[NUM_FAN][7];
868 u8 auto_temp[NUM_FAN][7];
869 u8 pwm_temp_sel[NUM_FAN];
870 u8 pwm_weight_temp_sel[NUM_FAN];
871 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
872 * 2->temp_base
873 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800874
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700875 u8 vid;
876 u8 vrm;
877
Guenter Roeckf73cf632013-03-18 09:22:50 -0700878 bool have_vid;
879
Guenter Roeckaa136e52012-12-04 03:26:05 -0800880 u16 have_temp;
881 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700882 u16 have_in;
Guenter Roeck84d19d92012-12-04 08:01:39 -0800883#ifdef CONFIG_PM
884 /* Remember extra register values over suspend/resume */
885 u8 vbat;
886 u8 fandiv1;
887 u8 fandiv2;
888#endif
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700889};
890
891struct nct6775_sio_data {
892 int sioreg;
893 enum kinds kind;
894};
895
Guenter Roeckf73cf632013-03-18 09:22:50 -0700896struct sensor_device_template {
897 struct device_attribute dev_attr;
898 union {
899 struct {
900 u8 nr;
901 u8 index;
902 } s;
903 int index;
904 } u;
905 bool s2; /* true if both index and nr are used */
906};
907
908struct sensor_device_attr_u {
909 union {
910 struct sensor_device_attribute a1;
911 struct sensor_device_attribute_2 a2;
912 } u;
913 char name[32];
914};
915
916#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
917 .attr = {.name = _template, .mode = _mode }, \
918 .show = _show, \
919 .store = _store, \
920}
921
922#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
923 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
924 .u.index = _index, \
925 .s2 = false }
926
927#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
928 _nr, _index) \
929 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
930 .u.s.index = _index, \
931 .u.s.nr = _nr, \
932 .s2 = true }
933
934#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
935static struct sensor_device_template sensor_dev_template_##_name \
936 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
937 _index)
938
939#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
940 _nr, _index) \
941static struct sensor_device_template sensor_dev_template_##_name \
942 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
943 _nr, _index)
944
945struct sensor_template_group {
946 struct sensor_device_template **templates;
947 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
948 int base;
949};
950
951static struct attribute_group *
952nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
953 int repeat)
954{
955 struct attribute_group *group;
956 struct sensor_device_attr_u *su;
957 struct sensor_device_attribute *a;
958 struct sensor_device_attribute_2 *a2;
959 struct attribute **attrs;
960 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300961 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700962
963 if (repeat <= 0)
964 return ERR_PTR(-EINVAL);
965
966 t = tg->templates;
967 for (count = 0; *t; t++, count++)
968 ;
969
970 if (count == 0)
971 return ERR_PTR(-EINVAL);
972
973 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
974 if (group == NULL)
975 return ERR_PTR(-ENOMEM);
976
977 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
978 GFP_KERNEL);
979 if (attrs == NULL)
980 return ERR_PTR(-ENOMEM);
981
982 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
983 GFP_KERNEL);
984 if (su == NULL)
985 return ERR_PTR(-ENOMEM);
986
987 group->attrs = attrs;
988 group->is_visible = tg->is_visible;
989
990 for (i = 0; i < repeat; i++) {
991 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300992 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -0700993 snprintf(su->name, sizeof(su->name),
994 (*t)->dev_attr.attr.name, tg->base + i);
995 if ((*t)->s2) {
996 a2 = &su->u.a2;
997 a2->dev_attr.attr.name = su->name;
998 a2->nr = (*t)->u.s.nr + i;
999 a2->index = (*t)->u.s.index;
1000 a2->dev_attr.attr.mode =
1001 (*t)->dev_attr.attr.mode;
1002 a2->dev_attr.show = (*t)->dev_attr.show;
1003 a2->dev_attr.store = (*t)->dev_attr.store;
1004 *attrs = &a2->dev_attr.attr;
1005 } else {
1006 a = &su->u.a1;
1007 a->dev_attr.attr.name = su->name;
1008 a->index = (*t)->u.index + i;
1009 a->dev_attr.attr.mode =
1010 (*t)->dev_attr.attr.mode;
1011 a->dev_attr.show = (*t)->dev_attr.show;
1012 a->dev_attr.store = (*t)->dev_attr.store;
1013 *attrs = &a->dev_attr.attr;
1014 }
1015 attrs++;
1016 su++;
1017 t++;
1018 }
1019 }
1020
Guenter Roeckf73cf632013-03-18 09:22:50 -07001021 return group;
1022}
1023
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001024static bool is_word_sized(struct nct6775_data *data, u16 reg)
1025{
1026 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001027 case nct6106:
1028 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1029 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1030 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001031 case nct6775:
1032 return (((reg & 0xff00) == 0x100 ||
1033 (reg & 0xff00) == 0x200) &&
1034 ((reg & 0x00ff) == 0x50 ||
1035 (reg & 0x00ff) == 0x53 ||
1036 (reg & 0x00ff) == 0x55)) ||
1037 (reg & 0xfff0) == 0x630 ||
1038 reg == 0x640 || reg == 0x642 ||
1039 reg == 0x662 ||
1040 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1041 reg == 0x73 || reg == 0x75 || reg == 0x77;
1042 case nct6776:
1043 return (((reg & 0xff00) == 0x100 ||
1044 (reg & 0xff00) == 0x200) &&
1045 ((reg & 0x00ff) == 0x50 ||
1046 (reg & 0x00ff) == 0x53 ||
1047 (reg & 0x00ff) == 0x55)) ||
1048 (reg & 0xfff0) == 0x630 ||
1049 reg == 0x402 ||
1050 reg == 0x640 || reg == 0x642 ||
1051 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1052 reg == 0x73 || reg == 0x75 || reg == 0x77;
1053 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001054 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001055 case nct6792:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001056 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001057 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001058 reg == 0x402 ||
1059 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1060 reg == 0x640 || reg == 0x642 ||
1061 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001062 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001063 }
1064 return false;
1065}
1066
1067/*
1068 * On older chips, only registers 0x50-0x5f are banked.
1069 * On more recent chips, all registers are banked.
1070 * Assume that is the case and set the bank number for each access.
1071 * Cache the bank number so it only needs to be set if it changes.
1072 */
1073static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1074{
1075 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001076
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001077 if (data->bank != bank) {
1078 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1079 outb_p(bank, data->addr + DATA_REG_OFFSET);
1080 data->bank = bank;
1081 }
1082}
1083
1084static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1085{
1086 int res, word_sized = is_word_sized(data, reg);
1087
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001088 nct6775_set_bank(data, reg);
1089 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1090 res = inb_p(data->addr + DATA_REG_OFFSET);
1091 if (word_sized) {
1092 outb_p((reg & 0xff) + 1,
1093 data->addr + ADDR_REG_OFFSET);
1094 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1095 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001096 return res;
1097}
1098
1099static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1100{
1101 int word_sized = is_word_sized(data, reg);
1102
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001103 nct6775_set_bank(data, reg);
1104 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1105 if (word_sized) {
1106 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1107 outb_p((reg & 0xff) + 1,
1108 data->addr + ADDR_REG_OFFSET);
1109 }
1110 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001111 return 0;
1112}
1113
Guenter Roeckaa136e52012-12-04 03:26:05 -08001114/* We left-align 8-bit temperature values to make the code simpler */
1115static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1116{
1117 u16 res;
1118
1119 res = nct6775_read_value(data, reg);
1120 if (!is_word_sized(data, reg))
1121 res <<= 8;
1122
1123 return res;
1124}
1125
1126static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1127{
1128 if (!is_word_sized(data, reg))
1129 value >>= 8;
1130 return nct6775_write_value(data, reg, value);
1131}
1132
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001133/* This function assumes that the caller holds data->update_lock */
1134static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1135{
1136 u8 reg;
1137
1138 switch (nr) {
1139 case 0:
1140 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1141 | (data->fan_div[0] & 0x7);
1142 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1143 break;
1144 case 1:
1145 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1146 | ((data->fan_div[1] << 4) & 0x70);
1147 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1148 break;
1149 case 2:
1150 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1151 | (data->fan_div[2] & 0x7);
1152 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1153 break;
1154 case 3:
1155 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1156 | ((data->fan_div[3] << 4) & 0x70);
1157 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1158 break;
1159 }
1160}
1161
1162static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1163{
1164 if (data->kind == nct6775)
1165 nct6775_write_fan_div(data, nr);
1166}
1167
1168static void nct6775_update_fan_div(struct nct6775_data *data)
1169{
1170 u8 i;
1171
1172 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1173 data->fan_div[0] = i & 0x7;
1174 data->fan_div[1] = (i & 0x70) >> 4;
1175 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1176 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001177 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001178 data->fan_div[3] = (i & 0x70) >> 4;
1179}
1180
1181static void nct6775_update_fan_div_common(struct nct6775_data *data)
1182{
1183 if (data->kind == nct6775)
1184 nct6775_update_fan_div(data);
1185}
1186
1187static void nct6775_init_fan_div(struct nct6775_data *data)
1188{
1189 int i;
1190
1191 nct6775_update_fan_div_common(data);
1192 /*
1193 * For all fans, start with highest divider value if the divider
1194 * register is not initialized. This ensures that we get a
1195 * reading from the fan count register, even if it is not optimal.
1196 * We'll compute a better divider later on.
1197 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001198 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001199 if (!(data->has_fan & (1 << i)))
1200 continue;
1201 if (data->fan_div[i] == 0) {
1202 data->fan_div[i] = 7;
1203 nct6775_write_fan_div_common(data, i);
1204 }
1205 }
1206}
1207
1208static void nct6775_init_fan_common(struct device *dev,
1209 struct nct6775_data *data)
1210{
1211 int i;
1212 u8 reg;
1213
1214 if (data->has_fan_div)
1215 nct6775_init_fan_div(data);
1216
1217 /*
1218 * If fan_min is not set (0), set it to 0xff to disable it. This
1219 * prevents the unnecessary warning when fanX_min is reported as 0.
1220 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001221 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001222 if (data->has_fan_min & (1 << i)) {
1223 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1224 if (!reg)
1225 nct6775_write_value(data, data->REG_FAN_MIN[i],
1226 data->has_fan_div ? 0xff
1227 : 0xff1f);
1228 }
1229 }
1230}
1231
1232static void nct6775_select_fan_div(struct device *dev,
1233 struct nct6775_data *data, int nr, u16 reg)
1234{
1235 u8 fan_div = data->fan_div[nr];
1236 u16 fan_min;
1237
1238 if (!data->has_fan_div)
1239 return;
1240
1241 /*
1242 * If we failed to measure the fan speed, or the reported value is not
1243 * in the optimal range, and the clock divider can be modified,
1244 * let's try that for next time.
1245 */
1246 if (reg == 0x00 && fan_div < 0x07)
1247 fan_div++;
1248 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1249 fan_div--;
1250
1251 if (fan_div != data->fan_div[nr]) {
1252 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1253 nr + 1, div_from_reg(data->fan_div[nr]),
1254 div_from_reg(fan_div));
1255
1256 /* Preserve min limit if possible */
1257 if (data->has_fan_min & (1 << nr)) {
1258 fan_min = data->fan_min[nr];
1259 if (fan_div > data->fan_div[nr]) {
1260 if (fan_min != 255 && fan_min > 1)
1261 fan_min >>= 1;
1262 } else {
1263 if (fan_min != 255) {
1264 fan_min <<= 1;
1265 if (fan_min > 254)
1266 fan_min = 254;
1267 }
1268 }
1269 if (fan_min != data->fan_min[nr]) {
1270 data->fan_min[nr] = fan_min;
1271 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1272 fan_min);
1273 }
1274 }
1275 data->fan_div[nr] = fan_div;
1276 nct6775_write_fan_div_common(data, nr);
1277 }
1278}
1279
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001280static void nct6775_update_pwm(struct device *dev)
1281{
1282 struct nct6775_data *data = dev_get_drvdata(dev);
1283 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001284 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001285 bool duty_is_dc;
1286
1287 for (i = 0; i < data->pwm_num; i++) {
1288 if (!(data->has_pwm & (1 << i)))
1289 continue;
1290
1291 duty_is_dc = data->REG_PWM_MODE[i] &&
1292 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1293 & data->PWM_MODE_MASK[i]);
1294 data->pwm_mode[i] = duty_is_dc;
1295
1296 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1297 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1298 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1299 data->pwm[j][i]
1300 = nct6775_read_value(data,
1301 data->REG_PWM[j][i]);
1302 }
1303 }
1304
1305 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1306 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001307
1308 if (!data->temp_tolerance[0][i] ||
1309 data->pwm_enable[i] != speed_cruise)
1310 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1311 if (!data->target_speed_tolerance[i] ||
1312 data->pwm_enable[i] == speed_cruise) {
1313 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001314
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001315 if (data->REG_TOLERANCE_H) {
1316 t |= (nct6775_read_value(data,
1317 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1318 }
1319 data->target_speed_tolerance[i] = t;
1320 }
1321
1322 data->temp_tolerance[1][i] =
1323 nct6775_read_value(data,
1324 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1325
1326 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1327 data->pwm_temp_sel[i] = reg & 0x1f;
1328 /* If fan can stop, report floor as 0 */
1329 if (reg & 0x80)
1330 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001331
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001332 if (!data->REG_WEIGHT_TEMP_SEL[i])
1333 continue;
1334
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001335 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1336 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1337 /* If weight is disabled, report weight source as 0 */
1338 if (j == 1 && !(reg & 0x80))
1339 data->pwm_weight_temp_sel[i] = 0;
1340
1341 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001342 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001343 data->weight_temp[j][i]
1344 = nct6775_read_value(data,
1345 data->REG_WEIGHT_TEMP[j][i]);
1346 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001347 }
1348}
1349
1350static void nct6775_update_pwm_limits(struct device *dev)
1351{
1352 struct nct6775_data *data = dev_get_drvdata(dev);
1353 int i, j;
1354 u8 reg;
1355 u16 reg_t;
1356
1357 for (i = 0; i < data->pwm_num; i++) {
1358 if (!(data->has_pwm & (1 << i)))
1359 continue;
1360
Guenter Roeckc409fd42013-04-09 05:04:00 -07001361 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001362 data->fan_time[j][i] =
1363 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1364 }
1365
1366 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1367 /* Update only in matching mode or if never updated */
1368 if (!data->target_temp[i] ||
1369 data->pwm_enable[i] == thermal_cruise)
1370 data->target_temp[i] = reg_t & data->target_temp_mask;
1371 if (!data->target_speed[i] ||
1372 data->pwm_enable[i] == speed_cruise) {
1373 if (data->REG_TOLERANCE_H) {
1374 reg_t |= (nct6775_read_value(data,
1375 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1376 }
1377 data->target_speed[i] = reg_t;
1378 }
1379
1380 for (j = 0; j < data->auto_pwm_num; j++) {
1381 data->auto_pwm[i][j] =
1382 nct6775_read_value(data,
1383 NCT6775_AUTO_PWM(data, i, j));
1384 data->auto_temp[i][j] =
1385 nct6775_read_value(data,
1386 NCT6775_AUTO_TEMP(data, i, j));
1387 }
1388
1389 /* critical auto_pwm temperature data */
1390 data->auto_temp[i][data->auto_pwm_num] =
1391 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1392
1393 switch (data->kind) {
1394 case nct6775:
1395 reg = nct6775_read_value(data,
1396 NCT6775_REG_CRITICAL_ENAB[i]);
1397 data->auto_pwm[i][data->auto_pwm_num] =
1398 (reg & 0x02) ? 0xff : 0x00;
1399 break;
1400 case nct6776:
1401 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1402 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001403 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001404 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001405 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001406 case nct6792:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001407 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001408 data->REG_CRITICAL_PWM_ENABLE[i]);
1409 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1410 reg = nct6775_read_value(data,
1411 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001412 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001413 reg = 0xff;
1414 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001415 break;
1416 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001417 }
1418}
1419
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001420static struct nct6775_data *nct6775_update_device(struct device *dev)
1421{
1422 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001423 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001424
1425 mutex_lock(&data->update_lock);
1426
Guenter Roeck6445e662013-04-21 09:13:28 -07001427 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001428 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001429 /* Fan clock dividers */
1430 nct6775_update_fan_div_common(data);
1431
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001432 /* Measured voltages and limits */
1433 for (i = 0; i < data->in_num; i++) {
1434 if (!(data->have_in & (1 << i)))
1435 continue;
1436
1437 data->in[i][0] = nct6775_read_value(data,
1438 data->REG_VIN[i]);
1439 data->in[i][1] = nct6775_read_value(data,
1440 data->REG_IN_MINMAX[0][i]);
1441 data->in[i][2] = nct6775_read_value(data,
1442 data->REG_IN_MINMAX[1][i]);
1443 }
1444
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001445 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001446 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001447 u16 reg;
1448
1449 if (!(data->has_fan & (1 << i)))
1450 continue;
1451
1452 reg = nct6775_read_value(data, data->REG_FAN[i]);
1453 data->rpm[i] = data->fan_from_reg(reg,
1454 data->fan_div[i]);
1455
1456 if (data->has_fan_min & (1 << i))
1457 data->fan_min[i] = nct6775_read_value(data,
1458 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001459 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001460 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1461 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001462
1463 nct6775_select_fan_div(dev, data, i, reg);
1464 }
1465
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001466 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001467 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001468
Guenter Roeckaa136e52012-12-04 03:26:05 -08001469 /* Measured temperatures and limits */
1470 for (i = 0; i < NUM_TEMP; i++) {
1471 if (!(data->have_temp & (1 << i)))
1472 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001473 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001474 if (data->reg_temp[j][i])
1475 data->temp[j][i]
1476 = nct6775_read_temp(data,
1477 data->reg_temp[j][i]);
1478 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001479 if (i >= NUM_TEMP_FIXED ||
1480 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001481 continue;
1482 data->temp_offset[i]
1483 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1484 }
1485
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001486 data->alarms = 0;
1487 for (i = 0; i < NUM_REG_ALARM; i++) {
1488 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001489
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001490 if (!data->REG_ALARM[i])
1491 continue;
1492 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1493 data->alarms |= ((u64)alarm) << (i << 3);
1494 }
1495
Guenter Roeck30846992013-06-24 22:21:59 -07001496 data->beeps = 0;
1497 for (i = 0; i < NUM_REG_BEEP; i++) {
1498 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001499
Guenter Roeck30846992013-06-24 22:21:59 -07001500 if (!data->REG_BEEP[i])
1501 continue;
1502 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1503 data->beeps |= ((u64)beep) << (i << 3);
1504 }
1505
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001506 data->last_updated = jiffies;
1507 data->valid = true;
1508 }
1509
1510 mutex_unlock(&data->update_lock);
1511 return data;
1512}
1513
1514/*
1515 * Sysfs callback functions
1516 */
1517static ssize_t
1518show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1519{
1520 struct nct6775_data *data = nct6775_update_device(dev);
1521 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001522 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001523 int nr = sattr->nr;
1524
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001525 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1526}
1527
1528static ssize_t
1529store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1530 size_t count)
1531{
1532 struct nct6775_data *data = dev_get_drvdata(dev);
1533 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001534 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001535 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001536 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001537 int err;
1538
1539 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001540 if (err < 0)
1541 return err;
1542 mutex_lock(&data->update_lock);
1543 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001544 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001545 data->in[nr][index]);
1546 mutex_unlock(&data->update_lock);
1547 return count;
1548}
1549
1550static ssize_t
1551show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1552{
1553 struct nct6775_data *data = nct6775_update_device(dev);
1554 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1555 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001556
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001557 return sprintf(buf, "%u\n",
1558 (unsigned int)((data->alarms >> nr) & 0x01));
1559}
1560
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001561static int find_temp_source(struct nct6775_data *data, int index, int count)
1562{
1563 int source = data->temp_src[index];
1564 int nr;
1565
1566 for (nr = 0; nr < count; nr++) {
1567 int src;
1568
1569 src = nct6775_read_value(data,
1570 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1571 if (src == source)
1572 return nr;
1573 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001574 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001575}
1576
1577static ssize_t
1578show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1579{
1580 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1581 struct nct6775_data *data = nct6775_update_device(dev);
1582 unsigned int alarm = 0;
1583 int nr;
1584
1585 /*
1586 * For temperatures, there is no fixed mapping from registers to alarm
1587 * bits. Alarm bits are determined by the temperature source mapping.
1588 */
1589 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1590 if (nr >= 0) {
1591 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001592
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001593 alarm = (data->alarms >> bit) & 0x01;
1594 }
1595 return sprintf(buf, "%u\n", alarm);
1596}
1597
Guenter Roeck30846992013-06-24 22:21:59 -07001598static ssize_t
1599show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1600{
1601 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1602 struct nct6775_data *data = nct6775_update_device(dev);
1603 int nr = data->BEEP_BITS[sattr->index];
1604
1605 return sprintf(buf, "%u\n",
1606 (unsigned int)((data->beeps >> nr) & 0x01));
1607}
1608
1609static ssize_t
1610store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1611 size_t count)
1612{
1613 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1614 struct nct6775_data *data = dev_get_drvdata(dev);
1615 int nr = data->BEEP_BITS[sattr->index];
1616 int regindex = nr >> 3;
1617 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001618 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001619
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001620 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001621 if (err < 0)
1622 return err;
1623 if (val > 1)
1624 return -EINVAL;
1625
1626 mutex_lock(&data->update_lock);
1627 if (val)
1628 data->beeps |= (1ULL << nr);
1629 else
1630 data->beeps &= ~(1ULL << nr);
1631 nct6775_write_value(data, data->REG_BEEP[regindex],
1632 (data->beeps >> (regindex << 3)) & 0xff);
1633 mutex_unlock(&data->update_lock);
1634 return count;
1635}
1636
1637static ssize_t
1638show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1639{
1640 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1641 struct nct6775_data *data = nct6775_update_device(dev);
1642 unsigned int beep = 0;
1643 int nr;
1644
1645 /*
1646 * For temperatures, there is no fixed mapping from registers to beep
1647 * enable bits. Beep enable bits are determined by the temperature
1648 * source mapping.
1649 */
1650 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1651 if (nr >= 0) {
1652 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001653
Guenter Roeck30846992013-06-24 22:21:59 -07001654 beep = (data->beeps >> bit) & 0x01;
1655 }
1656 return sprintf(buf, "%u\n", beep);
1657}
1658
1659static ssize_t
1660store_temp_beep(struct device *dev, struct device_attribute *attr,
1661 const char *buf, size_t count)
1662{
1663 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1664 struct nct6775_data *data = dev_get_drvdata(dev);
1665 int nr, bit, regindex;
1666 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001667 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001668
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001669 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001670 if (err < 0)
1671 return err;
1672 if (val > 1)
1673 return -EINVAL;
1674
1675 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1676 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001677 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001678
1679 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1680 regindex = bit >> 3;
1681
1682 mutex_lock(&data->update_lock);
1683 if (val)
1684 data->beeps |= (1ULL << bit);
1685 else
1686 data->beeps &= ~(1ULL << bit);
1687 nct6775_write_value(data, data->REG_BEEP[regindex],
1688 (data->beeps >> (regindex << 3)) & 0xff);
1689 mutex_unlock(&data->update_lock);
1690
1691 return count;
1692}
1693
Guenter Roeckf73cf632013-03-18 09:22:50 -07001694static umode_t nct6775_in_is_visible(struct kobject *kobj,
1695 struct attribute *attr, int index)
1696{
1697 struct device *dev = container_of(kobj, struct device, kobj);
1698 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001699 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001700
Guenter Roeckf73cf632013-03-18 09:22:50 -07001701 if (!(data->have_in & (1 << in)))
1702 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001703
Guenter Roeckf73cf632013-03-18 09:22:50 -07001704 return attr->mode;
1705}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001706
Guenter Roeckf73cf632013-03-18 09:22:50 -07001707SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1708SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001709SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1710 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001711SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1712 store_in_reg, 0, 1);
1713SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1714 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001715
Guenter Roeckf73cf632013-03-18 09:22:50 -07001716/*
1717 * nct6775_in_is_visible uses the index into the following array
1718 * to determine if attributes should be created or not.
1719 * Any change in order or content must be matched.
1720 */
1721static struct sensor_device_template *nct6775_attributes_in_template[] = {
1722 &sensor_dev_template_in_input,
1723 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001724 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001725 &sensor_dev_template_in_min,
1726 &sensor_dev_template_in_max,
1727 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001728};
1729
Guenter Roeckf73cf632013-03-18 09:22:50 -07001730static struct sensor_template_group nct6775_in_template_group = {
1731 .templates = nct6775_attributes_in_template,
1732 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001733};
1734
1735static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001736show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1737{
1738 struct nct6775_data *data = nct6775_update_device(dev);
1739 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1740 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001741
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001742 return sprintf(buf, "%d\n", data->rpm[nr]);
1743}
1744
1745static ssize_t
1746show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1747{
1748 struct nct6775_data *data = nct6775_update_device(dev);
1749 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1750 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001751
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001752 return sprintf(buf, "%d\n",
1753 data->fan_from_reg_min(data->fan_min[nr],
1754 data->fan_div[nr]));
1755}
1756
1757static ssize_t
1758show_fan_div(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, "%u\n", div_from_reg(data->fan_div[nr]));
1765}
1766
1767static ssize_t
1768store_fan_min(struct device *dev, struct device_attribute *attr,
1769 const char *buf, size_t count)
1770{
1771 struct nct6775_data *data = dev_get_drvdata(dev);
1772 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1773 int nr = sattr->index;
1774 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001775 unsigned int reg;
1776 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001777 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001778
1779 err = kstrtoul(buf, 10, &val);
1780 if (err < 0)
1781 return err;
1782
1783 mutex_lock(&data->update_lock);
1784 if (!data->has_fan_div) {
1785 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1786 if (!val) {
1787 val = 0xff1f;
1788 } else {
1789 if (val > 1350000U)
1790 val = 135000U;
1791 val = 1350000U / val;
1792 val = (val & 0x1f) | ((val << 3) & 0xff00);
1793 }
1794 data->fan_min[nr] = val;
1795 goto write_min; /* Leave fan divider alone */
1796 }
1797 if (!val) {
1798 /* No min limit, alarm disabled */
1799 data->fan_min[nr] = 255;
1800 new_div = data->fan_div[nr]; /* No change */
1801 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1802 goto write_div;
1803 }
1804 reg = 1350000U / val;
1805 if (reg >= 128 * 255) {
1806 /*
1807 * Speed below this value cannot possibly be represented,
1808 * even with the highest divider (128)
1809 */
1810 data->fan_min[nr] = 254;
1811 new_div = 7; /* 128 == (1 << 7) */
1812 dev_warn(dev,
1813 "fan%u low limit %lu below minimum %u, set to minimum\n",
1814 nr + 1, val, data->fan_from_reg_min(254, 7));
1815 } else if (!reg) {
1816 /*
1817 * Speed above this value cannot possibly be represented,
1818 * even with the lowest divider (1)
1819 */
1820 data->fan_min[nr] = 1;
1821 new_div = 0; /* 1 == (1 << 0) */
1822 dev_warn(dev,
1823 "fan%u low limit %lu above maximum %u, set to maximum\n",
1824 nr + 1, val, data->fan_from_reg_min(1, 0));
1825 } else {
1826 /*
1827 * Automatically pick the best divider, i.e. the one such
1828 * that the min limit will correspond to a register value
1829 * in the 96..192 range
1830 */
1831 new_div = 0;
1832 while (reg > 192 && new_div < 7) {
1833 reg >>= 1;
1834 new_div++;
1835 }
1836 data->fan_min[nr] = reg;
1837 }
1838
1839write_div:
1840 /*
1841 * Write both the fan clock divider (if it changed) and the new
1842 * fan min (unconditionally)
1843 */
1844 if (new_div != data->fan_div[nr]) {
1845 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1846 nr + 1, div_from_reg(data->fan_div[nr]),
1847 div_from_reg(new_div));
1848 data->fan_div[nr] = new_div;
1849 nct6775_write_fan_div_common(data, nr);
1850 /* Give the chip time to sample a new speed value */
1851 data->last_updated = jiffies;
1852 }
1853
1854write_min:
1855 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1856 mutex_unlock(&data->update_lock);
1857
1858 return count;
1859}
1860
Guenter Roeck5c25d952012-12-11 07:29:06 -08001861static ssize_t
1862show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1863{
1864 struct nct6775_data *data = nct6775_update_device(dev);
1865 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1866 int p = data->fan_pulses[sattr->index];
1867
1868 return sprintf(buf, "%d\n", p ? : 4);
1869}
1870
1871static ssize_t
1872store_fan_pulses(struct device *dev, struct device_attribute *attr,
1873 const char *buf, size_t count)
1874{
1875 struct nct6775_data *data = dev_get_drvdata(dev);
1876 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1877 int nr = sattr->index;
1878 unsigned long val;
1879 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001880 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001881
1882 err = kstrtoul(buf, 10, &val);
1883 if (err < 0)
1884 return err;
1885
1886 if (val > 4)
1887 return -EINVAL;
1888
1889 mutex_lock(&data->update_lock);
1890 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001891 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1892 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1893 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1894 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001895 mutex_unlock(&data->update_lock);
1896
1897 return count;
1898}
1899
Guenter Roeckf73cf632013-03-18 09:22:50 -07001900static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1901 struct attribute *attr, int index)
1902{
1903 struct device *dev = container_of(kobj, struct device, kobj);
1904 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001905 int fan = index / 6; /* fan index */
1906 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001907
1908 if (!(data->has_fan & (1 << fan)))
1909 return 0;
1910
1911 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1912 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001913 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001914 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001915 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1916 return 0;
1917 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001918 return 0;
1919
1920 return attr->mode;
1921}
1922
1923SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1924SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1925 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001926SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1927 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001928SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1929 store_fan_pulses, 0);
1930SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1931 store_fan_min, 0);
1932SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1933
1934/*
1935 * nct6775_fan_is_visible uses the index into the following array
1936 * to determine if attributes should be created or not.
1937 * Any change in order or content must be matched.
1938 */
1939static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1940 &sensor_dev_template_fan_input,
1941 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001942 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001943 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001944 &sensor_dev_template_fan_min, /* 4 */
1945 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001946 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001947};
1948
Guenter Roeckf73cf632013-03-18 09:22:50 -07001949static struct sensor_template_group nct6775_fan_template_group = {
1950 .templates = nct6775_attributes_fan_template,
1951 .is_visible = nct6775_fan_is_visible,
1952 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001953};
1954
1955static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001956show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1957{
1958 struct nct6775_data *data = nct6775_update_device(dev);
1959 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1960 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001961
Guenter Roeckaa136e52012-12-04 03:26:05 -08001962 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1963}
1964
1965static ssize_t
1966show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1967{
1968 struct nct6775_data *data = nct6775_update_device(dev);
1969 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1970 int nr = sattr->nr;
1971 int index = sattr->index;
1972
1973 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1974}
1975
1976static ssize_t
1977store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
1978 size_t count)
1979{
1980 struct nct6775_data *data = dev_get_drvdata(dev);
1981 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1982 int nr = sattr->nr;
1983 int index = sattr->index;
1984 int err;
1985 long val;
1986
1987 err = kstrtol(buf, 10, &val);
1988 if (err < 0)
1989 return err;
1990
1991 mutex_lock(&data->update_lock);
1992 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
1993 nct6775_write_temp(data, data->reg_temp[index][nr],
1994 data->temp[index][nr]);
1995 mutex_unlock(&data->update_lock);
1996 return count;
1997}
1998
1999static ssize_t
2000show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2001{
2002 struct nct6775_data *data = nct6775_update_device(dev);
2003 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2004
2005 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2006}
2007
2008static ssize_t
2009store_temp_offset(struct device *dev, struct device_attribute *attr,
2010 const char *buf, size_t count)
2011{
2012 struct nct6775_data *data = dev_get_drvdata(dev);
2013 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2014 int nr = sattr->index;
2015 long val;
2016 int err;
2017
2018 err = kstrtol(buf, 10, &val);
2019 if (err < 0)
2020 return err;
2021
2022 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2023
2024 mutex_lock(&data->update_lock);
2025 data->temp_offset[nr] = val;
2026 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2027 mutex_unlock(&data->update_lock);
2028
2029 return count;
2030}
2031
2032static ssize_t
2033show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2034{
2035 struct nct6775_data *data = nct6775_update_device(dev);
2036 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2037 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002038
Guenter Roeckaa136e52012-12-04 03:26:05 -08002039 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2040}
2041
2042static ssize_t
2043store_temp_type(struct device *dev, struct device_attribute *attr,
2044 const char *buf, size_t count)
2045{
2046 struct nct6775_data *data = nct6775_update_device(dev);
2047 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2048 int nr = sattr->index;
2049 unsigned long val;
2050 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002051 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002052
2053 err = kstrtoul(buf, 10, &val);
2054 if (err < 0)
2055 return err;
2056
2057 if (val != 1 && val != 3 && val != 4)
2058 return -EINVAL;
2059
2060 mutex_lock(&data->update_lock);
2061
2062 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002063 vbit = 0x02 << nr;
2064 dbit = data->DIODE_MASK << nr;
2065 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2066 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002067 switch (val) {
2068 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002069 vbat |= vbit;
2070 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002071 break;
2072 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002073 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002074 break;
2075 case 4: /* thermistor */
2076 break;
2077 }
2078 nct6775_write_value(data, data->REG_VBAT, vbat);
2079 nct6775_write_value(data, data->REG_DIODE, diode);
2080
2081 mutex_unlock(&data->update_lock);
2082 return count;
2083}
2084
Guenter Roeckf73cf632013-03-18 09:22:50 -07002085static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2086 struct attribute *attr, int index)
2087{
2088 struct device *dev = container_of(kobj, struct device, kobj);
2089 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002090 int temp = index / 10; /* temp index */
2091 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002092
2093 if (!(data->have_temp & (1 << temp)))
2094 return 0;
2095
2096 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2097 return 0; /* alarm */
2098
Guenter Roeck30846992013-06-24 22:21:59 -07002099 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2100 return 0; /* beep */
2101
2102 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002103 return 0;
2104
Guenter Roeck30846992013-06-24 22:21:59 -07002105 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002106 return 0;
2107
Guenter Roeck30846992013-06-24 22:21:59 -07002108 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002109 return 0;
2110
Guenter Roeck30846992013-06-24 22:21:59 -07002111 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002112 return 0;
2113
2114 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002115 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002116 return 0;
2117
2118 return attr->mode;
2119}
2120
2121SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2122SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2123SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2124 store_temp, 0, 1);
2125SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2126 show_temp, store_temp, 0, 2);
2127SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2128 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002129SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2130 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002131SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2132 show_temp_offset, store_temp_offset, 0);
2133SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2134 store_temp_type, 0);
2135SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002136SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2137 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002138
2139/*
2140 * nct6775_temp_is_visible uses the index into the following array
2141 * to determine if attributes should be created or not.
2142 * Any change in order or content must be matched.
2143 */
2144static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2145 &sensor_dev_template_temp_input,
2146 &sensor_dev_template_temp_label,
2147 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002148 &sensor_dev_template_temp_beep, /* 3 */
2149 &sensor_dev_template_temp_max, /* 4 */
2150 &sensor_dev_template_temp_max_hyst, /* 5 */
2151 &sensor_dev_template_temp_crit, /* 6 */
2152 &sensor_dev_template_temp_lcrit, /* 7 */
2153 &sensor_dev_template_temp_offset, /* 8 */
2154 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002155 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002156};
2157
Guenter Roeckf73cf632013-03-18 09:22:50 -07002158static struct sensor_template_group nct6775_temp_template_group = {
2159 .templates = nct6775_attributes_temp_template,
2160 .is_visible = nct6775_temp_is_visible,
2161 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002162};
2163
Guenter Roeckaa136e52012-12-04 03:26:05 -08002164static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002165show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2166{
2167 struct nct6775_data *data = nct6775_update_device(dev);
2168 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2169
2170 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2171}
2172
2173static ssize_t
2174store_pwm_mode(struct device *dev, struct device_attribute *attr,
2175 const char *buf, size_t count)
2176{
2177 struct nct6775_data *data = dev_get_drvdata(dev);
2178 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2179 int nr = sattr->index;
2180 unsigned long val;
2181 int err;
2182 u8 reg;
2183
2184 err = kstrtoul(buf, 10, &val);
2185 if (err < 0)
2186 return err;
2187
2188 if (val > 1)
2189 return -EINVAL;
2190
2191 /* Setting DC mode is not supported for all chips/channels */
2192 if (data->REG_PWM_MODE[nr] == 0) {
2193 if (val)
2194 return -EINVAL;
2195 return count;
2196 }
2197
2198 mutex_lock(&data->update_lock);
2199 data->pwm_mode[nr] = val;
2200 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2201 reg &= ~data->PWM_MODE_MASK[nr];
2202 if (val)
2203 reg |= data->PWM_MODE_MASK[nr];
2204 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2205 mutex_unlock(&data->update_lock);
2206 return count;
2207}
2208
2209static ssize_t
2210show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2211{
2212 struct nct6775_data *data = nct6775_update_device(dev);
2213 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2214 int nr = sattr->nr;
2215 int index = sattr->index;
2216 int pwm;
2217
2218 /*
2219 * For automatic fan control modes, show current pwm readings.
2220 * Otherwise, show the configured value.
2221 */
2222 if (index == 0 && data->pwm_enable[nr] > manual)
2223 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2224 else
2225 pwm = data->pwm[index][nr];
2226
2227 return sprintf(buf, "%d\n", pwm);
2228}
2229
2230static ssize_t
2231store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2232 size_t count)
2233{
2234 struct nct6775_data *data = dev_get_drvdata(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 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002239 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2240 int maxval[7]
2241 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002242 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002243 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002244
2245 err = kstrtoul(buf, 10, &val);
2246 if (err < 0)
2247 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002248 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002249
2250 mutex_lock(&data->update_lock);
2251 data->pwm[index][nr] = val;
2252 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002253 if (index == 2) { /* floor: disable if val == 0 */
2254 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2255 reg &= 0x7f;
2256 if (val)
2257 reg |= 0x80;
2258 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2259 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002260 mutex_unlock(&data->update_lock);
2261 return count;
2262}
2263
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002264/* Returns 0 if OK, -EINVAL otherwise */
2265static int check_trip_points(struct nct6775_data *data, int nr)
2266{
2267 int i;
2268
2269 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2270 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2271 return -EINVAL;
2272 }
2273 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2274 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2275 return -EINVAL;
2276 }
2277 /* validate critical temperature and pwm if enabled (pwm > 0) */
2278 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2279 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2280 data->auto_temp[nr][data->auto_pwm_num] ||
2281 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2282 data->auto_pwm[nr][data->auto_pwm_num])
2283 return -EINVAL;
2284 }
2285 return 0;
2286}
2287
2288static void pwm_update_registers(struct nct6775_data *data, int nr)
2289{
2290 u8 reg;
2291
2292 switch (data->pwm_enable[nr]) {
2293 case off:
2294 case manual:
2295 break;
2296 case speed_cruise:
2297 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2298 reg = (reg & ~data->tolerance_mask) |
2299 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2300 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2301 nct6775_write_value(data, data->REG_TARGET[nr],
2302 data->target_speed[nr] & 0xff);
2303 if (data->REG_TOLERANCE_H) {
2304 reg = (data->target_speed[nr] >> 8) & 0x0f;
2305 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2306 nct6775_write_value(data,
2307 data->REG_TOLERANCE_H[nr],
2308 reg);
2309 }
2310 break;
2311 case thermal_cruise:
2312 nct6775_write_value(data, data->REG_TARGET[nr],
2313 data->target_temp[nr]);
2314 /* intentional */
2315 default:
2316 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2317 reg = (reg & ~data->tolerance_mask) |
2318 data->temp_tolerance[0][nr];
2319 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2320 break;
2321 }
2322}
2323
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002324static ssize_t
2325show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2326{
2327 struct nct6775_data *data = nct6775_update_device(dev);
2328 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2329
2330 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2331}
2332
2333static ssize_t
2334store_pwm_enable(struct device *dev, struct device_attribute *attr,
2335 const char *buf, size_t count)
2336{
2337 struct nct6775_data *data = dev_get_drvdata(dev);
2338 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2339 int nr = sattr->index;
2340 unsigned long val;
2341 int err;
2342 u16 reg;
2343
2344 err = kstrtoul(buf, 10, &val);
2345 if (err < 0)
2346 return err;
2347
2348 if (val > sf4)
2349 return -EINVAL;
2350
2351 if (val == sf3 && data->kind != nct6775)
2352 return -EINVAL;
2353
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002354 if (val == sf4 && check_trip_points(data, nr)) {
2355 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2356 dev_err(dev, "Adjust trip points and try again\n");
2357 return -EINVAL;
2358 }
2359
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002360 mutex_lock(&data->update_lock);
2361 data->pwm_enable[nr] = val;
2362 if (val == off) {
2363 /*
2364 * turn off pwm control: select manual mode, set pwm to maximum
2365 */
2366 data->pwm[0][nr] = 255;
2367 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2368 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002369 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002370 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2371 reg &= 0x0f;
2372 reg |= pwm_enable_to_reg(val) << 4;
2373 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2374 mutex_unlock(&data->update_lock);
2375 return count;
2376}
2377
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002378static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002379show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002380{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002381 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002382
2383 for (i = 0; i < NUM_TEMP; i++) {
2384 if (!(data->have_temp & (1 << i)))
2385 continue;
2386 if (src == data->temp_src[i]) {
2387 sel = i + 1;
2388 break;
2389 }
2390 }
2391
2392 return sprintf(buf, "%d\n", sel);
2393}
2394
2395static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002396show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2397{
2398 struct nct6775_data *data = nct6775_update_device(dev);
2399 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2400 int index = sattr->index;
2401
2402 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2403}
2404
2405static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002406store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2407 const char *buf, size_t count)
2408{
2409 struct nct6775_data *data = nct6775_update_device(dev);
2410 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2411 int nr = sattr->index;
2412 unsigned long val;
2413 int err, reg, src;
2414
2415 err = kstrtoul(buf, 10, &val);
2416 if (err < 0)
2417 return err;
2418 if (val == 0 || val > NUM_TEMP)
2419 return -EINVAL;
2420 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2421 return -EINVAL;
2422
2423 mutex_lock(&data->update_lock);
2424 src = data->temp_src[val - 1];
2425 data->pwm_temp_sel[nr] = src;
2426 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2427 reg &= 0xe0;
2428 reg |= src;
2429 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2430 mutex_unlock(&data->update_lock);
2431
2432 return count;
2433}
2434
2435static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002436show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2437 char *buf)
2438{
2439 struct nct6775_data *data = nct6775_update_device(dev);
2440 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2441 int index = sattr->index;
2442
2443 return show_pwm_temp_sel_common(data, buf,
2444 data->pwm_weight_temp_sel[index]);
2445}
2446
2447static ssize_t
2448store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2449 const char *buf, size_t count)
2450{
2451 struct nct6775_data *data = nct6775_update_device(dev);
2452 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2453 int nr = sattr->index;
2454 unsigned long val;
2455 int err, reg, src;
2456
2457 err = kstrtoul(buf, 10, &val);
2458 if (err < 0)
2459 return err;
2460 if (val > NUM_TEMP)
2461 return -EINVAL;
2462 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2463 !data->temp_src[val - 1]))
2464 return -EINVAL;
2465
2466 mutex_lock(&data->update_lock);
2467 if (val) {
2468 src = data->temp_src[val - 1];
2469 data->pwm_weight_temp_sel[nr] = src;
2470 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2471 reg &= 0xe0;
2472 reg |= (src | 0x80);
2473 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2474 } else {
2475 data->pwm_weight_temp_sel[nr] = 0;
2476 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2477 reg &= 0x7f;
2478 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2479 }
2480 mutex_unlock(&data->update_lock);
2481
2482 return count;
2483}
2484
2485static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002486show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2487{
2488 struct nct6775_data *data = nct6775_update_device(dev);
2489 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2490
2491 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2492}
2493
2494static ssize_t
2495store_target_temp(struct device *dev, struct device_attribute *attr,
2496 const char *buf, size_t count)
2497{
2498 struct nct6775_data *data = dev_get_drvdata(dev);
2499 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2500 int nr = sattr->index;
2501 unsigned long val;
2502 int err;
2503
2504 err = kstrtoul(buf, 10, &val);
2505 if (err < 0)
2506 return err;
2507
2508 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2509 data->target_temp_mask);
2510
2511 mutex_lock(&data->update_lock);
2512 data->target_temp[nr] = val;
2513 pwm_update_registers(data, nr);
2514 mutex_unlock(&data->update_lock);
2515 return count;
2516}
2517
2518static ssize_t
2519show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2520{
2521 struct nct6775_data *data = nct6775_update_device(dev);
2522 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2523 int nr = sattr->index;
2524
2525 return sprintf(buf, "%d\n",
2526 fan_from_reg16(data->target_speed[nr],
2527 data->fan_div[nr]));
2528}
2529
2530static ssize_t
2531store_target_speed(struct device *dev, struct device_attribute *attr,
2532 const char *buf, size_t count)
2533{
2534 struct nct6775_data *data = dev_get_drvdata(dev);
2535 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2536 int nr = sattr->index;
2537 unsigned long val;
2538 int err;
2539 u16 speed;
2540
2541 err = kstrtoul(buf, 10, &val);
2542 if (err < 0)
2543 return err;
2544
2545 val = clamp_val(val, 0, 1350000U);
2546 speed = fan_to_reg(val, data->fan_div[nr]);
2547
2548 mutex_lock(&data->update_lock);
2549 data->target_speed[nr] = speed;
2550 pwm_update_registers(data, nr);
2551 mutex_unlock(&data->update_lock);
2552 return count;
2553}
2554
2555static ssize_t
2556show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2557 char *buf)
2558{
2559 struct nct6775_data *data = nct6775_update_device(dev);
2560 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2561 int nr = sattr->nr;
2562 int index = sattr->index;
2563
2564 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2565}
2566
2567static ssize_t
2568store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2569 const char *buf, size_t count)
2570{
2571 struct nct6775_data *data = dev_get_drvdata(dev);
2572 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2573 int nr = sattr->nr;
2574 int index = sattr->index;
2575 unsigned long val;
2576 int err;
2577
2578 err = kstrtoul(buf, 10, &val);
2579 if (err < 0)
2580 return err;
2581
2582 /* Limit tolerance as needed */
2583 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2584
2585 mutex_lock(&data->update_lock);
2586 data->temp_tolerance[index][nr] = val;
2587 if (index)
2588 pwm_update_registers(data, nr);
2589 else
2590 nct6775_write_value(data,
2591 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2592 val);
2593 mutex_unlock(&data->update_lock);
2594 return count;
2595}
2596
2597/*
2598 * Fan speed tolerance is a tricky beast, since the associated register is
2599 * a tick counter, but the value is reported and configured as rpm.
2600 * Compute resulting low and high rpm values and report the difference.
2601 */
2602static ssize_t
2603show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2604 char *buf)
2605{
2606 struct nct6775_data *data = nct6775_update_device(dev);
2607 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2608 int nr = sattr->index;
2609 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2610 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2611 int tolerance;
2612
2613 if (low <= 0)
2614 low = 1;
2615 if (high > 0xffff)
2616 high = 0xffff;
2617 if (high < low)
2618 high = low;
2619
2620 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2621 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2622
2623 return sprintf(buf, "%d\n", tolerance);
2624}
2625
2626static ssize_t
2627store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2628 const char *buf, size_t count)
2629{
2630 struct nct6775_data *data = dev_get_drvdata(dev);
2631 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2632 int nr = sattr->index;
2633 unsigned long val;
2634 int err;
2635 int low, high;
2636
2637 err = kstrtoul(buf, 10, &val);
2638 if (err < 0)
2639 return err;
2640
2641 high = fan_from_reg16(data->target_speed[nr],
2642 data->fan_div[nr]) + val;
2643 low = fan_from_reg16(data->target_speed[nr],
2644 data->fan_div[nr]) - val;
2645 if (low <= 0)
2646 low = 1;
2647 if (high < low)
2648 high = low;
2649
2650 val = (fan_to_reg(low, data->fan_div[nr]) -
2651 fan_to_reg(high, data->fan_div[nr])) / 2;
2652
2653 /* Limit tolerance as needed */
2654 val = clamp_val(val, 0, data->speed_tolerance_limit);
2655
2656 mutex_lock(&data->update_lock);
2657 data->target_speed_tolerance[nr] = val;
2658 pwm_update_registers(data, nr);
2659 mutex_unlock(&data->update_lock);
2660 return count;
2661}
2662
Guenter Roeckf73cf632013-03-18 09:22:50 -07002663SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2664SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2665 store_pwm_mode, 0);
2666SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2667 store_pwm_enable, 0);
2668SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2669 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2670SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2671 show_target_temp, store_target_temp, 0);
2672SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2673 show_target_speed, store_target_speed, 0);
2674SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2675 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002676
2677/* Smart Fan registers */
2678
2679static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002680show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2681{
2682 struct nct6775_data *data = nct6775_update_device(dev);
2683 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2684 int nr = sattr->nr;
2685 int index = sattr->index;
2686
2687 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2688}
2689
2690static ssize_t
2691store_weight_temp(struct device *dev, struct device_attribute *attr,
2692 const char *buf, size_t count)
2693{
2694 struct nct6775_data *data = dev_get_drvdata(dev);
2695 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2696 int nr = sattr->nr;
2697 int index = sattr->index;
2698 unsigned long val;
2699 int err;
2700
2701 err = kstrtoul(buf, 10, &val);
2702 if (err < 0)
2703 return err;
2704
2705 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2706
2707 mutex_lock(&data->update_lock);
2708 data->weight_temp[index][nr] = val;
2709 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2710 mutex_unlock(&data->update_lock);
2711 return count;
2712}
2713
Guenter Roeckf73cf632013-03-18 09:22:50 -07002714SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2715 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2716SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2717 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2718SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2719 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2720SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2721 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2722SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2723 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2724SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2725 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002726
2727static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002728show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2729{
2730 struct nct6775_data *data = nct6775_update_device(dev);
2731 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2732 int nr = sattr->nr;
2733 int index = sattr->index;
2734
2735 return sprintf(buf, "%d\n",
2736 step_time_from_reg(data->fan_time[index][nr],
2737 data->pwm_mode[nr]));
2738}
2739
2740static ssize_t
2741store_fan_time(struct device *dev, struct device_attribute *attr,
2742 const char *buf, size_t count)
2743{
2744 struct nct6775_data *data = dev_get_drvdata(dev);
2745 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2746 int nr = sattr->nr;
2747 int index = sattr->index;
2748 unsigned long val;
2749 int err;
2750
2751 err = kstrtoul(buf, 10, &val);
2752 if (err < 0)
2753 return err;
2754
2755 val = step_time_to_reg(val, data->pwm_mode[nr]);
2756 mutex_lock(&data->update_lock);
2757 data->fan_time[index][nr] = val;
2758 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2759 mutex_unlock(&data->update_lock);
2760 return count;
2761}
2762
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002763static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002764show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2765{
2766 struct nct6775_data *data = nct6775_update_device(dev);
2767 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2768
2769 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2770}
2771
2772static ssize_t
2773store_auto_pwm(struct device *dev, struct device_attribute *attr,
2774 const char *buf, size_t count)
2775{
2776 struct nct6775_data *data = dev_get_drvdata(dev);
2777 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2778 int nr = sattr->nr;
2779 int point = sattr->index;
2780 unsigned long val;
2781 int err;
2782 u8 reg;
2783
2784 err = kstrtoul(buf, 10, &val);
2785 if (err < 0)
2786 return err;
2787 if (val > 255)
2788 return -EINVAL;
2789
2790 if (point == data->auto_pwm_num) {
2791 if (data->kind != nct6775 && !val)
2792 return -EINVAL;
2793 if (data->kind != nct6779 && val)
2794 val = 0xff;
2795 }
2796
2797 mutex_lock(&data->update_lock);
2798 data->auto_pwm[nr][point] = val;
2799 if (point < data->auto_pwm_num) {
2800 nct6775_write_value(data,
2801 NCT6775_AUTO_PWM(data, nr, point),
2802 data->auto_pwm[nr][point]);
2803 } else {
2804 switch (data->kind) {
2805 case nct6775:
2806 /* disable if needed (pwm == 0) */
2807 reg = nct6775_read_value(data,
2808 NCT6775_REG_CRITICAL_ENAB[nr]);
2809 if (val)
2810 reg |= 0x02;
2811 else
2812 reg &= ~0x02;
2813 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2814 reg);
2815 break;
2816 case nct6776:
2817 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002818 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002819 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002820 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002821 case nct6792:
Guenter Roeck6c009502012-07-01 08:23:15 -07002822 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002823 val);
2824 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002825 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002826 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002827 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002828 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002829 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002830 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002831 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002832 reg);
2833 break;
2834 }
2835 }
2836 mutex_unlock(&data->update_lock);
2837 return count;
2838}
2839
2840static ssize_t
2841show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2842{
2843 struct nct6775_data *data = nct6775_update_device(dev);
2844 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2845 int nr = sattr->nr;
2846 int point = sattr->index;
2847
2848 /*
2849 * We don't know for sure if the temperature is signed or unsigned.
2850 * Assume it is unsigned.
2851 */
2852 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2853}
2854
2855static ssize_t
2856store_auto_temp(struct device *dev, struct device_attribute *attr,
2857 const char *buf, size_t count)
2858{
2859 struct nct6775_data *data = dev_get_drvdata(dev);
2860 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2861 int nr = sattr->nr;
2862 int point = sattr->index;
2863 unsigned long val;
2864 int err;
2865
2866 err = kstrtoul(buf, 10, &val);
2867 if (err)
2868 return err;
2869 if (val > 255000)
2870 return -EINVAL;
2871
2872 mutex_lock(&data->update_lock);
2873 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2874 if (point < data->auto_pwm_num) {
2875 nct6775_write_value(data,
2876 NCT6775_AUTO_TEMP(data, nr, point),
2877 data->auto_temp[nr][point]);
2878 } else {
2879 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2880 data->auto_temp[nr][point]);
2881 }
2882 mutex_unlock(&data->update_lock);
2883 return count;
2884}
2885
Guenter Roeckf73cf632013-03-18 09:22:50 -07002886static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2887 struct attribute *attr, int index)
2888{
2889 struct device *dev = container_of(kobj, struct device, kobj);
2890 struct nct6775_data *data = dev_get_drvdata(dev);
2891 int pwm = index / 36; /* pwm index */
2892 int nr = index % 36; /* attribute index */
2893
2894 if (!(data->has_pwm & (1 << pwm)))
2895 return 0;
2896
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002897 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2898 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2899 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002900 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2901 return 0;
2902 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2903 return 0;
2904 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2905 return 0;
2906
2907 if (nr >= 22 && nr <= 35) { /* auto point */
2908 int api = (nr - 22) / 2; /* auto point index */
2909
2910 if (api > data->auto_pwm_num)
2911 return 0;
2912 }
2913 return attr->mode;
2914}
2915
2916SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2917 show_fan_time, store_fan_time, 0, 0);
2918SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2919 show_fan_time, store_fan_time, 0, 1);
2920SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2921 show_fan_time, store_fan_time, 0, 2);
2922SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2923 store_pwm, 0, 1);
2924SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2925 store_pwm, 0, 2);
2926SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2927 show_temp_tolerance, store_temp_tolerance, 0, 0);
2928SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2929 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2930 0, 1);
2931
2932SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2933 0, 3);
2934
2935SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2936 store_pwm, 0, 4);
2937
2938SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2939 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2940SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2941 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2942
2943SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2944 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2945SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2946 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2947
2948SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2949 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2950SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2951 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2952
2953SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2954 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2955SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2956 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2957
2958SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2959 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2960SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2961 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2962
2963SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2964 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2965SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2966 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2967
2968SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2969 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2970SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2971 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2972
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002973/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002974 * nct6775_pwm_is_visible uses the index into the following array
2975 * to determine if attributes should be created or not.
2976 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002977 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002978static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
2979 &sensor_dev_template_pwm,
2980 &sensor_dev_template_pwm_mode,
2981 &sensor_dev_template_pwm_enable,
2982 &sensor_dev_template_pwm_temp_sel,
2983 &sensor_dev_template_pwm_temp_tolerance,
2984 &sensor_dev_template_pwm_crit_temp_tolerance,
2985 &sensor_dev_template_pwm_target_temp,
2986 &sensor_dev_template_fan_target,
2987 &sensor_dev_template_fan_tolerance,
2988 &sensor_dev_template_pwm_stop_time,
2989 &sensor_dev_template_pwm_step_up_time,
2990 &sensor_dev_template_pwm_step_down_time,
2991 &sensor_dev_template_pwm_start,
2992 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002993 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002994 &sensor_dev_template_pwm_weight_temp_step,
2995 &sensor_dev_template_pwm_weight_temp_step_tol,
2996 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002997 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002998 &sensor_dev_template_pwm_max, /* 19 */
2999 &sensor_dev_template_pwm_step, /* 20 */
3000 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3001 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3002 &sensor_dev_template_pwm_auto_point1_temp,
3003 &sensor_dev_template_pwm_auto_point2_pwm,
3004 &sensor_dev_template_pwm_auto_point2_temp,
3005 &sensor_dev_template_pwm_auto_point3_pwm,
3006 &sensor_dev_template_pwm_auto_point3_temp,
3007 &sensor_dev_template_pwm_auto_point4_pwm,
3008 &sensor_dev_template_pwm_auto_point4_temp,
3009 &sensor_dev_template_pwm_auto_point5_pwm,
3010 &sensor_dev_template_pwm_auto_point5_temp,
3011 &sensor_dev_template_pwm_auto_point6_pwm,
3012 &sensor_dev_template_pwm_auto_point6_temp,
3013 &sensor_dev_template_pwm_auto_point7_pwm,
3014 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003015
Guenter Roeckf73cf632013-03-18 09:22:50 -07003016 NULL
3017};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003018
Guenter Roeckf73cf632013-03-18 09:22:50 -07003019static struct sensor_template_group nct6775_pwm_template_group = {
3020 .templates = nct6775_attributes_pwm_template,
3021 .is_visible = nct6775_pwm_is_visible,
3022 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003023};
3024
3025static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003026show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3027{
3028 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003029
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003030 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3031}
3032
3033static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3034
Guenter Roecka6bd5872012-12-04 03:13:34 -08003035/* Case open detection */
3036
3037static ssize_t
3038clear_caseopen(struct device *dev, struct device_attribute *attr,
3039 const char *buf, size_t count)
3040{
3041 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003042 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3043 unsigned long val;
3044 u8 reg;
3045 int ret;
3046
3047 if (kstrtoul(buf, 10, &val) || val != 0)
3048 return -EINVAL;
3049
3050 mutex_lock(&data->update_lock);
3051
3052 /*
3053 * Use CR registers to clear caseopen status.
3054 * The CR registers are the same for all chips, and not all chips
3055 * support clearing the caseopen status through "regular" registers.
3056 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003057 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003058 if (ret) {
3059 count = ret;
3060 goto error;
3061 }
3062
Guenter Roeckdf612d52013-07-08 13:15:04 -07003063 superio_select(data->sioreg, NCT6775_LD_ACPI);
3064 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003065 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003066 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003067 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003068 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3069 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003070
3071 data->valid = false; /* Force cache refresh */
3072error:
3073 mutex_unlock(&data->update_lock);
3074 return count;
3075}
3076
Guenter Roeckf73cf632013-03-18 09:22:50 -07003077static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3078 clear_caseopen, INTRUSION_ALARM_BASE);
3079static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3080 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003081static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3082 store_beep, INTRUSION_ALARM_BASE);
3083static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3084 store_beep, INTRUSION_ALARM_BASE + 1);
3085static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3086 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003087
3088static umode_t nct6775_other_is_visible(struct kobject *kobj,
3089 struct attribute *attr, int index)
3090{
3091 struct device *dev = container_of(kobj, struct device, kobj);
3092 struct nct6775_data *data = dev_get_drvdata(dev);
3093
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003094 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003095 return 0;
3096
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003097 if (index == 1 || index == 2) {
3098 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003099 return 0;
3100 }
3101
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003102 if (index == 3 || index == 4) {
3103 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003104 return 0;
3105 }
3106
Guenter Roeckf73cf632013-03-18 09:22:50 -07003107 return attr->mode;
3108}
3109
3110/*
3111 * nct6775_other_is_visible uses the index into the following array
3112 * to determine if attributes should be created or not.
3113 * Any change in order or content must be matched.
3114 */
3115static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003116 &dev_attr_cpu0_vid.attr, /* 0 */
3117 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3118 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3119 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3120 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3121 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003122
3123 NULL
3124};
3125
3126static const struct attribute_group nct6775_group_other = {
3127 .attrs = nct6775_attributes_other,
3128 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003129};
3130
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003131static inline void nct6775_init_device(struct nct6775_data *data)
3132{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003133 int i;
3134 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003135
3136 /* Start monitoring if needed */
3137 if (data->REG_CONFIG) {
3138 tmp = nct6775_read_value(data, data->REG_CONFIG);
3139 if (!(tmp & 0x01))
3140 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3141 }
3142
Guenter Roeckaa136e52012-12-04 03:26:05 -08003143 /* Enable temperature sensors if needed */
3144 for (i = 0; i < NUM_TEMP; i++) {
3145 if (!(data->have_temp & (1 << i)))
3146 continue;
3147 if (!data->reg_temp_config[i])
3148 continue;
3149 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3150 if (tmp & 0x01)
3151 nct6775_write_value(data, data->reg_temp_config[i],
3152 tmp & 0xfe);
3153 }
3154
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003155 /* Enable VBAT monitoring if needed */
3156 tmp = nct6775_read_value(data, data->REG_VBAT);
3157 if (!(tmp & 0x01))
3158 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003159
3160 diode = nct6775_read_value(data, data->REG_DIODE);
3161
3162 for (i = 0; i < data->temp_fixed_num; i++) {
3163 if (!(data->have_temp_fixed & (1 << i)))
3164 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003165 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3166 data->temp_type[i]
3167 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003168 else /* thermistor */
3169 data->temp_type[i] = 4;
3170 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003171}
3172
Guenter Roeckf73cf632013-03-18 09:22:50 -07003173static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003174nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003175{
David Bartley578ab5f2013-06-24 22:28:28 -07003176 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3177 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003178 int sioreg = data->sioreg;
3179 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003180
3181 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3182 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003183 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003184
3185 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003186 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003187
3188 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003189 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003190 fan4min = false;
3191 fan5pin = false;
3192 fan6pin = false;
3193 pwm4pin = false;
3194 pwm5pin = false;
3195 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003196 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003197 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003198
Guenter Roeckdf612d52013-07-08 13:15:04 -07003199 superio_select(sioreg, NCT6775_LD_HWM);
3200 regval = superio_inb(sioreg, SIO_REG_ENABLE);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003201
3202 if (regval & 0x80)
3203 fan3pin = gpok;
3204 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003205 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003206
3207 if (regval & 0x40)
3208 fan4pin = gpok;
3209 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003210 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003211
3212 if (regval & 0x20)
3213 fan5pin = gpok;
3214 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003215 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003216
3217 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003218 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003219 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003220 pwm4pin = false;
3221 pwm5pin = false;
3222 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003223 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003224 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003225 fan3pin = !(regval & 0x80);
3226 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003227
3228 fan4pin = false;
3229 fan4min = false;
3230 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003231 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003232 pwm4pin = false;
3233 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003234 pwm6pin = false;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003235 } else { /* NCT6779D, NCT6791D, or NCT6792D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003236 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003237
3238 fan3pin = !(regval & (1 << 5));
3239 fan4pin = !(regval & (1 << 6));
3240 fan5pin = !(regval & (1 << 7));
3241
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003242 pwm3pin = !(regval & (1 << 0));
3243 pwm4pin = !(regval & (1 << 1));
3244 pwm5pin = !(regval & (1 << 2));
3245
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003246 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003247
Guenter Roeck8aefb932014-11-16 09:50:04 -08003248 if (data->kind == nct6791 || data->kind == nct6792) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003249 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003250 fan6pin = (regval & (1 << 1));
3251 pwm6pin = (regval & (1 << 0));
3252 } else { /* NCT6779D */
3253 fan6pin = false;
3254 pwm6pin = false;
3255 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003256 }
3257
David Bartley578ab5f2013-06-24 22:28:28 -07003258 /* fan 1 and 2 (0x03) are always present */
3259 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3260 (fan5pin << 4) | (fan6pin << 5);
3261 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3262 (fan5pin << 4);
3263 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3264 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003265}
3266
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003267static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3268 int *available, int *mask)
3269{
3270 int i;
3271 u8 src;
3272
3273 for (i = 0; i < data->pwm_num && *available; i++) {
3274 int index;
3275
3276 if (!regp[i])
3277 continue;
3278 src = nct6775_read_value(data, regp[i]);
3279 src &= 0x1f;
3280 if (!src || (*mask & (1 << src)))
3281 continue;
3282 if (src >= data->temp_label_num ||
3283 !strlen(data->temp_label[src]))
3284 continue;
3285
3286 index = __ffs(*available);
3287 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3288 *available &= ~(1 << index);
3289 *mask |= 1 << src;
3290 }
3291}
3292
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003293static int nct6775_probe(struct platform_device *pdev)
3294{
3295 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003296 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003297 struct nct6775_data *data;
3298 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003299 int i, s, err = 0;
3300 int src, mask, available;
3301 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003302 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003303 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003304 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003305 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003306 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003307 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003308 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003309
3310 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3311 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3312 DRVNAME))
3313 return -EBUSY;
3314
3315 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3316 GFP_KERNEL);
3317 if (!data)
3318 return -ENOMEM;
3319
3320 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003321 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003322 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003323 mutex_init(&data->update_lock);
3324 data->name = nct6775_device_names[data->kind];
3325 data->bank = 0xff; /* Force initial bank selection */
3326 platform_set_drvdata(pdev, data);
3327
3328 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003329 case nct6106:
3330 data->in_num = 9;
3331 data->pwm_num = 3;
3332 data->auto_pwm_num = 4;
3333 data->temp_fixed_num = 3;
3334 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003335 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003336
3337 data->fan_from_reg = fan_from_reg13;
3338 data->fan_from_reg_min = fan_from_reg13;
3339
3340 data->temp_label = nct6776_temp_label;
3341 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3342
3343 data->REG_VBAT = NCT6106_REG_VBAT;
3344 data->REG_DIODE = NCT6106_REG_DIODE;
3345 data->DIODE_MASK = NCT6106_DIODE_MASK;
3346 data->REG_VIN = NCT6106_REG_IN;
3347 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3348 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3349 data->REG_TARGET = NCT6106_REG_TARGET;
3350 data->REG_FAN = NCT6106_REG_FAN;
3351 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3352 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3353 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3354 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3355 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3356 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3357 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3358 data->REG_PWM[0] = NCT6106_REG_PWM;
3359 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3360 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3361 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3362 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3363 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3364 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3365 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3366 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3367 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3368 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3369 data->REG_CRITICAL_TEMP_TOLERANCE
3370 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3371 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3372 data->CRITICAL_PWM_ENABLE_MASK
3373 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3374 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3375 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3376 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3377 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3378 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3379 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3380 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3381 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3382 data->REG_ALARM = NCT6106_REG_ALARM;
3383 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003384 data->REG_BEEP = NCT6106_REG_BEEP;
3385 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003386
3387 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003388 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003389 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003390 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003391 reg_temp_over = NCT6106_REG_TEMP_OVER;
3392 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3393 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3394 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3395 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003396 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3397 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003398
3399 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003400 case nct6775:
3401 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003402 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003403 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003404 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003405 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003406 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003407 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003408
3409 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003410 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003411
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003412 data->fan_from_reg = fan_from_reg16;
3413 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003414 data->target_temp_mask = 0x7f;
3415 data->tolerance_mask = 0x0f;
3416 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003417
Guenter Roeckaa136e52012-12-04 03:26:05 -08003418 data->temp_label = nct6775_temp_label;
3419 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3420
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003421 data->REG_CONFIG = NCT6775_REG_CONFIG;
3422 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003423 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003424 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003425 data->REG_VIN = NCT6775_REG_IN;
3426 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3427 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003428 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003429 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003430 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003431 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003432 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003433 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003434 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3435 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3436 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003437 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003438 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3439 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3440 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3441 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003442 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003443 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3444 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3445 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003446 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3447 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3448 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3449 data->REG_CRITICAL_TEMP_TOLERANCE
3450 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003451 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3452 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003453 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003454 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3455 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3456 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3457 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003458 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003459 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003460
3461 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003462 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003463 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003464 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003465 reg_temp_over = NCT6775_REG_TEMP_OVER;
3466 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3467 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3468 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3469 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3470
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003471 break;
3472 case nct6776:
3473 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003474 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003475 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003476 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003477 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003478 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003479 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003480
3481 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003482 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003483
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003484 data->fan_from_reg = fan_from_reg13;
3485 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003486 data->target_temp_mask = 0xff;
3487 data->tolerance_mask = 0x07;
3488 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003489
Guenter Roeckaa136e52012-12-04 03:26:05 -08003490 data->temp_label = nct6776_temp_label;
3491 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3492
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003493 data->REG_CONFIG = NCT6775_REG_CONFIG;
3494 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003495 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003496 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003497 data->REG_VIN = NCT6775_REG_IN;
3498 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3499 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003500 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003501 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003502 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003503 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003504 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003505 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003506 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3507 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3508 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3509 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003510 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003511 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3512 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003513 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3514 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003515 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3516 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3517 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003518 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3519 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3520 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3521 data->REG_CRITICAL_TEMP_TOLERANCE
3522 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003523 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3524 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003525 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003526 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3527 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3528 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3529 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003530 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003531 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003532
3533 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003534 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003535 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003536 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003537 reg_temp_over = NCT6775_REG_TEMP_OVER;
3538 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3539 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3540 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3541 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3542
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003543 break;
3544 case nct6779:
3545 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003546 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003547 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003548 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003549 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003550 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003551 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003552
3553 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003554 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003555
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003556 data->fan_from_reg = fan_from_reg13;
3557 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003558 data->target_temp_mask = 0xff;
3559 data->tolerance_mask = 0x07;
3560 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003561
Guenter Roeckaa136e52012-12-04 03:26:05 -08003562 data->temp_label = nct6779_temp_label;
3563 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3564
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003565 data->REG_CONFIG = NCT6775_REG_CONFIG;
3566 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003567 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003568 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003569 data->REG_VIN = NCT6779_REG_IN;
3570 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3571 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003572 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003573 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003574 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003575 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003576 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003577 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003578 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3579 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3580 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3581 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003582 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003583 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3584 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003585 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3586 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003587 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3588 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3589 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003590 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3591 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3592 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3593 data->REG_CRITICAL_TEMP_TOLERANCE
3594 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003595 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3596 data->CRITICAL_PWM_ENABLE_MASK
3597 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3598 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003599 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3600 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003601 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003602 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3603 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3604 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3605 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003606 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003607 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003608
3609 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003610 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003611 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003612 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003613 reg_temp_over = NCT6779_REG_TEMP_OVER;
3614 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3615 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3616 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3617 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3618
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003619 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003620 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003621 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003622 data->in_num = 15;
3623 data->pwm_num = 6;
3624 data->auto_pwm_num = 4;
3625 data->has_fan_div = false;
3626 data->temp_fixed_num = 6;
3627 data->num_temp_alarms = 2;
3628 data->num_temp_beeps = 2;
3629
3630 data->ALARM_BITS = NCT6791_ALARM_BITS;
3631 data->BEEP_BITS = NCT6779_BEEP_BITS;
3632
3633 data->fan_from_reg = fan_from_reg13;
3634 data->fan_from_reg_min = fan_from_reg13;
3635 data->target_temp_mask = 0xff;
3636 data->tolerance_mask = 0x07;
3637 data->speed_tolerance_limit = 63;
3638
3639 data->temp_label = nct6779_temp_label;
3640 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3641
3642 data->REG_CONFIG = NCT6775_REG_CONFIG;
3643 data->REG_VBAT = NCT6775_REG_VBAT;
3644 data->REG_DIODE = NCT6775_REG_DIODE;
3645 data->DIODE_MASK = NCT6775_DIODE_MASK;
3646 data->REG_VIN = NCT6779_REG_IN;
3647 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3648 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3649 data->REG_TARGET = NCT6775_REG_TARGET;
3650 data->REG_FAN = NCT6779_REG_FAN;
3651 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3652 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3653 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3654 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3655 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3656 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3657 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3658 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3659 data->REG_PWM[0] = NCT6775_REG_PWM;
3660 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3661 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003662 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3663 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003664 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3665 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3666 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3667 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3668 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3669 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3670 data->REG_CRITICAL_TEMP_TOLERANCE
3671 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3672 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3673 data->CRITICAL_PWM_ENABLE_MASK
3674 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3675 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3676 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3677 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3678 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003679 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3680 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3681 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3682 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003683 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003684 if (data->kind == nct6791)
3685 data->REG_BEEP = NCT6776_REG_BEEP;
3686 else
3687 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003688
3689 reg_temp = NCT6779_REG_TEMP;
3690 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003691 if (data->kind == nct6791) {
3692 reg_temp_mon = NCT6779_REG_TEMP_MON;
3693 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3694 } else {
3695 reg_temp_mon = NCT6792_REG_TEMP_MON;
3696 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3697 }
David Bartley578ab5f2013-06-24 22:28:28 -07003698 reg_temp_over = NCT6779_REG_TEMP_OVER;
3699 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3700 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3701 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3702 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3703
3704 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003705 default:
3706 return -ENODEV;
3707 }
3708 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003709 data->have_temp = 0;
3710
3711 /*
3712 * On some boards, not all available temperature sources are monitored,
3713 * even though some of the monitoring registers are unused.
3714 * Get list of unused monitoring registers, then detect if any fan
3715 * controls are configured to use unmonitored temperature sources.
3716 * If so, assign the unmonitored temperature sources to available
3717 * monitoring registers.
3718 */
3719 mask = 0;
3720 available = 0;
3721 for (i = 0; i < num_reg_temp; i++) {
3722 if (reg_temp[i] == 0)
3723 continue;
3724
3725 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3726 if (!src || (mask & (1 << src)))
3727 available |= 1 << i;
3728
3729 mask |= 1 << src;
3730 }
3731
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003732 /*
3733 * Now find unmonitored temperature registers and enable monitoring
3734 * if additional monitoring registers are available.
3735 */
3736 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3737 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3738
Guenter Roeckaa136e52012-12-04 03:26:05 -08003739 mask = 0;
3740 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3741 for (i = 0; i < num_reg_temp; i++) {
3742 if (reg_temp[i] == 0)
3743 continue;
3744
3745 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3746 if (!src || (mask & (1 << src)))
3747 continue;
3748
3749 if (src >= data->temp_label_num ||
3750 !strlen(data->temp_label[src])) {
3751 dev_info(dev,
3752 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3753 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3754 continue;
3755 }
3756
3757 mask |= 1 << src;
3758
3759 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3760 if (src <= data->temp_fixed_num) {
3761 data->have_temp |= 1 << (src - 1);
3762 data->have_temp_fixed |= 1 << (src - 1);
3763 data->reg_temp[0][src - 1] = reg_temp[i];
3764 data->reg_temp[1][src - 1] = reg_temp_over[i];
3765 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003766 if (reg_temp_crit_h && reg_temp_crit_h[i])
3767 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3768 else if (reg_temp_crit[src - 1])
3769 data->reg_temp[3][src - 1]
3770 = reg_temp_crit[src - 1];
3771 if (reg_temp_crit_l && reg_temp_crit_l[i])
3772 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003773 data->reg_temp_config[src - 1] = reg_temp_config[i];
3774 data->temp_src[src - 1] = src;
3775 continue;
3776 }
3777
3778 if (s >= NUM_TEMP)
3779 continue;
3780
3781 /* Use dynamic index for other sources */
3782 data->have_temp |= 1 << s;
3783 data->reg_temp[0][s] = reg_temp[i];
3784 data->reg_temp[1][s] = reg_temp_over[i];
3785 data->reg_temp[2][s] = reg_temp_hyst[i];
3786 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003787 if (reg_temp_crit_h && reg_temp_crit_h[i])
3788 data->reg_temp[3][s] = reg_temp_crit_h[i];
3789 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003790 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003791 if (reg_temp_crit_l && reg_temp_crit_l[i])
3792 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003793
3794 data->temp_src[s] = src;
3795 s++;
3796 }
3797
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003798 /*
3799 * Repeat with temperatures used for fan control.
3800 * This set of registers does not support limits.
3801 */
3802 for (i = 0; i < num_reg_temp_mon; i++) {
3803 if (reg_temp_mon[i] == 0)
3804 continue;
3805
3806 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3807 if (!src || (mask & (1 << src)))
3808 continue;
3809
3810 if (src >= data->temp_label_num ||
3811 !strlen(data->temp_label[src])) {
3812 dev_info(dev,
3813 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3814 src, i, data->REG_TEMP_SEL[i],
3815 reg_temp_mon[i]);
3816 continue;
3817 }
3818
3819 mask |= 1 << src;
3820
3821 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3822 if (src <= data->temp_fixed_num) {
3823 if (data->have_temp & (1 << (src - 1)))
3824 continue;
3825 data->have_temp |= 1 << (src - 1);
3826 data->have_temp_fixed |= 1 << (src - 1);
3827 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3828 data->temp_src[src - 1] = src;
3829 continue;
3830 }
3831
3832 if (s >= NUM_TEMP)
3833 continue;
3834
3835 /* Use dynamic index for other sources */
3836 data->have_temp |= 1 << s;
3837 data->reg_temp[0][s] = reg_temp_mon[i];
3838 data->temp_src[s] = src;
3839 s++;
3840 }
3841
Guenter Roeckaa136e52012-12-04 03:26:05 -08003842#ifdef USE_ALTERNATE
3843 /*
3844 * Go through the list of alternate temp registers and enable
3845 * if possible.
3846 * The temperature is already monitored if the respective bit in <mask>
3847 * is set.
3848 */
3849 for (i = 0; i < data->temp_label_num - 1; i++) {
3850 if (!reg_temp_alternate[i])
3851 continue;
3852 if (mask & (1 << (i + 1)))
3853 continue;
3854 if (i < data->temp_fixed_num) {
3855 if (data->have_temp & (1 << i))
3856 continue;
3857 data->have_temp |= 1 << i;
3858 data->have_temp_fixed |= 1 << i;
3859 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07003860 if (i < num_reg_temp) {
3861 data->reg_temp[1][i] = reg_temp_over[i];
3862 data->reg_temp[2][i] = reg_temp_hyst[i];
3863 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003864 data->temp_src[i] = i + 1;
3865 continue;
3866 }
3867
3868 if (s >= NUM_TEMP) /* Abort if no more space */
3869 break;
3870
3871 data->have_temp |= 1 << s;
3872 data->reg_temp[0][s] = reg_temp_alternate[i];
3873 data->temp_src[s] = i + 1;
3874 s++;
3875 }
3876#endif /* USE_ALTERNATE */
3877
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003878 /* Initialize the chip */
3879 nct6775_init_device(data);
3880
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003881 err = superio_enter(sio_data->sioreg);
3882 if (err)
3883 return err;
3884
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003885 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3886 switch (data->kind) {
3887 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003888 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003889 break;
3890 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003891 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003892 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003893 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003894 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003895 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003896 case nct6792:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003897 break;
3898 }
3899
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003900 /*
3901 * Read VID value
3902 * We can get the VID input values directly at logical device D 0xe3.
3903 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003904 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003905 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3906 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3907 data->vrm = vid_which_vrm();
3908 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003909
3910 if (fan_debounce) {
3911 u8 tmp;
3912
3913 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3914 tmp = superio_inb(sio_data->sioreg,
3915 NCT6775_REG_CR_FAN_DEBOUNCE);
3916 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003917 case nct6106:
3918 tmp |= 0xe0;
3919 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003920 case nct6775:
3921 tmp |= 0x1e;
3922 break;
3923 case nct6776:
3924 case nct6779:
3925 tmp |= 0x3e;
3926 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003927 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003928 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003929 tmp |= 0x7e;
3930 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003931 }
3932 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3933 tmp);
3934 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3935 data->name);
3936 }
3937
Guenter Roeckdf612d52013-07-08 13:15:04 -07003938 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003939
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003940 superio_exit(sio_data->sioreg);
3941
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003942 /* Read fan clock dividers immediately */
3943 nct6775_init_fan_common(dev, data);
3944
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003945 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003946 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3947 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003948 if (IS_ERR(group))
3949 return PTR_ERR(group);
3950
Axel Lin55bdee62014-07-24 08:59:34 +08003951 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003952
Guenter Roeckf73cf632013-03-18 09:22:50 -07003953 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
3954 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003955 if (IS_ERR(group))
3956 return PTR_ERR(group);
3957
Axel Lin55bdee62014-07-24 08:59:34 +08003958 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003959
Guenter Roeckf73cf632013-03-18 09:22:50 -07003960 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
3961 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003962 if (IS_ERR(group))
3963 return PTR_ERR(group);
3964
Axel Lin55bdee62014-07-24 08:59:34 +08003965 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003966
Guenter Roeckf73cf632013-03-18 09:22:50 -07003967 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
3968 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003969 if (IS_ERR(group))
3970 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003971
Axel Lin55bdee62014-07-24 08:59:34 +08003972 data->groups[num_attr_groups++] = group;
3973 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003974
Guenter Roecka150d952013-07-11 22:55:22 -07003975 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
3976 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07003977 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003978}
3979
Guenter Roeckf5776cc2013-12-25 07:25:59 -08003980static void nct6791_enable_io_mapping(int sioaddr)
3981{
3982 int val;
3983
3984 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
3985 if (val & 0x10) {
3986 pr_info("Enabling hardware monitor logical device mappings.\n");
3987 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
3988 val & ~0x10);
3989 }
3990}
3991
Guenter Roeck84d19d92012-12-04 08:01:39 -08003992#ifdef CONFIG_PM
3993static int nct6775_suspend(struct device *dev)
3994{
3995 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08003996
3997 mutex_lock(&data->update_lock);
3998 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07003999 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004000 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
4001 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4002 }
4003 mutex_unlock(&data->update_lock);
4004
4005 return 0;
4006}
4007
4008static int nct6775_resume(struct device *dev)
4009{
4010 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004011 int i, j, err = 0;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004012
4013 mutex_lock(&data->update_lock);
4014 data->bank = 0xff; /* Force initial bank selection */
4015
Guenter Roeck8aefb932014-11-16 09:50:04 -08004016 if (data->kind == nct6791 || data->kind == nct6792) {
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004017 err = superio_enter(data->sioreg);
4018 if (err)
4019 goto abort;
4020
4021 nct6791_enable_io_mapping(data->sioreg);
4022 superio_exit(data->sioreg);
4023 }
4024
Guenter Roeck84d19d92012-12-04 08:01:39 -08004025 /* Restore limits */
4026 for (i = 0; i < data->in_num; i++) {
4027 if (!(data->have_in & (1 << i)))
4028 continue;
4029
4030 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4031 data->in[i][1]);
4032 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4033 data->in[i][2]);
4034 }
4035
Guenter Roeckc409fd42013-04-09 05:04:00 -07004036 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004037 if (!(data->has_fan_min & (1 << i)))
4038 continue;
4039
4040 nct6775_write_value(data, data->REG_FAN_MIN[i],
4041 data->fan_min[i]);
4042 }
4043
4044 for (i = 0; i < NUM_TEMP; i++) {
4045 if (!(data->have_temp & (1 << i)))
4046 continue;
4047
Guenter Roeckc409fd42013-04-09 05:04:00 -07004048 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004049 if (data->reg_temp[j][i])
4050 nct6775_write_temp(data, data->reg_temp[j][i],
4051 data->temp[j][i]);
4052 }
4053
4054 /* Restore other settings */
4055 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004056 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004057 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4058 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4059 }
4060
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004061abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004062 /* Force re-reading all values */
4063 data->valid = false;
4064 mutex_unlock(&data->update_lock);
4065
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004066 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004067}
4068
4069static const struct dev_pm_ops nct6775_dev_pm_ops = {
4070 .suspend = nct6775_suspend,
4071 .resume = nct6775_resume,
Harald Judt374d1f92013-07-30 19:50:16 +02004072 .freeze = nct6775_suspend,
4073 .restore = nct6775_resume,
Guenter Roeck84d19d92012-12-04 08:01:39 -08004074};
4075
4076#define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops)
4077#else
4078#define NCT6775_DEV_PM_OPS NULL
4079#endif /* CONFIG_PM */
4080
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004081static struct platform_driver nct6775_driver = {
4082 .driver = {
4083 .owner = THIS_MODULE,
4084 .name = DRVNAME,
Guenter Roeck84d19d92012-12-04 08:01:39 -08004085 .pm = NCT6775_DEV_PM_OPS,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004086 },
4087 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004088};
4089
Guenter Roeck6d4b3622013-04-21 09:08:11 -07004090static const char * const nct6775_sio_names[] __initconst = {
Guenter Roeck6c009502012-07-01 08:23:15 -07004091 "NCT6106D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004092 "NCT6775F",
4093 "NCT6776D/F",
4094 "NCT6779D",
David Bartley578ab5f2013-06-24 22:28:28 -07004095 "NCT6791D",
Guenter Roeck8aefb932014-11-16 09:50:04 -08004096 "NCT6792D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004097};
4098
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004099/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004100static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004101{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004102 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004103 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004104 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004105
4106 err = superio_enter(sioaddr);
4107 if (err)
4108 return err;
4109
4110 if (force_id)
4111 val = force_id;
4112 else
4113 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4114 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4115 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004116 case SIO_NCT6106_ID:
4117 sio_data->kind = nct6106;
4118 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004119 case SIO_NCT6775_ID:
4120 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004121 break;
4122 case SIO_NCT6776_ID:
4123 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004124 break;
4125 case SIO_NCT6779_ID:
4126 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004127 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004128 case SIO_NCT6791_ID:
4129 sio_data->kind = nct6791;
4130 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004131 case SIO_NCT6792_ID:
4132 sio_data->kind = nct6792;
4133 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004134 default:
4135 if (val != 0xffff)
4136 pr_debug("unsupported chip ID: 0x%04x\n", val);
4137 superio_exit(sioaddr);
4138 return -ENODEV;
4139 }
4140
4141 /* We have a known chip, find the HWM I/O address */
4142 superio_select(sioaddr, NCT6775_LD_HWM);
4143 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4144 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004145 addr = val & IOREGION_ALIGNMENT;
4146 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004147 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4148 superio_exit(sioaddr);
4149 return -ENODEV;
4150 }
4151
4152 /* Activate logical device if needed */
4153 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4154 if (!(val & 0x01)) {
4155 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4156 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4157 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004158
Guenter Roeck8aefb932014-11-16 09:50:04 -08004159 if (sio_data->kind == nct6791 || sio_data->kind == nct6792)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004160 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004161
4162 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004163 pr_info("Found %s or compatible chip at %#x:%#x\n",
4164 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004165 sio_data->sioreg = sioaddr;
4166
Guenter Roeck698a7c22013-04-05 07:35:25 -07004167 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004168}
4169
4170/*
4171 * when Super-I/O functions move to a separate file, the Super-I/O
4172 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004173 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004174 * must keep track of the device
4175 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004176static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004177
4178static int __init sensors_nct6775_init(void)
4179{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004180 int i, err;
4181 bool found = false;
4182 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004183 struct resource res;
4184 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004185 int sioaddr[2] = { 0x2e, 0x4e };
4186
4187 err = platform_driver_register(&nct6775_driver);
4188 if (err)
4189 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004190
4191 /*
4192 * initialize sio_data->kind and sio_data->sioreg.
4193 *
4194 * when Super-I/O functions move to a separate file, the Super-I/O
4195 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4196 * nct6775 hardware monitor, and call probe()
4197 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004198 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4199 address = nct6775_find(sioaddr[i], &sio_data);
4200 if (address <= 0)
4201 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004202
Guenter Roeck698a7c22013-04-05 07:35:25 -07004203 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004204
Guenter Roeck698a7c22013-04-05 07:35:25 -07004205 pdev[i] = platform_device_alloc(DRVNAME, address);
4206 if (!pdev[i]) {
4207 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004208 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004209 }
4210
4211 err = platform_device_add_data(pdev[i], &sio_data,
4212 sizeof(struct nct6775_sio_data));
4213 if (err)
4214 goto exit_device_put;
4215
4216 memset(&res, 0, sizeof(res));
4217 res.name = DRVNAME;
4218 res.start = address + IOREGION_OFFSET;
4219 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4220 res.flags = IORESOURCE_IO;
4221
4222 err = acpi_check_resource_conflict(&res);
4223 if (err) {
4224 platform_device_put(pdev[i]);
4225 pdev[i] = NULL;
4226 continue;
4227 }
4228
4229 err = platform_device_add_resources(pdev[i], &res, 1);
4230 if (err)
4231 goto exit_device_put;
4232
4233 /* platform_device_add calls probe() */
4234 err = platform_device_add(pdev[i]);
4235 if (err)
4236 goto exit_device_put;
4237 }
4238 if (!found) {
4239 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004240 goto exit_unregister;
4241 }
4242
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004243 return 0;
4244
4245exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004246 platform_device_put(pdev[i]);
4247exit_device_unregister:
4248 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004249 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004250 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004251 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004252exit_unregister:
4253 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004254 return err;
4255}
4256
4257static void __exit sensors_nct6775_exit(void)
4258{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004259 int i;
4260
4261 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4262 if (pdev[i])
4263 platform_device_unregister(pdev[i]);
4264 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004265 platform_driver_unregister(&nct6775_driver);
4266}
4267
4268MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeck8aefb932014-11-16 09:50:04 -08004269MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004270MODULE_LICENSE("GPL");
4271
4272module_init(sensors_nct6775_init);
4273module_exit(sensors_nct6775_exit);