blob: db6a68efc3895da547d2d80f33a1d17f68fa5dbc [file] [log] [blame]
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001/*
2 * nct6775 - Driver for the hardware monitoring functionality of
3 * Nuvoton NCT677x Super-I/O chips
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from w83627ehf driver
Jean Delvare7c81c602014-01-29 20:40:08 +01008 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07009 * Copyright (C) 2006 Yuan Mu (Winbond),
10 * Rudolf Marek <r.marek@assembler.cz>
11 * David Hubbard <david.c.hubbard@gmail.com>
12 * Daniel J Blueman <daniel.blueman@gmail.com>
13 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
14 *
15 * Shamelessly ripped from the w83627hf driver
16 * Copyright (C) 2003 Mark Studebaker
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 *
33 * Supports the following chips:
34 *
35 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070036 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070037 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
38 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
39 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070040 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080041 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter 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 Roeck48e93182015-02-07 08:48:49 -0800883
Guenter Roeck84d19d92012-12-04 08:01:39 -0800884 /* Remember extra register values over suspend/resume */
885 u8 vbat;
886 u8 fandiv1;
887 u8 fandiv2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700888};
889
890struct nct6775_sio_data {
891 int sioreg;
892 enum kinds kind;
893};
894
Guenter Roeckf73cf632013-03-18 09:22:50 -0700895struct sensor_device_template {
896 struct device_attribute dev_attr;
897 union {
898 struct {
899 u8 nr;
900 u8 index;
901 } s;
902 int index;
903 } u;
904 bool s2; /* true if both index and nr are used */
905};
906
907struct sensor_device_attr_u {
908 union {
909 struct sensor_device_attribute a1;
910 struct sensor_device_attribute_2 a2;
911 } u;
912 char name[32];
913};
914
915#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
916 .attr = {.name = _template, .mode = _mode }, \
917 .show = _show, \
918 .store = _store, \
919}
920
921#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
922 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
923 .u.index = _index, \
924 .s2 = false }
925
926#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
927 _nr, _index) \
928 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
929 .u.s.index = _index, \
930 .u.s.nr = _nr, \
931 .s2 = true }
932
933#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
934static struct sensor_device_template sensor_dev_template_##_name \
935 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
936 _index)
937
938#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
939 _nr, _index) \
940static struct sensor_device_template sensor_dev_template_##_name \
941 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
942 _nr, _index)
943
944struct sensor_template_group {
945 struct sensor_device_template **templates;
946 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
947 int base;
948};
949
950static struct attribute_group *
951nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
952 int repeat)
953{
954 struct attribute_group *group;
955 struct sensor_device_attr_u *su;
956 struct sensor_device_attribute *a;
957 struct sensor_device_attribute_2 *a2;
958 struct attribute **attrs;
959 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300960 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -0700961
962 if (repeat <= 0)
963 return ERR_PTR(-EINVAL);
964
965 t = tg->templates;
966 for (count = 0; *t; t++, count++)
967 ;
968
969 if (count == 0)
970 return ERR_PTR(-EINVAL);
971
972 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
973 if (group == NULL)
974 return ERR_PTR(-ENOMEM);
975
976 attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
977 GFP_KERNEL);
978 if (attrs == NULL)
979 return ERR_PTR(-ENOMEM);
980
981 su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
982 GFP_KERNEL);
983 if (su == NULL)
984 return ERR_PTR(-ENOMEM);
985
986 group->attrs = attrs;
987 group->is_visible = tg->is_visible;
988
989 for (i = 0; i < repeat; i++) {
990 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +0300991 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -0700992 snprintf(su->name, sizeof(su->name),
993 (*t)->dev_attr.attr.name, tg->base + i);
994 if ((*t)->s2) {
995 a2 = &su->u.a2;
996 a2->dev_attr.attr.name = su->name;
997 a2->nr = (*t)->u.s.nr + i;
998 a2->index = (*t)->u.s.index;
999 a2->dev_attr.attr.mode =
1000 (*t)->dev_attr.attr.mode;
1001 a2->dev_attr.show = (*t)->dev_attr.show;
1002 a2->dev_attr.store = (*t)->dev_attr.store;
1003 *attrs = &a2->dev_attr.attr;
1004 } else {
1005 a = &su->u.a1;
1006 a->dev_attr.attr.name = su->name;
1007 a->index = (*t)->u.index + i;
1008 a->dev_attr.attr.mode =
1009 (*t)->dev_attr.attr.mode;
1010 a->dev_attr.show = (*t)->dev_attr.show;
1011 a->dev_attr.store = (*t)->dev_attr.store;
1012 *attrs = &a->dev_attr.attr;
1013 }
1014 attrs++;
1015 su++;
1016 t++;
1017 }
1018 }
1019
Guenter Roeckf73cf632013-03-18 09:22:50 -07001020 return group;
1021}
1022
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001023static bool is_word_sized(struct nct6775_data *data, u16 reg)
1024{
1025 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001026 case nct6106:
1027 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1028 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1029 reg == 0x111 || reg == 0x121 || reg == 0x131;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001030 case nct6775:
1031 return (((reg & 0xff00) == 0x100 ||
1032 (reg & 0xff00) == 0x200) &&
1033 ((reg & 0x00ff) == 0x50 ||
1034 (reg & 0x00ff) == 0x53 ||
1035 (reg & 0x00ff) == 0x55)) ||
1036 (reg & 0xfff0) == 0x630 ||
1037 reg == 0x640 || reg == 0x642 ||
1038 reg == 0x662 ||
1039 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1040 reg == 0x73 || reg == 0x75 || reg == 0x77;
1041 case nct6776:
1042 return (((reg & 0xff00) == 0x100 ||
1043 (reg & 0xff00) == 0x200) &&
1044 ((reg & 0x00ff) == 0x50 ||
1045 (reg & 0x00ff) == 0x53 ||
1046 (reg & 0x00ff) == 0x55)) ||
1047 (reg & 0xfff0) == 0x630 ||
1048 reg == 0x402 ||
1049 reg == 0x640 || reg == 0x642 ||
1050 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1051 reg == 0x73 || reg == 0x75 || reg == 0x77;
1052 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001053 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001054 case nct6792:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001055 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
David Bartley578ab5f2013-06-24 22:28:28 -07001056 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001057 reg == 0x402 ||
1058 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
1059 reg == 0x640 || reg == 0x642 ||
1060 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001061 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001062 }
1063 return false;
1064}
1065
1066/*
1067 * On older chips, only registers 0x50-0x5f are banked.
1068 * On more recent chips, all registers are banked.
1069 * Assume that is the case and set the bank number for each access.
1070 * Cache the bank number so it only needs to be set if it changes.
1071 */
1072static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1073{
1074 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001075
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001076 if (data->bank != bank) {
1077 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1078 outb_p(bank, data->addr + DATA_REG_OFFSET);
1079 data->bank = bank;
1080 }
1081}
1082
1083static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1084{
1085 int res, word_sized = is_word_sized(data, reg);
1086
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001087 nct6775_set_bank(data, reg);
1088 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1089 res = inb_p(data->addr + DATA_REG_OFFSET);
1090 if (word_sized) {
1091 outb_p((reg & 0xff) + 1,
1092 data->addr + ADDR_REG_OFFSET);
1093 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1094 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001095 return res;
1096}
1097
1098static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1099{
1100 int word_sized = is_word_sized(data, reg);
1101
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001102 nct6775_set_bank(data, reg);
1103 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1104 if (word_sized) {
1105 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1106 outb_p((reg & 0xff) + 1,
1107 data->addr + ADDR_REG_OFFSET);
1108 }
1109 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001110 return 0;
1111}
1112
Guenter Roeckaa136e52012-12-04 03:26:05 -08001113/* We left-align 8-bit temperature values to make the code simpler */
1114static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1115{
1116 u16 res;
1117
1118 res = nct6775_read_value(data, reg);
1119 if (!is_word_sized(data, reg))
1120 res <<= 8;
1121
1122 return res;
1123}
1124
1125static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1126{
1127 if (!is_word_sized(data, reg))
1128 value >>= 8;
1129 return nct6775_write_value(data, reg, value);
1130}
1131
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001132/* This function assumes that the caller holds data->update_lock */
1133static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1134{
1135 u8 reg;
1136
1137 switch (nr) {
1138 case 0:
1139 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
1140 | (data->fan_div[0] & 0x7);
1141 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1142 break;
1143 case 1:
1144 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
1145 | ((data->fan_div[1] << 4) & 0x70);
1146 nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
1147 break;
1148 case 2:
1149 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
1150 | (data->fan_div[2] & 0x7);
1151 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1152 break;
1153 case 3:
1154 reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
1155 | ((data->fan_div[3] << 4) & 0x70);
1156 nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
1157 break;
1158 }
1159}
1160
1161static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1162{
1163 if (data->kind == nct6775)
1164 nct6775_write_fan_div(data, nr);
1165}
1166
1167static void nct6775_update_fan_div(struct nct6775_data *data)
1168{
1169 u8 i;
1170
1171 i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
1172 data->fan_div[0] = i & 0x7;
1173 data->fan_div[1] = (i & 0x70) >> 4;
1174 i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
1175 data->fan_div[2] = i & 0x7;
Guenter Roeck6445e662013-04-21 09:13:28 -07001176 if (data->has_fan & (1 << 3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001177 data->fan_div[3] = (i & 0x70) >> 4;
1178}
1179
1180static void nct6775_update_fan_div_common(struct nct6775_data *data)
1181{
1182 if (data->kind == nct6775)
1183 nct6775_update_fan_div(data);
1184}
1185
1186static void nct6775_init_fan_div(struct nct6775_data *data)
1187{
1188 int i;
1189
1190 nct6775_update_fan_div_common(data);
1191 /*
1192 * For all fans, start with highest divider value if the divider
1193 * register is not initialized. This ensures that we get a
1194 * reading from the fan count register, even if it is not optimal.
1195 * We'll compute a better divider later on.
1196 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001197 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001198 if (!(data->has_fan & (1 << i)))
1199 continue;
1200 if (data->fan_div[i] == 0) {
1201 data->fan_div[i] = 7;
1202 nct6775_write_fan_div_common(data, i);
1203 }
1204 }
1205}
1206
1207static void nct6775_init_fan_common(struct device *dev,
1208 struct nct6775_data *data)
1209{
1210 int i;
1211 u8 reg;
1212
1213 if (data->has_fan_div)
1214 nct6775_init_fan_div(data);
1215
1216 /*
1217 * If fan_min is not set (0), set it to 0xff to disable it. This
1218 * prevents the unnecessary warning when fanX_min is reported as 0.
1219 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001220 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001221 if (data->has_fan_min & (1 << i)) {
1222 reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
1223 if (!reg)
1224 nct6775_write_value(data, data->REG_FAN_MIN[i],
1225 data->has_fan_div ? 0xff
1226 : 0xff1f);
1227 }
1228 }
1229}
1230
1231static void nct6775_select_fan_div(struct device *dev,
1232 struct nct6775_data *data, int nr, u16 reg)
1233{
1234 u8 fan_div = data->fan_div[nr];
1235 u16 fan_min;
1236
1237 if (!data->has_fan_div)
1238 return;
1239
1240 /*
1241 * If we failed to measure the fan speed, or the reported value is not
1242 * in the optimal range, and the clock divider can be modified,
1243 * let's try that for next time.
1244 */
1245 if (reg == 0x00 && fan_div < 0x07)
1246 fan_div++;
1247 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1248 fan_div--;
1249
1250 if (fan_div != data->fan_div[nr]) {
1251 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1252 nr + 1, div_from_reg(data->fan_div[nr]),
1253 div_from_reg(fan_div));
1254
1255 /* Preserve min limit if possible */
1256 if (data->has_fan_min & (1 << nr)) {
1257 fan_min = data->fan_min[nr];
1258 if (fan_div > data->fan_div[nr]) {
1259 if (fan_min != 255 && fan_min > 1)
1260 fan_min >>= 1;
1261 } else {
1262 if (fan_min != 255) {
1263 fan_min <<= 1;
1264 if (fan_min > 254)
1265 fan_min = 254;
1266 }
1267 }
1268 if (fan_min != data->fan_min[nr]) {
1269 data->fan_min[nr] = fan_min;
1270 nct6775_write_value(data, data->REG_FAN_MIN[nr],
1271 fan_min);
1272 }
1273 }
1274 data->fan_div[nr] = fan_div;
1275 nct6775_write_fan_div_common(data, nr);
1276 }
1277}
1278
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001279static void nct6775_update_pwm(struct device *dev)
1280{
1281 struct nct6775_data *data = dev_get_drvdata(dev);
1282 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001283 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001284 bool duty_is_dc;
1285
1286 for (i = 0; i < data->pwm_num; i++) {
1287 if (!(data->has_pwm & (1 << i)))
1288 continue;
1289
1290 duty_is_dc = data->REG_PWM_MODE[i] &&
1291 (nct6775_read_value(data, data->REG_PWM_MODE[i])
1292 & data->PWM_MODE_MASK[i]);
1293 data->pwm_mode[i] = duty_is_dc;
1294
1295 fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
1296 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1297 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
1298 data->pwm[j][i]
1299 = nct6775_read_value(data,
1300 data->REG_PWM[j][i]);
1301 }
1302 }
1303
1304 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1305 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001306
1307 if (!data->temp_tolerance[0][i] ||
1308 data->pwm_enable[i] != speed_cruise)
1309 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1310 if (!data->target_speed_tolerance[i] ||
1311 data->pwm_enable[i] == speed_cruise) {
1312 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001313
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001314 if (data->REG_TOLERANCE_H) {
1315 t |= (nct6775_read_value(data,
1316 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1317 }
1318 data->target_speed_tolerance[i] = t;
1319 }
1320
1321 data->temp_tolerance[1][i] =
1322 nct6775_read_value(data,
1323 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
1324
1325 reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
1326 data->pwm_temp_sel[i] = reg & 0x1f;
1327 /* If fan can stop, report floor as 0 */
1328 if (reg & 0x80)
1329 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001330
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001331 if (!data->REG_WEIGHT_TEMP_SEL[i])
1332 continue;
1333
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001334 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
1335 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1336 /* If weight is disabled, report weight source as 0 */
1337 if (j == 1 && !(reg & 0x80))
1338 data->pwm_weight_temp_sel[i] = 0;
1339
1340 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001341 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001342 data->weight_temp[j][i]
1343 = nct6775_read_value(data,
1344 data->REG_WEIGHT_TEMP[j][i]);
1345 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001346 }
1347}
1348
1349static void nct6775_update_pwm_limits(struct device *dev)
1350{
1351 struct nct6775_data *data = dev_get_drvdata(dev);
1352 int i, j;
1353 u8 reg;
1354 u16 reg_t;
1355
1356 for (i = 0; i < data->pwm_num; i++) {
1357 if (!(data->has_pwm & (1 << i)))
1358 continue;
1359
Guenter Roeckc409fd42013-04-09 05:04:00 -07001360 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001361 data->fan_time[j][i] =
1362 nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
1363 }
1364
1365 reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
1366 /* Update only in matching mode or if never updated */
1367 if (!data->target_temp[i] ||
1368 data->pwm_enable[i] == thermal_cruise)
1369 data->target_temp[i] = reg_t & data->target_temp_mask;
1370 if (!data->target_speed[i] ||
1371 data->pwm_enable[i] == speed_cruise) {
1372 if (data->REG_TOLERANCE_H) {
1373 reg_t |= (nct6775_read_value(data,
1374 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1375 }
1376 data->target_speed[i] = reg_t;
1377 }
1378
1379 for (j = 0; j < data->auto_pwm_num; j++) {
1380 data->auto_pwm[i][j] =
1381 nct6775_read_value(data,
1382 NCT6775_AUTO_PWM(data, i, j));
1383 data->auto_temp[i][j] =
1384 nct6775_read_value(data,
1385 NCT6775_AUTO_TEMP(data, i, j));
1386 }
1387
1388 /* critical auto_pwm temperature data */
1389 data->auto_temp[i][data->auto_pwm_num] =
1390 nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
1391
1392 switch (data->kind) {
1393 case nct6775:
1394 reg = nct6775_read_value(data,
1395 NCT6775_REG_CRITICAL_ENAB[i]);
1396 data->auto_pwm[i][data->auto_pwm_num] =
1397 (reg & 0x02) ? 0xff : 0x00;
1398 break;
1399 case nct6776:
1400 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1401 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001402 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001403 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001404 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001405 case nct6792:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001406 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001407 data->REG_CRITICAL_PWM_ENABLE[i]);
1408 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
1409 reg = nct6775_read_value(data,
1410 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001411 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001412 reg = 0xff;
1413 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001414 break;
1415 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001416 }
1417}
1418
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001419static struct nct6775_data *nct6775_update_device(struct device *dev)
1420{
1421 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001422 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001423
1424 mutex_lock(&data->update_lock);
1425
Guenter Roeck6445e662013-04-21 09:13:28 -07001426 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001427 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001428 /* Fan clock dividers */
1429 nct6775_update_fan_div_common(data);
1430
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001431 /* Measured voltages and limits */
1432 for (i = 0; i < data->in_num; i++) {
1433 if (!(data->have_in & (1 << i)))
1434 continue;
1435
1436 data->in[i][0] = nct6775_read_value(data,
1437 data->REG_VIN[i]);
1438 data->in[i][1] = nct6775_read_value(data,
1439 data->REG_IN_MINMAX[0][i]);
1440 data->in[i][2] = nct6775_read_value(data,
1441 data->REG_IN_MINMAX[1][i]);
1442 }
1443
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001444 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001445 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001446 u16 reg;
1447
1448 if (!(data->has_fan & (1 << i)))
1449 continue;
1450
1451 reg = nct6775_read_value(data, data->REG_FAN[i]);
1452 data->rpm[i] = data->fan_from_reg(reg,
1453 data->fan_div[i]);
1454
1455 if (data->has_fan_min & (1 << i))
1456 data->fan_min[i] = nct6775_read_value(data,
1457 data->REG_FAN_MIN[i]);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001458 data->fan_pulses[i] =
Guenter Roeck6c009502012-07-01 08:23:15 -07001459 (nct6775_read_value(data, data->REG_FAN_PULSES[i])
1460 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001461
1462 nct6775_select_fan_div(dev, data, i, reg);
1463 }
1464
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001465 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001466 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001467
Guenter Roeckaa136e52012-12-04 03:26:05 -08001468 /* Measured temperatures and limits */
1469 for (i = 0; i < NUM_TEMP; i++) {
1470 if (!(data->have_temp & (1 << i)))
1471 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001472 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001473 if (data->reg_temp[j][i])
1474 data->temp[j][i]
1475 = nct6775_read_temp(data,
1476 data->reg_temp[j][i]);
1477 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001478 if (i >= NUM_TEMP_FIXED ||
1479 !(data->have_temp_fixed & (1 << i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001480 continue;
1481 data->temp_offset[i]
1482 = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
1483 }
1484
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001485 data->alarms = 0;
1486 for (i = 0; i < NUM_REG_ALARM; i++) {
1487 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001488
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001489 if (!data->REG_ALARM[i])
1490 continue;
1491 alarm = nct6775_read_value(data, data->REG_ALARM[i]);
1492 data->alarms |= ((u64)alarm) << (i << 3);
1493 }
1494
Guenter Roeck30846992013-06-24 22:21:59 -07001495 data->beeps = 0;
1496 for (i = 0; i < NUM_REG_BEEP; i++) {
1497 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001498
Guenter Roeck30846992013-06-24 22:21:59 -07001499 if (!data->REG_BEEP[i])
1500 continue;
1501 beep = nct6775_read_value(data, data->REG_BEEP[i]);
1502 data->beeps |= ((u64)beep) << (i << 3);
1503 }
1504
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001505 data->last_updated = jiffies;
1506 data->valid = true;
1507 }
1508
1509 mutex_unlock(&data->update_lock);
1510 return data;
1511}
1512
1513/*
1514 * Sysfs callback functions
1515 */
1516static ssize_t
1517show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
1518{
1519 struct nct6775_data *data = nct6775_update_device(dev);
1520 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001521 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001522 int nr = sattr->nr;
1523
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001524 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
1525}
1526
1527static ssize_t
1528store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
1529 size_t count)
1530{
1531 struct nct6775_data *data = dev_get_drvdata(dev);
1532 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001533 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001534 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001535 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001536 int err;
1537
1538 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001539 if (err < 0)
1540 return err;
1541 mutex_lock(&data->update_lock);
1542 data->in[nr][index] = in_to_reg(val, nr);
Guenter Roeck6445e662013-04-21 09:13:28 -07001543 nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001544 data->in[nr][index]);
1545 mutex_unlock(&data->update_lock);
1546 return count;
1547}
1548
1549static ssize_t
1550show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1551{
1552 struct nct6775_data *data = nct6775_update_device(dev);
1553 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1554 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001555
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001556 return sprintf(buf, "%u\n",
1557 (unsigned int)((data->alarms >> nr) & 0x01));
1558}
1559
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001560static int find_temp_source(struct nct6775_data *data, int index, int count)
1561{
1562 int source = data->temp_src[index];
1563 int nr;
1564
1565 for (nr = 0; nr < count; nr++) {
1566 int src;
1567
1568 src = nct6775_read_value(data,
1569 data->REG_TEMP_SOURCE[nr]) & 0x1f;
1570 if (src == source)
1571 return nr;
1572 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07001573 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001574}
1575
1576static ssize_t
1577show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
1578{
1579 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1580 struct nct6775_data *data = nct6775_update_device(dev);
1581 unsigned int alarm = 0;
1582 int nr;
1583
1584 /*
1585 * For temperatures, there is no fixed mapping from registers to alarm
1586 * bits. Alarm bits are determined by the temperature source mapping.
1587 */
1588 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
1589 if (nr >= 0) {
1590 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001591
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07001592 alarm = (data->alarms >> bit) & 0x01;
1593 }
1594 return sprintf(buf, "%u\n", alarm);
1595}
1596
Guenter Roeck30846992013-06-24 22:21:59 -07001597static ssize_t
1598show_beep(struct device *dev, struct device_attribute *attr, char *buf)
1599{
1600 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1601 struct nct6775_data *data = nct6775_update_device(dev);
1602 int nr = data->BEEP_BITS[sattr->index];
1603
1604 return sprintf(buf, "%u\n",
1605 (unsigned int)((data->beeps >> nr) & 0x01));
1606}
1607
1608static ssize_t
1609store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
1610 size_t count)
1611{
1612 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1613 struct nct6775_data *data = dev_get_drvdata(dev);
1614 int nr = data->BEEP_BITS[sattr->index];
1615 int regindex = nr >> 3;
1616 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001617 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001618
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001619 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001620 if (err < 0)
1621 return err;
1622 if (val > 1)
1623 return -EINVAL;
1624
1625 mutex_lock(&data->update_lock);
1626 if (val)
1627 data->beeps |= (1ULL << nr);
1628 else
1629 data->beeps &= ~(1ULL << nr);
1630 nct6775_write_value(data, data->REG_BEEP[regindex],
1631 (data->beeps >> (regindex << 3)) & 0xff);
1632 mutex_unlock(&data->update_lock);
1633 return count;
1634}
1635
1636static ssize_t
1637show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
1638{
1639 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1640 struct nct6775_data *data = nct6775_update_device(dev);
1641 unsigned int beep = 0;
1642 int nr;
1643
1644 /*
1645 * For temperatures, there is no fixed mapping from registers to beep
1646 * enable bits. Beep enable bits are determined by the temperature
1647 * source mapping.
1648 */
1649 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1650 if (nr >= 0) {
1651 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001652
Guenter Roeck30846992013-06-24 22:21:59 -07001653 beep = (data->beeps >> bit) & 0x01;
1654 }
1655 return sprintf(buf, "%u\n", beep);
1656}
1657
1658static ssize_t
1659store_temp_beep(struct device *dev, struct device_attribute *attr,
1660 const char *buf, size_t count)
1661{
1662 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1663 struct nct6775_data *data = dev_get_drvdata(dev);
1664 int nr, bit, regindex;
1665 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001666 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07001667
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001668 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07001669 if (err < 0)
1670 return err;
1671 if (val > 1)
1672 return -EINVAL;
1673
1674 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
1675 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07001676 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07001677
1678 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
1679 regindex = bit >> 3;
1680
1681 mutex_lock(&data->update_lock);
1682 if (val)
1683 data->beeps |= (1ULL << bit);
1684 else
1685 data->beeps &= ~(1ULL << bit);
1686 nct6775_write_value(data, data->REG_BEEP[regindex],
1687 (data->beeps >> (regindex << 3)) & 0xff);
1688 mutex_unlock(&data->update_lock);
1689
1690 return count;
1691}
1692
Guenter Roeckf73cf632013-03-18 09:22:50 -07001693static umode_t nct6775_in_is_visible(struct kobject *kobj,
1694 struct attribute *attr, int index)
1695{
1696 struct device *dev = container_of(kobj, struct device, kobj);
1697 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001698 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001699
Guenter Roeckf73cf632013-03-18 09:22:50 -07001700 if (!(data->have_in & (1 << in)))
1701 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001702
Guenter Roeckf73cf632013-03-18 09:22:50 -07001703 return attr->mode;
1704}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001705
Guenter Roeckf73cf632013-03-18 09:22:50 -07001706SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
1707SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07001708SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
1709 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001710SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
1711 store_in_reg, 0, 1);
1712SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
1713 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001714
Guenter Roeckf73cf632013-03-18 09:22:50 -07001715/*
1716 * nct6775_in_is_visible uses the index into the following array
1717 * to determine if attributes should be created or not.
1718 * Any change in order or content must be matched.
1719 */
1720static struct sensor_device_template *nct6775_attributes_in_template[] = {
1721 &sensor_dev_template_in_input,
1722 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07001723 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001724 &sensor_dev_template_in_min,
1725 &sensor_dev_template_in_max,
1726 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001727};
1728
Guenter Roeckf73cf632013-03-18 09:22:50 -07001729static struct sensor_template_group nct6775_in_template_group = {
1730 .templates = nct6775_attributes_in_template,
1731 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001732};
1733
1734static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001735show_fan(struct device *dev, struct device_attribute *attr, char *buf)
1736{
1737 struct nct6775_data *data = nct6775_update_device(dev);
1738 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1739 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001740
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001741 return sprintf(buf, "%d\n", data->rpm[nr]);
1742}
1743
1744static ssize_t
1745show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
1746{
1747 struct nct6775_data *data = nct6775_update_device(dev);
1748 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1749 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001750
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001751 return sprintf(buf, "%d\n",
1752 data->fan_from_reg_min(data->fan_min[nr],
1753 data->fan_div[nr]));
1754}
1755
1756static ssize_t
1757show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
1758{
1759 struct nct6775_data *data = nct6775_update_device(dev);
1760 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1761 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001762
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001763 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
1764}
1765
1766static ssize_t
1767store_fan_min(struct device *dev, struct device_attribute *attr,
1768 const char *buf, size_t count)
1769{
1770 struct nct6775_data *data = dev_get_drvdata(dev);
1771 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1772 int nr = sattr->index;
1773 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001774 unsigned int reg;
1775 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001776 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001777
1778 err = kstrtoul(buf, 10, &val);
1779 if (err < 0)
1780 return err;
1781
1782 mutex_lock(&data->update_lock);
1783 if (!data->has_fan_div) {
1784 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
1785 if (!val) {
1786 val = 0xff1f;
1787 } else {
1788 if (val > 1350000U)
1789 val = 135000U;
1790 val = 1350000U / val;
1791 val = (val & 0x1f) | ((val << 3) & 0xff00);
1792 }
1793 data->fan_min[nr] = val;
1794 goto write_min; /* Leave fan divider alone */
1795 }
1796 if (!val) {
1797 /* No min limit, alarm disabled */
1798 data->fan_min[nr] = 255;
1799 new_div = data->fan_div[nr]; /* No change */
1800 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1801 goto write_div;
1802 }
1803 reg = 1350000U / val;
1804 if (reg >= 128 * 255) {
1805 /*
1806 * Speed below this value cannot possibly be represented,
1807 * even with the highest divider (128)
1808 */
1809 data->fan_min[nr] = 254;
1810 new_div = 7; /* 128 == (1 << 7) */
1811 dev_warn(dev,
1812 "fan%u low limit %lu below minimum %u, set to minimum\n",
1813 nr + 1, val, data->fan_from_reg_min(254, 7));
1814 } else if (!reg) {
1815 /*
1816 * Speed above this value cannot possibly be represented,
1817 * even with the lowest divider (1)
1818 */
1819 data->fan_min[nr] = 1;
1820 new_div = 0; /* 1 == (1 << 0) */
1821 dev_warn(dev,
1822 "fan%u low limit %lu above maximum %u, set to maximum\n",
1823 nr + 1, val, data->fan_from_reg_min(1, 0));
1824 } else {
1825 /*
1826 * Automatically pick the best divider, i.e. the one such
1827 * that the min limit will correspond to a register value
1828 * in the 96..192 range
1829 */
1830 new_div = 0;
1831 while (reg > 192 && new_div < 7) {
1832 reg >>= 1;
1833 new_div++;
1834 }
1835 data->fan_min[nr] = reg;
1836 }
1837
1838write_div:
1839 /*
1840 * Write both the fan clock divider (if it changed) and the new
1841 * fan min (unconditionally)
1842 */
1843 if (new_div != data->fan_div[nr]) {
1844 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1845 nr + 1, div_from_reg(data->fan_div[nr]),
1846 div_from_reg(new_div));
1847 data->fan_div[nr] = new_div;
1848 nct6775_write_fan_div_common(data, nr);
1849 /* Give the chip time to sample a new speed value */
1850 data->last_updated = jiffies;
1851 }
1852
1853write_min:
1854 nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
1855 mutex_unlock(&data->update_lock);
1856
1857 return count;
1858}
1859
Guenter Roeck5c25d952012-12-11 07:29:06 -08001860static ssize_t
1861show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
1862{
1863 struct nct6775_data *data = nct6775_update_device(dev);
1864 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1865 int p = data->fan_pulses[sattr->index];
1866
1867 return sprintf(buf, "%d\n", p ? : 4);
1868}
1869
1870static ssize_t
1871store_fan_pulses(struct device *dev, struct device_attribute *attr,
1872 const char *buf, size_t count)
1873{
1874 struct nct6775_data *data = dev_get_drvdata(dev);
1875 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1876 int nr = sattr->index;
1877 unsigned long val;
1878 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07001879 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001880
1881 err = kstrtoul(buf, 10, &val);
1882 if (err < 0)
1883 return err;
1884
1885 if (val > 4)
1886 return -EINVAL;
1887
1888 mutex_lock(&data->update_lock);
1889 data->fan_pulses[nr] = val & 3;
Guenter Roeck6c009502012-07-01 08:23:15 -07001890 reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
1891 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
1892 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
1893 nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08001894 mutex_unlock(&data->update_lock);
1895
1896 return count;
1897}
1898
Guenter Roeckf73cf632013-03-18 09:22:50 -07001899static umode_t nct6775_fan_is_visible(struct kobject *kobj,
1900 struct attribute *attr, int index)
1901{
1902 struct device *dev = container_of(kobj, struct device, kobj);
1903 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07001904 int fan = index / 6; /* fan index */
1905 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001906
1907 if (!(data->has_fan & (1 << fan)))
1908 return 0;
1909
1910 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
1911 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001912 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001913 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07001914 if (nr == 4 && !(data->has_fan_min & (1 << fan)))
1915 return 0;
1916 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07001917 return 0;
1918
1919 return attr->mode;
1920}
1921
1922SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
1923SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
1924 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07001925SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
1926 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001927SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
1928 store_fan_pulses, 0);
1929SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
1930 store_fan_min, 0);
1931SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
1932
1933/*
1934 * nct6775_fan_is_visible uses the index into the following array
1935 * to determine if attributes should be created or not.
1936 * Any change in order or content must be matched.
1937 */
1938static struct sensor_device_template *nct6775_attributes_fan_template[] = {
1939 &sensor_dev_template_fan_input,
1940 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07001941 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001942 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07001943 &sensor_dev_template_fan_min, /* 4 */
1944 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07001945 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001946};
1947
Guenter Roeckf73cf632013-03-18 09:22:50 -07001948static struct sensor_template_group nct6775_fan_template_group = {
1949 .templates = nct6775_attributes_fan_template,
1950 .is_visible = nct6775_fan_is_visible,
1951 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001952};
1953
1954static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08001955show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1956{
1957 struct nct6775_data *data = nct6775_update_device(dev);
1958 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
1959 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001960
Guenter Roeckaa136e52012-12-04 03:26:05 -08001961 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1962}
1963
1964static ssize_t
1965show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1966{
1967 struct nct6775_data *data = nct6775_update_device(dev);
1968 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1969 int nr = sattr->nr;
1970 int index = sattr->index;
1971
1972 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
1973}
1974
1975static ssize_t
1976store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
1977 size_t count)
1978{
1979 struct nct6775_data *data = dev_get_drvdata(dev);
1980 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1981 int nr = sattr->nr;
1982 int index = sattr->index;
1983 int err;
1984 long val;
1985
1986 err = kstrtol(buf, 10, &val);
1987 if (err < 0)
1988 return err;
1989
1990 mutex_lock(&data->update_lock);
1991 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
1992 nct6775_write_temp(data, data->reg_temp[index][nr],
1993 data->temp[index][nr]);
1994 mutex_unlock(&data->update_lock);
1995 return count;
1996}
1997
1998static ssize_t
1999show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2000{
2001 struct nct6775_data *data = nct6775_update_device(dev);
2002 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2003
2004 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2005}
2006
2007static ssize_t
2008store_temp_offset(struct device *dev, struct device_attribute *attr,
2009 const char *buf, size_t count)
2010{
2011 struct nct6775_data *data = dev_get_drvdata(dev);
2012 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2013 int nr = sattr->index;
2014 long val;
2015 int err;
2016
2017 err = kstrtol(buf, 10, &val);
2018 if (err < 0)
2019 return err;
2020
2021 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2022
2023 mutex_lock(&data->update_lock);
2024 data->temp_offset[nr] = val;
2025 nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
2026 mutex_unlock(&data->update_lock);
2027
2028 return count;
2029}
2030
2031static ssize_t
2032show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2033{
2034 struct nct6775_data *data = nct6775_update_device(dev);
2035 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2036 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002037
Guenter Roeckaa136e52012-12-04 03:26:05 -08002038 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2039}
2040
2041static ssize_t
2042store_temp_type(struct device *dev, struct device_attribute *attr,
2043 const char *buf, size_t count)
2044{
2045 struct nct6775_data *data = nct6775_update_device(dev);
2046 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2047 int nr = sattr->index;
2048 unsigned long val;
2049 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002050 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002051
2052 err = kstrtoul(buf, 10, &val);
2053 if (err < 0)
2054 return err;
2055
2056 if (val != 1 && val != 3 && val != 4)
2057 return -EINVAL;
2058
2059 mutex_lock(&data->update_lock);
2060
2061 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002062 vbit = 0x02 << nr;
2063 dbit = data->DIODE_MASK << nr;
2064 vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
2065 diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002066 switch (val) {
2067 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002068 vbat |= vbit;
2069 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002070 break;
2071 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002072 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002073 break;
2074 case 4: /* thermistor */
2075 break;
2076 }
2077 nct6775_write_value(data, data->REG_VBAT, vbat);
2078 nct6775_write_value(data, data->REG_DIODE, diode);
2079
2080 mutex_unlock(&data->update_lock);
2081 return count;
2082}
2083
Guenter Roeckf73cf632013-03-18 09:22:50 -07002084static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2085 struct attribute *attr, int index)
2086{
2087 struct device *dev = container_of(kobj, struct device, kobj);
2088 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002089 int temp = index / 10; /* temp index */
2090 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002091
2092 if (!(data->have_temp & (1 << temp)))
2093 return 0;
2094
2095 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2096 return 0; /* alarm */
2097
Guenter Roeck30846992013-06-24 22:21:59 -07002098 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2099 return 0; /* beep */
2100
2101 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002102 return 0;
2103
Guenter Roeck30846992013-06-24 22:21:59 -07002104 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002105 return 0;
2106
Guenter Roeck30846992013-06-24 22:21:59 -07002107 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002108 return 0;
2109
Guenter Roeck30846992013-06-24 22:21:59 -07002110 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002111 return 0;
2112
2113 /* offset and type only apply to fixed sensors */
Guenter Roeck30846992013-06-24 22:21:59 -07002114 if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002115 return 0;
2116
2117 return attr->mode;
2118}
2119
2120SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2121SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2122SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2123 store_temp, 0, 1);
2124SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2125 show_temp, store_temp, 0, 2);
2126SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2127 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002128SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2129 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002130SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2131 show_temp_offset, store_temp_offset, 0);
2132SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2133 store_temp_type, 0);
2134SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002135SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2136 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002137
2138/*
2139 * nct6775_temp_is_visible uses the index into the following array
2140 * to determine if attributes should be created or not.
2141 * Any change in order or content must be matched.
2142 */
2143static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2144 &sensor_dev_template_temp_input,
2145 &sensor_dev_template_temp_label,
2146 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002147 &sensor_dev_template_temp_beep, /* 3 */
2148 &sensor_dev_template_temp_max, /* 4 */
2149 &sensor_dev_template_temp_max_hyst, /* 5 */
2150 &sensor_dev_template_temp_crit, /* 6 */
2151 &sensor_dev_template_temp_lcrit, /* 7 */
2152 &sensor_dev_template_temp_offset, /* 8 */
2153 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002154 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002155};
2156
Guenter Roeckf73cf632013-03-18 09:22:50 -07002157static struct sensor_template_group nct6775_temp_template_group = {
2158 .templates = nct6775_attributes_temp_template,
2159 .is_visible = nct6775_temp_is_visible,
2160 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002161};
2162
Guenter Roeckaa136e52012-12-04 03:26:05 -08002163static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002164show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2165{
2166 struct nct6775_data *data = nct6775_update_device(dev);
2167 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2168
2169 return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
2170}
2171
2172static ssize_t
2173store_pwm_mode(struct device *dev, struct device_attribute *attr,
2174 const char *buf, size_t count)
2175{
2176 struct nct6775_data *data = dev_get_drvdata(dev);
2177 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2178 int nr = sattr->index;
2179 unsigned long val;
2180 int err;
2181 u8 reg;
2182
2183 err = kstrtoul(buf, 10, &val);
2184 if (err < 0)
2185 return err;
2186
2187 if (val > 1)
2188 return -EINVAL;
2189
2190 /* Setting DC mode is not supported for all chips/channels */
2191 if (data->REG_PWM_MODE[nr] == 0) {
2192 if (val)
2193 return -EINVAL;
2194 return count;
2195 }
2196
2197 mutex_lock(&data->update_lock);
2198 data->pwm_mode[nr] = val;
2199 reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
2200 reg &= ~data->PWM_MODE_MASK[nr];
2201 if (val)
2202 reg |= data->PWM_MODE_MASK[nr];
2203 nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
2204 mutex_unlock(&data->update_lock);
2205 return count;
2206}
2207
2208static ssize_t
2209show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2210{
2211 struct nct6775_data *data = nct6775_update_device(dev);
2212 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2213 int nr = sattr->nr;
2214 int index = sattr->index;
2215 int pwm;
2216
2217 /*
2218 * For automatic fan control modes, show current pwm readings.
2219 * Otherwise, show the configured value.
2220 */
2221 if (index == 0 && data->pwm_enable[nr] > manual)
2222 pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
2223 else
2224 pwm = data->pwm[index][nr];
2225
2226 return sprintf(buf, "%d\n", pwm);
2227}
2228
2229static ssize_t
2230store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2231 size_t count)
2232{
2233 struct nct6775_data *data = dev_get_drvdata(dev);
2234 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2235 int nr = sattr->nr;
2236 int index = sattr->index;
2237 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002238 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2239 int maxval[7]
2240 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002241 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002242 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002243
2244 err = kstrtoul(buf, 10, &val);
2245 if (err < 0)
2246 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002247 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002248
2249 mutex_lock(&data->update_lock);
2250 data->pwm[index][nr] = val;
2251 nct6775_write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002252 if (index == 2) { /* floor: disable if val == 0 */
2253 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2254 reg &= 0x7f;
2255 if (val)
2256 reg |= 0x80;
2257 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2258 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002259 mutex_unlock(&data->update_lock);
2260 return count;
2261}
2262
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002263/* Returns 0 if OK, -EINVAL otherwise */
2264static int check_trip_points(struct nct6775_data *data, int nr)
2265{
2266 int i;
2267
2268 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2269 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2270 return -EINVAL;
2271 }
2272 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2273 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2274 return -EINVAL;
2275 }
2276 /* validate critical temperature and pwm if enabled (pwm > 0) */
2277 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2278 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2279 data->auto_temp[nr][data->auto_pwm_num] ||
2280 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2281 data->auto_pwm[nr][data->auto_pwm_num])
2282 return -EINVAL;
2283 }
2284 return 0;
2285}
2286
2287static void pwm_update_registers(struct nct6775_data *data, int nr)
2288{
2289 u8 reg;
2290
2291 switch (data->pwm_enable[nr]) {
2292 case off:
2293 case manual:
2294 break;
2295 case speed_cruise:
2296 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2297 reg = (reg & ~data->tolerance_mask) |
2298 (data->target_speed_tolerance[nr] & data->tolerance_mask);
2299 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2300 nct6775_write_value(data, data->REG_TARGET[nr],
2301 data->target_speed[nr] & 0xff);
2302 if (data->REG_TOLERANCE_H) {
2303 reg = (data->target_speed[nr] >> 8) & 0x0f;
2304 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
2305 nct6775_write_value(data,
2306 data->REG_TOLERANCE_H[nr],
2307 reg);
2308 }
2309 break;
2310 case thermal_cruise:
2311 nct6775_write_value(data, data->REG_TARGET[nr],
2312 data->target_temp[nr]);
2313 /* intentional */
2314 default:
2315 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2316 reg = (reg & ~data->tolerance_mask) |
2317 data->temp_tolerance[0][nr];
2318 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2319 break;
2320 }
2321}
2322
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002323static ssize_t
2324show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2325{
2326 struct nct6775_data *data = nct6775_update_device(dev);
2327 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2328
2329 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2330}
2331
2332static ssize_t
2333store_pwm_enable(struct device *dev, struct device_attribute *attr,
2334 const char *buf, size_t count)
2335{
2336 struct nct6775_data *data = dev_get_drvdata(dev);
2337 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2338 int nr = sattr->index;
2339 unsigned long val;
2340 int err;
2341 u16 reg;
2342
2343 err = kstrtoul(buf, 10, &val);
2344 if (err < 0)
2345 return err;
2346
2347 if (val > sf4)
2348 return -EINVAL;
2349
2350 if (val == sf3 && data->kind != nct6775)
2351 return -EINVAL;
2352
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002353 if (val == sf4 && check_trip_points(data, nr)) {
2354 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2355 dev_err(dev, "Adjust trip points and try again\n");
2356 return -EINVAL;
2357 }
2358
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002359 mutex_lock(&data->update_lock);
2360 data->pwm_enable[nr] = val;
2361 if (val == off) {
2362 /*
2363 * turn off pwm control: select manual mode, set pwm to maximum
2364 */
2365 data->pwm[0][nr] = 255;
2366 nct6775_write_value(data, data->REG_PWM[0][nr], 255);
2367 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002368 pwm_update_registers(data, nr);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002369 reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
2370 reg &= 0x0f;
2371 reg |= pwm_enable_to_reg(val) << 4;
2372 nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
2373 mutex_unlock(&data->update_lock);
2374 return count;
2375}
2376
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002377static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002378show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002379{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002380 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002381
2382 for (i = 0; i < NUM_TEMP; i++) {
2383 if (!(data->have_temp & (1 << i)))
2384 continue;
2385 if (src == data->temp_src[i]) {
2386 sel = i + 1;
2387 break;
2388 }
2389 }
2390
2391 return sprintf(buf, "%d\n", sel);
2392}
2393
2394static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002395show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2396{
2397 struct nct6775_data *data = nct6775_update_device(dev);
2398 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2399 int index = sattr->index;
2400
2401 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2402}
2403
2404static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002405store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2406 const char *buf, size_t count)
2407{
2408 struct nct6775_data *data = nct6775_update_device(dev);
2409 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2410 int nr = sattr->index;
2411 unsigned long val;
2412 int err, reg, src;
2413
2414 err = kstrtoul(buf, 10, &val);
2415 if (err < 0)
2416 return err;
2417 if (val == 0 || val > NUM_TEMP)
2418 return -EINVAL;
2419 if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
2420 return -EINVAL;
2421
2422 mutex_lock(&data->update_lock);
2423 src = data->temp_src[val - 1];
2424 data->pwm_temp_sel[nr] = src;
2425 reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
2426 reg &= 0xe0;
2427 reg |= src;
2428 nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
2429 mutex_unlock(&data->update_lock);
2430
2431 return count;
2432}
2433
2434static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002435show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2436 char *buf)
2437{
2438 struct nct6775_data *data = nct6775_update_device(dev);
2439 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2440 int index = sattr->index;
2441
2442 return show_pwm_temp_sel_common(data, buf,
2443 data->pwm_weight_temp_sel[index]);
2444}
2445
2446static ssize_t
2447store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2448 const char *buf, size_t count)
2449{
2450 struct nct6775_data *data = nct6775_update_device(dev);
2451 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2452 int nr = sattr->index;
2453 unsigned long val;
2454 int err, reg, src;
2455
2456 err = kstrtoul(buf, 10, &val);
2457 if (err < 0)
2458 return err;
2459 if (val > NUM_TEMP)
2460 return -EINVAL;
2461 if (val && (!(data->have_temp & (1 << (val - 1))) ||
2462 !data->temp_src[val - 1]))
2463 return -EINVAL;
2464
2465 mutex_lock(&data->update_lock);
2466 if (val) {
2467 src = data->temp_src[val - 1];
2468 data->pwm_weight_temp_sel[nr] = src;
2469 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2470 reg &= 0xe0;
2471 reg |= (src | 0x80);
2472 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2473 } else {
2474 data->pwm_weight_temp_sel[nr] = 0;
2475 reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
2476 reg &= 0x7f;
2477 nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
2478 }
2479 mutex_unlock(&data->update_lock);
2480
2481 return count;
2482}
2483
2484static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002485show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2486{
2487 struct nct6775_data *data = nct6775_update_device(dev);
2488 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2489
2490 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
2491}
2492
2493static ssize_t
2494store_target_temp(struct device *dev, struct device_attribute *attr,
2495 const char *buf, size_t count)
2496{
2497 struct nct6775_data *data = dev_get_drvdata(dev);
2498 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2499 int nr = sattr->index;
2500 unsigned long val;
2501 int err;
2502
2503 err = kstrtoul(buf, 10, &val);
2504 if (err < 0)
2505 return err;
2506
2507 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
2508 data->target_temp_mask);
2509
2510 mutex_lock(&data->update_lock);
2511 data->target_temp[nr] = val;
2512 pwm_update_registers(data, nr);
2513 mutex_unlock(&data->update_lock);
2514 return count;
2515}
2516
2517static ssize_t
2518show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
2519{
2520 struct nct6775_data *data = nct6775_update_device(dev);
2521 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2522 int nr = sattr->index;
2523
2524 return sprintf(buf, "%d\n",
2525 fan_from_reg16(data->target_speed[nr],
2526 data->fan_div[nr]));
2527}
2528
2529static ssize_t
2530store_target_speed(struct device *dev, struct device_attribute *attr,
2531 const char *buf, size_t count)
2532{
2533 struct nct6775_data *data = dev_get_drvdata(dev);
2534 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2535 int nr = sattr->index;
2536 unsigned long val;
2537 int err;
2538 u16 speed;
2539
2540 err = kstrtoul(buf, 10, &val);
2541 if (err < 0)
2542 return err;
2543
2544 val = clamp_val(val, 0, 1350000U);
2545 speed = fan_to_reg(val, data->fan_div[nr]);
2546
2547 mutex_lock(&data->update_lock);
2548 data->target_speed[nr] = speed;
2549 pwm_update_registers(data, nr);
2550 mutex_unlock(&data->update_lock);
2551 return count;
2552}
2553
2554static ssize_t
2555show_temp_tolerance(struct device *dev, struct device_attribute *attr,
2556 char *buf)
2557{
2558 struct nct6775_data *data = nct6775_update_device(dev);
2559 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2560 int nr = sattr->nr;
2561 int index = sattr->index;
2562
2563 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
2564}
2565
2566static ssize_t
2567store_temp_tolerance(struct device *dev, struct device_attribute *attr,
2568 const char *buf, size_t count)
2569{
2570 struct nct6775_data *data = dev_get_drvdata(dev);
2571 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2572 int nr = sattr->nr;
2573 int index = sattr->index;
2574 unsigned long val;
2575 int err;
2576
2577 err = kstrtoul(buf, 10, &val);
2578 if (err < 0)
2579 return err;
2580
2581 /* Limit tolerance as needed */
2582 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
2583
2584 mutex_lock(&data->update_lock);
2585 data->temp_tolerance[index][nr] = val;
2586 if (index)
2587 pwm_update_registers(data, nr);
2588 else
2589 nct6775_write_value(data,
2590 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
2591 val);
2592 mutex_unlock(&data->update_lock);
2593 return count;
2594}
2595
2596/*
2597 * Fan speed tolerance is a tricky beast, since the associated register is
2598 * a tick counter, but the value is reported and configured as rpm.
2599 * Compute resulting low and high rpm values and report the difference.
2600 */
2601static ssize_t
2602show_speed_tolerance(struct device *dev, struct device_attribute *attr,
2603 char *buf)
2604{
2605 struct nct6775_data *data = nct6775_update_device(dev);
2606 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2607 int nr = sattr->index;
2608 int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
2609 int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
2610 int tolerance;
2611
2612 if (low <= 0)
2613 low = 1;
2614 if (high > 0xffff)
2615 high = 0xffff;
2616 if (high < low)
2617 high = low;
2618
2619 tolerance = (fan_from_reg16(low, data->fan_div[nr])
2620 - fan_from_reg16(high, data->fan_div[nr])) / 2;
2621
2622 return sprintf(buf, "%d\n", tolerance);
2623}
2624
2625static ssize_t
2626store_speed_tolerance(struct device *dev, struct device_attribute *attr,
2627 const char *buf, size_t count)
2628{
2629 struct nct6775_data *data = dev_get_drvdata(dev);
2630 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2631 int nr = sattr->index;
2632 unsigned long val;
2633 int err;
2634 int low, high;
2635
2636 err = kstrtoul(buf, 10, &val);
2637 if (err < 0)
2638 return err;
2639
2640 high = fan_from_reg16(data->target_speed[nr],
2641 data->fan_div[nr]) + val;
2642 low = fan_from_reg16(data->target_speed[nr],
2643 data->fan_div[nr]) - val;
2644 if (low <= 0)
2645 low = 1;
2646 if (high < low)
2647 high = low;
2648
2649 val = (fan_to_reg(low, data->fan_div[nr]) -
2650 fan_to_reg(high, data->fan_div[nr])) / 2;
2651
2652 /* Limit tolerance as needed */
2653 val = clamp_val(val, 0, data->speed_tolerance_limit);
2654
2655 mutex_lock(&data->update_lock);
2656 data->target_speed_tolerance[nr] = val;
2657 pwm_update_registers(data, nr);
2658 mutex_unlock(&data->update_lock);
2659 return count;
2660}
2661
Guenter Roeckf73cf632013-03-18 09:22:50 -07002662SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
2663SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
2664 store_pwm_mode, 0);
2665SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
2666 store_pwm_enable, 0);
2667SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
2668 show_pwm_temp_sel, store_pwm_temp_sel, 0);
2669SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
2670 show_target_temp, store_target_temp, 0);
2671SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
2672 show_target_speed, store_target_speed, 0);
2673SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
2674 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002675
2676/* Smart Fan registers */
2677
2678static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002679show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
2680{
2681 struct nct6775_data *data = nct6775_update_device(dev);
2682 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2683 int nr = sattr->nr;
2684 int index = sattr->index;
2685
2686 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
2687}
2688
2689static ssize_t
2690store_weight_temp(struct device *dev, struct device_attribute *attr,
2691 const char *buf, size_t count)
2692{
2693 struct nct6775_data *data = dev_get_drvdata(dev);
2694 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2695 int nr = sattr->nr;
2696 int index = sattr->index;
2697 unsigned long val;
2698 int err;
2699
2700 err = kstrtoul(buf, 10, &val);
2701 if (err < 0)
2702 return err;
2703
2704 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
2705
2706 mutex_lock(&data->update_lock);
2707 data->weight_temp[index][nr] = val;
2708 nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
2709 mutex_unlock(&data->update_lock);
2710 return count;
2711}
2712
Guenter Roeckf73cf632013-03-18 09:22:50 -07002713SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
2714 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
2715SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
2716 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
2717SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
2718 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
2719SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
2720 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
2721SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
2722 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
2723SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
2724 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002725
2726static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002727show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
2728{
2729 struct nct6775_data *data = nct6775_update_device(dev);
2730 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2731 int nr = sattr->nr;
2732 int index = sattr->index;
2733
2734 return sprintf(buf, "%d\n",
2735 step_time_from_reg(data->fan_time[index][nr],
2736 data->pwm_mode[nr]));
2737}
2738
2739static ssize_t
2740store_fan_time(struct device *dev, struct device_attribute *attr,
2741 const char *buf, size_t count)
2742{
2743 struct nct6775_data *data = dev_get_drvdata(dev);
2744 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2745 int nr = sattr->nr;
2746 int index = sattr->index;
2747 unsigned long val;
2748 int err;
2749
2750 err = kstrtoul(buf, 10, &val);
2751 if (err < 0)
2752 return err;
2753
2754 val = step_time_to_reg(val, data->pwm_mode[nr]);
2755 mutex_lock(&data->update_lock);
2756 data->fan_time[index][nr] = val;
2757 nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
2758 mutex_unlock(&data->update_lock);
2759 return count;
2760}
2761
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002762static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002763show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2764{
2765 struct nct6775_data *data = nct6775_update_device(dev);
2766 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2767
2768 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
2769}
2770
2771static ssize_t
2772store_auto_pwm(struct device *dev, struct device_attribute *attr,
2773 const char *buf, size_t count)
2774{
2775 struct nct6775_data *data = dev_get_drvdata(dev);
2776 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2777 int nr = sattr->nr;
2778 int point = sattr->index;
2779 unsigned long val;
2780 int err;
2781 u8 reg;
2782
2783 err = kstrtoul(buf, 10, &val);
2784 if (err < 0)
2785 return err;
2786 if (val > 255)
2787 return -EINVAL;
2788
2789 if (point == data->auto_pwm_num) {
2790 if (data->kind != nct6775 && !val)
2791 return -EINVAL;
2792 if (data->kind != nct6779 && val)
2793 val = 0xff;
2794 }
2795
2796 mutex_lock(&data->update_lock);
2797 data->auto_pwm[nr][point] = val;
2798 if (point < data->auto_pwm_num) {
2799 nct6775_write_value(data,
2800 NCT6775_AUTO_PWM(data, nr, point),
2801 data->auto_pwm[nr][point]);
2802 } else {
2803 switch (data->kind) {
2804 case nct6775:
2805 /* disable if needed (pwm == 0) */
2806 reg = nct6775_read_value(data,
2807 NCT6775_REG_CRITICAL_ENAB[nr]);
2808 if (val)
2809 reg |= 0x02;
2810 else
2811 reg &= ~0x02;
2812 nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
2813 reg);
2814 break;
2815 case nct6776:
2816 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07002817 case nct6106:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002818 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07002819 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08002820 case nct6792:
Guenter Roeck6c009502012-07-01 08:23:15 -07002821 nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002822 val);
2823 reg = nct6775_read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002824 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002825 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07002826 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002827 else
Guenter Roeck6c009502012-07-01 08:23:15 -07002828 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002829 nct6775_write_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07002830 data->REG_CRITICAL_PWM_ENABLE[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002831 reg);
2832 break;
2833 }
2834 }
2835 mutex_unlock(&data->update_lock);
2836 return count;
2837}
2838
2839static ssize_t
2840show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
2841{
2842 struct nct6775_data *data = nct6775_update_device(dev);
2843 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2844 int nr = sattr->nr;
2845 int point = sattr->index;
2846
2847 /*
2848 * We don't know for sure if the temperature is signed or unsigned.
2849 * Assume it is unsigned.
2850 */
2851 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
2852}
2853
2854static ssize_t
2855store_auto_temp(struct device *dev, struct device_attribute *attr,
2856 const char *buf, size_t count)
2857{
2858 struct nct6775_data *data = dev_get_drvdata(dev);
2859 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2860 int nr = sattr->nr;
2861 int point = sattr->index;
2862 unsigned long val;
2863 int err;
2864
2865 err = kstrtoul(buf, 10, &val);
2866 if (err)
2867 return err;
2868 if (val > 255000)
2869 return -EINVAL;
2870
2871 mutex_lock(&data->update_lock);
2872 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
2873 if (point < data->auto_pwm_num) {
2874 nct6775_write_value(data,
2875 NCT6775_AUTO_TEMP(data, nr, point),
2876 data->auto_temp[nr][point]);
2877 } else {
2878 nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
2879 data->auto_temp[nr][point]);
2880 }
2881 mutex_unlock(&data->update_lock);
2882 return count;
2883}
2884
Guenter Roeckf73cf632013-03-18 09:22:50 -07002885static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
2886 struct attribute *attr, int index)
2887{
2888 struct device *dev = container_of(kobj, struct device, kobj);
2889 struct nct6775_data *data = dev_get_drvdata(dev);
2890 int pwm = index / 36; /* pwm index */
2891 int nr = index % 36; /* attribute index */
2892
2893 if (!(data->has_pwm & (1 << pwm)))
2894 return 0;
2895
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002896 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
2897 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
2898 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07002899 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
2900 return 0;
2901 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
2902 return 0;
2903 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
2904 return 0;
2905
2906 if (nr >= 22 && nr <= 35) { /* auto point */
2907 int api = (nr - 22) / 2; /* auto point index */
2908
2909 if (api > data->auto_pwm_num)
2910 return 0;
2911 }
2912 return attr->mode;
2913}
2914
2915SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
2916 show_fan_time, store_fan_time, 0, 0);
2917SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
2918 show_fan_time, store_fan_time, 0, 1);
2919SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
2920 show_fan_time, store_fan_time, 0, 2);
2921SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
2922 store_pwm, 0, 1);
2923SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
2924 store_pwm, 0, 2);
2925SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
2926 show_temp_tolerance, store_temp_tolerance, 0, 0);
2927SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
2928 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
2929 0, 1);
2930
2931SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
2932 0, 3);
2933
2934SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
2935 store_pwm, 0, 4);
2936
2937SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
2938 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
2939SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
2940 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
2941
2942SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
2943 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
2944SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
2945 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
2946
2947SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
2948 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
2949SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
2950 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
2951
2952SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
2953 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
2954SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
2955 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
2956
2957SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
2958 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
2959SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
2960 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
2961
2962SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
2963 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
2964SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
2965 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
2966
2967SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
2968 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
2969SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
2970 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
2971
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002972/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07002973 * nct6775_pwm_is_visible uses the index into the following array
2974 * to determine if attributes should be created or not.
2975 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002976 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002977static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
2978 &sensor_dev_template_pwm,
2979 &sensor_dev_template_pwm_mode,
2980 &sensor_dev_template_pwm_enable,
2981 &sensor_dev_template_pwm_temp_sel,
2982 &sensor_dev_template_pwm_temp_tolerance,
2983 &sensor_dev_template_pwm_crit_temp_tolerance,
2984 &sensor_dev_template_pwm_target_temp,
2985 &sensor_dev_template_fan_target,
2986 &sensor_dev_template_fan_tolerance,
2987 &sensor_dev_template_pwm_stop_time,
2988 &sensor_dev_template_pwm_step_up_time,
2989 &sensor_dev_template_pwm_step_down_time,
2990 &sensor_dev_template_pwm_start,
2991 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002992 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002993 &sensor_dev_template_pwm_weight_temp_step,
2994 &sensor_dev_template_pwm_weight_temp_step_tol,
2995 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08002996 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002997 &sensor_dev_template_pwm_max, /* 19 */
2998 &sensor_dev_template_pwm_step, /* 20 */
2999 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3000 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3001 &sensor_dev_template_pwm_auto_point1_temp,
3002 &sensor_dev_template_pwm_auto_point2_pwm,
3003 &sensor_dev_template_pwm_auto_point2_temp,
3004 &sensor_dev_template_pwm_auto_point3_pwm,
3005 &sensor_dev_template_pwm_auto_point3_temp,
3006 &sensor_dev_template_pwm_auto_point4_pwm,
3007 &sensor_dev_template_pwm_auto_point4_temp,
3008 &sensor_dev_template_pwm_auto_point5_pwm,
3009 &sensor_dev_template_pwm_auto_point5_temp,
3010 &sensor_dev_template_pwm_auto_point6_pwm,
3011 &sensor_dev_template_pwm_auto_point6_temp,
3012 &sensor_dev_template_pwm_auto_point7_pwm,
3013 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003014
Guenter Roeckf73cf632013-03-18 09:22:50 -07003015 NULL
3016};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003017
Guenter Roeckf73cf632013-03-18 09:22:50 -07003018static struct sensor_template_group nct6775_pwm_template_group = {
3019 .templates = nct6775_attributes_pwm_template,
3020 .is_visible = nct6775_pwm_is_visible,
3021 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003022};
3023
3024static ssize_t
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003025show_vid(struct device *dev, struct device_attribute *attr, char *buf)
3026{
3027 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003028
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003029 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3030}
3031
3032static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
3033
Guenter Roecka6bd5872012-12-04 03:13:34 -08003034/* Case open detection */
3035
3036static ssize_t
3037clear_caseopen(struct device *dev, struct device_attribute *attr,
3038 const char *buf, size_t count)
3039{
3040 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003041 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3042 unsigned long val;
3043 u8 reg;
3044 int ret;
3045
3046 if (kstrtoul(buf, 10, &val) || val != 0)
3047 return -EINVAL;
3048
3049 mutex_lock(&data->update_lock);
3050
3051 /*
3052 * Use CR registers to clear caseopen status.
3053 * The CR registers are the same for all chips, and not all chips
3054 * support clearing the caseopen status through "regular" registers.
3055 */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003056 ret = superio_enter(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003057 if (ret) {
3058 count = ret;
3059 goto error;
3060 }
3061
Guenter Roeckdf612d52013-07-08 13:15:04 -07003062 superio_select(data->sioreg, NCT6775_LD_ACPI);
3063 reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003064 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003065 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003066 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Guenter Roeckdf612d52013-07-08 13:15:04 -07003067 superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3068 superio_exit(data->sioreg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003069
3070 data->valid = false; /* Force cache refresh */
3071error:
3072 mutex_unlock(&data->update_lock);
3073 return count;
3074}
3075
Guenter Roeckf73cf632013-03-18 09:22:50 -07003076static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3077 clear_caseopen, INTRUSION_ALARM_BASE);
3078static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3079 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003080static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3081 store_beep, INTRUSION_ALARM_BASE);
3082static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3083 store_beep, INTRUSION_ALARM_BASE + 1);
3084static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3085 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003086
3087static umode_t nct6775_other_is_visible(struct kobject *kobj,
3088 struct attribute *attr, int index)
3089{
3090 struct device *dev = container_of(kobj, struct device, kobj);
3091 struct nct6775_data *data = dev_get_drvdata(dev);
3092
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003093 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003094 return 0;
3095
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003096 if (index == 1 || index == 2) {
3097 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003098 return 0;
3099 }
3100
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003101 if (index == 3 || index == 4) {
3102 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003103 return 0;
3104 }
3105
Guenter Roeckf73cf632013-03-18 09:22:50 -07003106 return attr->mode;
3107}
3108
3109/*
3110 * nct6775_other_is_visible uses the index into the following array
3111 * to determine if attributes should be created or not.
3112 * Any change in order or content must be matched.
3113 */
3114static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003115 &dev_attr_cpu0_vid.attr, /* 0 */
3116 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3117 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3118 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3119 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3120 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003121
3122 NULL
3123};
3124
3125static const struct attribute_group nct6775_group_other = {
3126 .attrs = nct6775_attributes_other,
3127 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003128};
3129
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003130static inline void nct6775_init_device(struct nct6775_data *data)
3131{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003132 int i;
3133 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003134
3135 /* Start monitoring if needed */
3136 if (data->REG_CONFIG) {
3137 tmp = nct6775_read_value(data, data->REG_CONFIG);
3138 if (!(tmp & 0x01))
3139 nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
3140 }
3141
Guenter Roeckaa136e52012-12-04 03:26:05 -08003142 /* Enable temperature sensors if needed */
3143 for (i = 0; i < NUM_TEMP; i++) {
3144 if (!(data->have_temp & (1 << i)))
3145 continue;
3146 if (!data->reg_temp_config[i])
3147 continue;
3148 tmp = nct6775_read_value(data, data->reg_temp_config[i]);
3149 if (tmp & 0x01)
3150 nct6775_write_value(data, data->reg_temp_config[i],
3151 tmp & 0xfe);
3152 }
3153
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003154 /* Enable VBAT monitoring if needed */
3155 tmp = nct6775_read_value(data, data->REG_VBAT);
3156 if (!(tmp & 0x01))
3157 nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003158
3159 diode = nct6775_read_value(data, data->REG_DIODE);
3160
3161 for (i = 0; i < data->temp_fixed_num; i++) {
3162 if (!(data->have_temp_fixed & (1 << i)))
3163 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003164 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3165 data->temp_type[i]
3166 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003167 else /* thermistor */
3168 data->temp_type[i] = 4;
3169 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003170}
3171
Guenter Roeckf73cf632013-03-18 09:22:50 -07003172static void
Guenter Roeckdf612d52013-07-08 13:15:04 -07003173nct6775_check_fan_inputs(struct nct6775_data *data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003174{
David Bartley578ab5f2013-06-24 22:28:28 -07003175 bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
3176 bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003177 int sioreg = data->sioreg;
3178 int regval;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003179
3180 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3181 if (data->kind == nct6775) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003182 regval = superio_inb(sioreg, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003183
3184 fan3pin = regval & (1 << 6);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003185 pwm3pin = regval & (1 << 7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003186
3187 /* On NCT6775, fan4 shares pins with the fdc interface */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003188 fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
David Bartley578ab5f2013-06-24 22:28:28 -07003189 fan4min = false;
3190 fan5pin = false;
3191 fan6pin = false;
3192 pwm4pin = false;
3193 pwm5pin = false;
3194 pwm6pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003195 } else if (data->kind == nct6776) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003196 bool gpok = superio_inb(sioreg, 0x27) & 0x80;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003197
Guenter Roeckdf612d52013-07-08 13:15:04 -07003198 superio_select(sioreg, NCT6775_LD_HWM);
3199 regval = superio_inb(sioreg, SIO_REG_ENABLE);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003200
3201 if (regval & 0x80)
3202 fan3pin = gpok;
3203 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003204 fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003205
3206 if (regval & 0x40)
3207 fan4pin = gpok;
3208 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003209 fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003210
3211 if (regval & 0x20)
3212 fan5pin = gpok;
3213 else
Guenter Roeckdf612d52013-07-08 13:15:04 -07003214 fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003215
3216 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003217 fan6pin = false;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003218 pwm3pin = fan3pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003219 pwm4pin = false;
3220 pwm5pin = false;
3221 pwm6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003222 } else if (data->kind == nct6106) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003223 regval = superio_inb(sioreg, 0x24);
Guenter Roeck6c009502012-07-01 08:23:15 -07003224 fan3pin = !(regval & 0x80);
3225 pwm3pin = regval & 0x08;
Guenter Roeck6c009502012-07-01 08:23:15 -07003226
3227 fan4pin = false;
3228 fan4min = false;
3229 fan5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003230 fan6pin = false;
Guenter Roeck6c009502012-07-01 08:23:15 -07003231 pwm4pin = false;
3232 pwm5pin = false;
David Bartley578ab5f2013-06-24 22:28:28 -07003233 pwm6pin = false;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003234 } else { /* NCT6779D, NCT6791D, or NCT6792D */
Guenter Roeckdf612d52013-07-08 13:15:04 -07003235 regval = superio_inb(sioreg, 0x1c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003236
3237 fan3pin = !(regval & (1 << 5));
3238 fan4pin = !(regval & (1 << 6));
3239 fan5pin = !(regval & (1 << 7));
3240
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003241 pwm3pin = !(regval & (1 << 0));
3242 pwm4pin = !(regval & (1 << 1));
3243 pwm5pin = !(regval & (1 << 2));
3244
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003245 fan4min = fan4pin;
David Bartley578ab5f2013-06-24 22:28:28 -07003246
Guenter Roeck8aefb932014-11-16 09:50:04 -08003247 if (data->kind == nct6791 || data->kind == nct6792) {
Guenter Roeckdf612d52013-07-08 13:15:04 -07003248 regval = superio_inb(sioreg, 0x2d);
David Bartley578ab5f2013-06-24 22:28:28 -07003249 fan6pin = (regval & (1 << 1));
3250 pwm6pin = (regval & (1 << 0));
3251 } else { /* NCT6779D */
3252 fan6pin = false;
3253 pwm6pin = false;
3254 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003255 }
3256
David Bartley578ab5f2013-06-24 22:28:28 -07003257 /* fan 1 and 2 (0x03) are always present */
3258 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
3259 (fan5pin << 4) | (fan6pin << 5);
3260 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
3261 (fan5pin << 4);
3262 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
3263 (pwm5pin << 4) | (pwm6pin << 5);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003264}
3265
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003266static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3267 int *available, int *mask)
3268{
3269 int i;
3270 u8 src;
3271
3272 for (i = 0; i < data->pwm_num && *available; i++) {
3273 int index;
3274
3275 if (!regp[i])
3276 continue;
3277 src = nct6775_read_value(data, regp[i]);
3278 src &= 0x1f;
3279 if (!src || (*mask & (1 << src)))
3280 continue;
3281 if (src >= data->temp_label_num ||
3282 !strlen(data->temp_label[src]))
3283 continue;
3284
3285 index = __ffs(*available);
3286 nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
3287 *available &= ~(1 << index);
3288 *mask |= 1 << src;
3289 }
3290}
3291
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003292static int nct6775_probe(struct platform_device *pdev)
3293{
3294 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003295 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003296 struct nct6775_data *data;
3297 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003298 int i, s, err = 0;
3299 int src, mask, available;
3300 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003301 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003302 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003303 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003304 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003305 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003306 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003307 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003308
3309 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3310 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3311 DRVNAME))
3312 return -EBUSY;
3313
3314 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3315 GFP_KERNEL);
3316 if (!data)
3317 return -ENOMEM;
3318
3319 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003320 data->sioreg = sio_data->sioreg;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003321 data->addr = res->start;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003322 mutex_init(&data->update_lock);
3323 data->name = nct6775_device_names[data->kind];
3324 data->bank = 0xff; /* Force initial bank selection */
3325 platform_set_drvdata(pdev, data);
3326
3327 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003328 case nct6106:
3329 data->in_num = 9;
3330 data->pwm_num = 3;
3331 data->auto_pwm_num = 4;
3332 data->temp_fixed_num = 3;
3333 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003334 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003335
3336 data->fan_from_reg = fan_from_reg13;
3337 data->fan_from_reg_min = fan_from_reg13;
3338
3339 data->temp_label = nct6776_temp_label;
3340 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3341
3342 data->REG_VBAT = NCT6106_REG_VBAT;
3343 data->REG_DIODE = NCT6106_REG_DIODE;
3344 data->DIODE_MASK = NCT6106_DIODE_MASK;
3345 data->REG_VIN = NCT6106_REG_IN;
3346 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
3347 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
3348 data->REG_TARGET = NCT6106_REG_TARGET;
3349 data->REG_FAN = NCT6106_REG_FAN;
3350 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
3351 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
3352 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
3353 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
3354 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
3355 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
3356 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
3357 data->REG_PWM[0] = NCT6106_REG_PWM;
3358 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
3359 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
3360 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
3361 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
3362 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
3363 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
3364 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
3365 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
3366 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
3367 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
3368 data->REG_CRITICAL_TEMP_TOLERANCE
3369 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
3370 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
3371 data->CRITICAL_PWM_ENABLE_MASK
3372 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
3373 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
3374 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
3375 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
3376 data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
3377 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
3378 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
3379 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
3380 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
3381 data->REG_ALARM = NCT6106_REG_ALARM;
3382 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003383 data->REG_BEEP = NCT6106_REG_BEEP;
3384 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07003385
3386 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003387 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07003388 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003389 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07003390 reg_temp_over = NCT6106_REG_TEMP_OVER;
3391 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
3392 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
3393 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
3394 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003395 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
3396 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07003397
3398 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003399 case nct6775:
3400 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003401 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003402 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003403 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003404 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003405 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003406 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003407
3408 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003409 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003410
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003411 data->fan_from_reg = fan_from_reg16;
3412 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003413 data->target_temp_mask = 0x7f;
3414 data->tolerance_mask = 0x0f;
3415 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003416
Guenter Roeckaa136e52012-12-04 03:26:05 -08003417 data->temp_label = nct6775_temp_label;
3418 data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
3419
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003420 data->REG_CONFIG = NCT6775_REG_CONFIG;
3421 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003422 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003423 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003424 data->REG_VIN = NCT6775_REG_IN;
3425 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3426 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003427 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003428 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003429 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003430 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003431 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003432 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003433 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3434 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3435 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003436 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003437 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3438 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
3439 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
3440 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003441 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003442 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3443 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
3444 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003445 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3446 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3447 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3448 data->REG_CRITICAL_TEMP_TOLERANCE
3449 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003450 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3451 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003452 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003453 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3454 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3455 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3456 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003457 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003458 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003459
3460 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003461 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003462 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003463 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003464 reg_temp_over = NCT6775_REG_TEMP_OVER;
3465 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3466 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
3467 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
3468 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
3469
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003470 break;
3471 case nct6776:
3472 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003473 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003474 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003475 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003476 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003477 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07003478 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003479
3480 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003481 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003482
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003483 data->fan_from_reg = fan_from_reg13;
3484 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003485 data->target_temp_mask = 0xff;
3486 data->tolerance_mask = 0x07;
3487 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003488
Guenter Roeckaa136e52012-12-04 03:26:05 -08003489 data->temp_label = nct6776_temp_label;
3490 data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
3491
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003492 data->REG_CONFIG = NCT6775_REG_CONFIG;
3493 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003494 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003495 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003496 data->REG_VIN = NCT6775_REG_IN;
3497 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3498 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003499 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003500 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003501 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003502 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003503 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003504 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003505 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3506 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3507 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3508 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003509 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003510 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3511 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003512 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3513 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003514 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3515 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3516 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003517 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3518 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3519 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3520 data->REG_CRITICAL_TEMP_TOLERANCE
3521 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003522 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
3523 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003524 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003525 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3526 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3527 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3528 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003529 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003530 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003531
3532 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003533 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003534 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003535 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003536 reg_temp_over = NCT6775_REG_TEMP_OVER;
3537 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
3538 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
3539 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
3540 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
3541
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003542 break;
3543 case nct6779:
3544 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003545 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003546 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003547 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003548 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07003549 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07003550 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003551
3552 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07003553 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003554
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003555 data->fan_from_reg = fan_from_reg13;
3556 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003557 data->target_temp_mask = 0xff;
3558 data->tolerance_mask = 0x07;
3559 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003560
Guenter Roeckaa136e52012-12-04 03:26:05 -08003561 data->temp_label = nct6779_temp_label;
3562 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3563
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003564 data->REG_CONFIG = NCT6775_REG_CONFIG;
3565 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003566 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003567 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003568 data->REG_VIN = NCT6779_REG_IN;
3569 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3570 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003571 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003572 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003573 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003574 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08003575 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07003576 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003577 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3578 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3579 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3580 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003581 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003582 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3583 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003584 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
3585 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003586 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3587 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3588 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003589 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3590 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3591 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3592 data->REG_CRITICAL_TEMP_TOLERANCE
3593 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07003594 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3595 data->CRITICAL_PWM_ENABLE_MASK
3596 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3597 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003598 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3599 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003600 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003601 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
3602 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
3603 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
3604 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003605 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07003606 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003607
3608 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003609 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003610 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003611 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003612 reg_temp_over = NCT6779_REG_TEMP_OVER;
3613 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3614 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3615 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3616 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3617
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003618 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003619 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003620 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003621 data->in_num = 15;
3622 data->pwm_num = 6;
3623 data->auto_pwm_num = 4;
3624 data->has_fan_div = false;
3625 data->temp_fixed_num = 6;
3626 data->num_temp_alarms = 2;
3627 data->num_temp_beeps = 2;
3628
3629 data->ALARM_BITS = NCT6791_ALARM_BITS;
3630 data->BEEP_BITS = NCT6779_BEEP_BITS;
3631
3632 data->fan_from_reg = fan_from_reg13;
3633 data->fan_from_reg_min = fan_from_reg13;
3634 data->target_temp_mask = 0xff;
3635 data->tolerance_mask = 0x07;
3636 data->speed_tolerance_limit = 63;
3637
3638 data->temp_label = nct6779_temp_label;
3639 data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
3640
3641 data->REG_CONFIG = NCT6775_REG_CONFIG;
3642 data->REG_VBAT = NCT6775_REG_VBAT;
3643 data->REG_DIODE = NCT6775_REG_DIODE;
3644 data->DIODE_MASK = NCT6775_DIODE_MASK;
3645 data->REG_VIN = NCT6779_REG_IN;
3646 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
3647 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
3648 data->REG_TARGET = NCT6775_REG_TARGET;
3649 data->REG_FAN = NCT6779_REG_FAN;
3650 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
3651 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
3652 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
3653 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
3654 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
3655 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
3656 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
3657 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
3658 data->REG_PWM[0] = NCT6775_REG_PWM;
3659 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
3660 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003661 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
3662 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003663 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
3664 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
3665 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
3666 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
3667 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
3668 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
3669 data->REG_CRITICAL_TEMP_TOLERANCE
3670 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
3671 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
3672 data->CRITICAL_PWM_ENABLE_MASK
3673 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
3674 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
3675 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
3676 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
3677 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003678 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
3679 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
3680 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
3681 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07003682 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08003683 if (data->kind == nct6791)
3684 data->REG_BEEP = NCT6776_REG_BEEP;
3685 else
3686 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07003687
3688 reg_temp = NCT6779_REG_TEMP;
3689 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08003690 if (data->kind == nct6791) {
3691 reg_temp_mon = NCT6779_REG_TEMP_MON;
3692 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
3693 } else {
3694 reg_temp_mon = NCT6792_REG_TEMP_MON;
3695 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
3696 }
David Bartley578ab5f2013-06-24 22:28:28 -07003697 reg_temp_over = NCT6779_REG_TEMP_OVER;
3698 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
3699 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
3700 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
3701 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
3702
3703 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003704 default:
3705 return -ENODEV;
3706 }
3707 data->have_in = (1 << data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003708 data->have_temp = 0;
3709
3710 /*
3711 * On some boards, not all available temperature sources are monitored,
3712 * even though some of the monitoring registers are unused.
3713 * Get list of unused monitoring registers, then detect if any fan
3714 * controls are configured to use unmonitored temperature sources.
3715 * If so, assign the unmonitored temperature sources to available
3716 * monitoring registers.
3717 */
3718 mask = 0;
3719 available = 0;
3720 for (i = 0; i < num_reg_temp; i++) {
3721 if (reg_temp[i] == 0)
3722 continue;
3723
3724 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3725 if (!src || (mask & (1 << src)))
3726 available |= 1 << i;
3727
3728 mask |= 1 << src;
3729 }
3730
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003731 /*
3732 * Now find unmonitored temperature registers and enable monitoring
3733 * if additional monitoring registers are available.
3734 */
3735 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
3736 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
3737
Guenter Roeckaa136e52012-12-04 03:26:05 -08003738 mask = 0;
3739 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
3740 for (i = 0; i < num_reg_temp; i++) {
3741 if (reg_temp[i] == 0)
3742 continue;
3743
3744 src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
3745 if (!src || (mask & (1 << src)))
3746 continue;
3747
3748 if (src >= data->temp_label_num ||
3749 !strlen(data->temp_label[src])) {
3750 dev_info(dev,
3751 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3752 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
3753 continue;
3754 }
3755
3756 mask |= 1 << src;
3757
3758 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3759 if (src <= data->temp_fixed_num) {
3760 data->have_temp |= 1 << (src - 1);
3761 data->have_temp_fixed |= 1 << (src - 1);
3762 data->reg_temp[0][src - 1] = reg_temp[i];
3763 data->reg_temp[1][src - 1] = reg_temp_over[i];
3764 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003765 if (reg_temp_crit_h && reg_temp_crit_h[i])
3766 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
3767 else if (reg_temp_crit[src - 1])
3768 data->reg_temp[3][src - 1]
3769 = reg_temp_crit[src - 1];
3770 if (reg_temp_crit_l && reg_temp_crit_l[i])
3771 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003772 data->reg_temp_config[src - 1] = reg_temp_config[i];
3773 data->temp_src[src - 1] = src;
3774 continue;
3775 }
3776
3777 if (s >= NUM_TEMP)
3778 continue;
3779
3780 /* Use dynamic index for other sources */
3781 data->have_temp |= 1 << s;
3782 data->reg_temp[0][s] = reg_temp[i];
3783 data->reg_temp[1][s] = reg_temp_over[i];
3784 data->reg_temp[2][s] = reg_temp_hyst[i];
3785 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003786 if (reg_temp_crit_h && reg_temp_crit_h[i])
3787 data->reg_temp[3][s] = reg_temp_crit_h[i];
3788 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08003789 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07003790 if (reg_temp_crit_l && reg_temp_crit_l[i])
3791 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08003792
3793 data->temp_src[s] = src;
3794 s++;
3795 }
3796
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003797 /*
3798 * Repeat with temperatures used for fan control.
3799 * This set of registers does not support limits.
3800 */
3801 for (i = 0; i < num_reg_temp_mon; i++) {
3802 if (reg_temp_mon[i] == 0)
3803 continue;
3804
3805 src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
3806 if (!src || (mask & (1 << src)))
3807 continue;
3808
3809 if (src >= data->temp_label_num ||
3810 !strlen(data->temp_label[src])) {
3811 dev_info(dev,
3812 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
3813 src, i, data->REG_TEMP_SEL[i],
3814 reg_temp_mon[i]);
3815 continue;
3816 }
3817
3818 mask |= 1 << src;
3819
3820 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
3821 if (src <= data->temp_fixed_num) {
3822 if (data->have_temp & (1 << (src - 1)))
3823 continue;
3824 data->have_temp |= 1 << (src - 1);
3825 data->have_temp_fixed |= 1 << (src - 1);
3826 data->reg_temp[0][src - 1] = reg_temp_mon[i];
3827 data->temp_src[src - 1] = src;
3828 continue;
3829 }
3830
3831 if (s >= NUM_TEMP)
3832 continue;
3833
3834 /* Use dynamic index for other sources */
3835 data->have_temp |= 1 << s;
3836 data->reg_temp[0][s] = reg_temp_mon[i];
3837 data->temp_src[s] = src;
3838 s++;
3839 }
3840
Guenter Roeckaa136e52012-12-04 03:26:05 -08003841#ifdef USE_ALTERNATE
3842 /*
3843 * Go through the list of alternate temp registers and enable
3844 * if possible.
3845 * The temperature is already monitored if the respective bit in <mask>
3846 * is set.
3847 */
3848 for (i = 0; i < data->temp_label_num - 1; i++) {
3849 if (!reg_temp_alternate[i])
3850 continue;
3851 if (mask & (1 << (i + 1)))
3852 continue;
3853 if (i < data->temp_fixed_num) {
3854 if (data->have_temp & (1 << i))
3855 continue;
3856 data->have_temp |= 1 << i;
3857 data->have_temp_fixed |= 1 << i;
3858 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05c2013-05-09 10:40:01 -07003859 if (i < num_reg_temp) {
3860 data->reg_temp[1][i] = reg_temp_over[i];
3861 data->reg_temp[2][i] = reg_temp_hyst[i];
3862 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08003863 data->temp_src[i] = i + 1;
3864 continue;
3865 }
3866
3867 if (s >= NUM_TEMP) /* Abort if no more space */
3868 break;
3869
3870 data->have_temp |= 1 << s;
3871 data->reg_temp[0][s] = reg_temp_alternate[i];
3872 data->temp_src[s] = i + 1;
3873 s++;
3874 }
3875#endif /* USE_ALTERNATE */
3876
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003877 /* Initialize the chip */
3878 nct6775_init_device(data);
3879
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003880 err = superio_enter(sio_data->sioreg);
3881 if (err)
3882 return err;
3883
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003884 cr2a = superio_inb(sio_data->sioreg, 0x2a);
3885 switch (data->kind) {
3886 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003887 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003888 break;
3889 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07003890 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003891 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07003892 case nct6106:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003893 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003894 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003895 case nct6792:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003896 break;
3897 }
3898
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003899 /*
3900 * Read VID value
3901 * We can get the VID input values directly at logical device D 0xe3.
3902 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003903 if (data->have_vid) {
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003904 superio_select(sio_data->sioreg, NCT6775_LD_VID);
3905 data->vid = superio_inb(sio_data->sioreg, 0xe3);
3906 data->vrm = vid_which_vrm();
3907 }
Guenter Roeck47ece962012-12-04 07:59:32 -08003908
3909 if (fan_debounce) {
3910 u8 tmp;
3911
3912 superio_select(sio_data->sioreg, NCT6775_LD_HWM);
3913 tmp = superio_inb(sio_data->sioreg,
3914 NCT6775_REG_CR_FAN_DEBOUNCE);
3915 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003916 case nct6106:
3917 tmp |= 0xe0;
3918 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003919 case nct6775:
3920 tmp |= 0x1e;
3921 break;
3922 case nct6776:
3923 case nct6779:
3924 tmp |= 0x3e;
3925 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003926 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003927 case nct6792:
David Bartley578ab5f2013-06-24 22:28:28 -07003928 tmp |= 0x7e;
3929 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08003930 }
3931 superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
3932 tmp);
3933 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
3934 data->name);
3935 }
3936
Guenter Roeckdf612d52013-07-08 13:15:04 -07003937 nct6775_check_fan_inputs(data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003938
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003939 superio_exit(sio_data->sioreg);
3940
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003941 /* Read fan clock dividers immediately */
3942 nct6775_init_fan_common(dev, data);
3943
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003944 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003945 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
3946 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003947 if (IS_ERR(group))
3948 return PTR_ERR(group);
3949
Axel Lin55bdee62014-07-24 08:59:34 +08003950 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003951
Guenter Roeckf73cf632013-03-18 09:22:50 -07003952 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
3953 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003954 if (IS_ERR(group))
3955 return PTR_ERR(group);
3956
Axel Lin55bdee62014-07-24 08:59:34 +08003957 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003958
Guenter Roeckf73cf632013-03-18 09:22:50 -07003959 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
3960 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003961 if (IS_ERR(group))
3962 return PTR_ERR(group);
3963
Axel Lin55bdee62014-07-24 08:59:34 +08003964 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003965
Guenter Roeckf73cf632013-03-18 09:22:50 -07003966 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
3967 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003968 if (IS_ERR(group))
3969 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003970
Axel Lin55bdee62014-07-24 08:59:34 +08003971 data->groups[num_attr_groups++] = group;
3972 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003973
Guenter Roecka150d952013-07-11 22:55:22 -07003974 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
3975 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07003976 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003977}
3978
Guenter Roeckf5776cc2013-12-25 07:25:59 -08003979static void nct6791_enable_io_mapping(int sioaddr)
3980{
3981 int val;
3982
3983 val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
3984 if (val & 0x10) {
3985 pr_info("Enabling hardware monitor logical device mappings.\n");
3986 superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
3987 val & ~0x10);
3988 }
3989}
3990
Guenter Roeck48e93182015-02-07 08:48:49 -08003991static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08003992{
3993 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08003994
3995 mutex_lock(&data->update_lock);
3996 data->vbat = nct6775_read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07003997 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08003998 data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
3999 data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
4000 }
4001 mutex_unlock(&data->update_lock);
4002
4003 return 0;
4004}
4005
Guenter Roeck48e93182015-02-07 08:48:49 -08004006static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004007{
4008 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004009 int i, j, err = 0;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004010
4011 mutex_lock(&data->update_lock);
4012 data->bank = 0xff; /* Force initial bank selection */
4013
Guenter Roeck8aefb932014-11-16 09:50:04 -08004014 if (data->kind == nct6791 || data->kind == nct6792) {
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004015 err = superio_enter(data->sioreg);
4016 if (err)
4017 goto abort;
4018
4019 nct6791_enable_io_mapping(data->sioreg);
4020 superio_exit(data->sioreg);
4021 }
4022
Guenter Roeck84d19d92012-12-04 08:01:39 -08004023 /* Restore limits */
4024 for (i = 0; i < data->in_num; i++) {
4025 if (!(data->have_in & (1 << i)))
4026 continue;
4027
4028 nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
4029 data->in[i][1]);
4030 nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
4031 data->in[i][2]);
4032 }
4033
Guenter Roeckc409fd42013-04-09 05:04:00 -07004034 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004035 if (!(data->has_fan_min & (1 << i)))
4036 continue;
4037
4038 nct6775_write_value(data, data->REG_FAN_MIN[i],
4039 data->fan_min[i]);
4040 }
4041
4042 for (i = 0; i < NUM_TEMP; i++) {
4043 if (!(data->have_temp & (1 << i)))
4044 continue;
4045
Guenter Roeckc409fd42013-04-09 05:04:00 -07004046 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004047 if (data->reg_temp[j][i])
4048 nct6775_write_temp(data, data->reg_temp[j][i],
4049 data->temp[j][i]);
4050 }
4051
4052 /* Restore other settings */
4053 nct6775_write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004054 if (data->kind == nct6775) {
Guenter Roeck84d19d92012-12-04 08:01:39 -08004055 nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4056 nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
4057 }
4058
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004059abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004060 /* Force re-reading all values */
4061 data->valid = false;
4062 mutex_unlock(&data->update_lock);
4063
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004064 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004065}
4066
Guenter Roeck48e93182015-02-07 08:48:49 -08004067static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004068
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004069static struct platform_driver nct6775_driver = {
4070 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004071 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004072 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004073 },
4074 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004075};
4076
Guenter Roeck6d4b3622013-04-21 09:08:11 -07004077static const char * const nct6775_sio_names[] __initconst = {
Guenter Roeck6c009502012-07-01 08:23:15 -07004078 "NCT6106D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004079 "NCT6775F",
4080 "NCT6776D/F",
4081 "NCT6779D",
David Bartley578ab5f2013-06-24 22:28:28 -07004082 "NCT6791D",
Guenter Roeck8aefb932014-11-16 09:50:04 -08004083 "NCT6792D",
Guenter Roeck2c7fd302013-04-02 08:53:19 -07004084};
4085
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004086/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004087static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004088{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004089 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004090 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004091 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004092
4093 err = superio_enter(sioaddr);
4094 if (err)
4095 return err;
4096
4097 if (force_id)
4098 val = force_id;
4099 else
4100 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
4101 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
4102 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004103 case SIO_NCT6106_ID:
4104 sio_data->kind = nct6106;
4105 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004106 case SIO_NCT6775_ID:
4107 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004108 break;
4109 case SIO_NCT6776_ID:
4110 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004111 break;
4112 case SIO_NCT6779_ID:
4113 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004114 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004115 case SIO_NCT6791_ID:
4116 sio_data->kind = nct6791;
4117 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004118 case SIO_NCT6792_ID:
4119 sio_data->kind = nct6792;
4120 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004121 default:
4122 if (val != 0xffff)
4123 pr_debug("unsupported chip ID: 0x%04x\n", val);
4124 superio_exit(sioaddr);
4125 return -ENODEV;
4126 }
4127
4128 /* We have a known chip, find the HWM I/O address */
4129 superio_select(sioaddr, NCT6775_LD_HWM);
4130 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
4131 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004132 addr = val & IOREGION_ALIGNMENT;
4133 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004134 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
4135 superio_exit(sioaddr);
4136 return -ENODEV;
4137 }
4138
4139 /* Activate logical device if needed */
4140 val = superio_inb(sioaddr, SIO_REG_ENABLE);
4141 if (!(val & 0x01)) {
4142 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
4143 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
4144 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004145
Guenter Roeck8aefb932014-11-16 09:50:04 -08004146 if (sio_data->kind == nct6791 || sio_data->kind == nct6792)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004147 nct6791_enable_io_mapping(sioaddr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004148
4149 superio_exit(sioaddr);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004150 pr_info("Found %s or compatible chip at %#x:%#x\n",
4151 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004152 sio_data->sioreg = sioaddr;
4153
Guenter Roeck698a7c22013-04-05 07:35:25 -07004154 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004155}
4156
4157/*
4158 * when Super-I/O functions move to a separate file, the Super-I/O
4159 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004160 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004161 * must keep track of the device
4162 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004163static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004164
4165static int __init sensors_nct6775_init(void)
4166{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004167 int i, err;
4168 bool found = false;
4169 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004170 struct resource res;
4171 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004172 int sioaddr[2] = { 0x2e, 0x4e };
4173
4174 err = platform_driver_register(&nct6775_driver);
4175 if (err)
4176 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004177
4178 /*
4179 * initialize sio_data->kind and sio_data->sioreg.
4180 *
4181 * when Super-I/O functions move to a separate file, the Super-I/O
4182 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
4183 * nct6775 hardware monitor, and call probe()
4184 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004185 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4186 address = nct6775_find(sioaddr[i], &sio_data);
4187 if (address <= 0)
4188 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004189
Guenter Roeck698a7c22013-04-05 07:35:25 -07004190 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004191
Guenter Roeck698a7c22013-04-05 07:35:25 -07004192 pdev[i] = platform_device_alloc(DRVNAME, address);
4193 if (!pdev[i]) {
4194 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08004195 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004196 }
4197
4198 err = platform_device_add_data(pdev[i], &sio_data,
4199 sizeof(struct nct6775_sio_data));
4200 if (err)
4201 goto exit_device_put;
4202
4203 memset(&res, 0, sizeof(res));
4204 res.name = DRVNAME;
4205 res.start = address + IOREGION_OFFSET;
4206 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
4207 res.flags = IORESOURCE_IO;
4208
4209 err = acpi_check_resource_conflict(&res);
4210 if (err) {
4211 platform_device_put(pdev[i]);
4212 pdev[i] = NULL;
4213 continue;
4214 }
4215
4216 err = platform_device_add_resources(pdev[i], &res, 1);
4217 if (err)
4218 goto exit_device_put;
4219
4220 /* platform_device_add calls probe() */
4221 err = platform_device_add(pdev[i]);
4222 if (err)
4223 goto exit_device_put;
4224 }
4225 if (!found) {
4226 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004227 goto exit_unregister;
4228 }
4229
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230 return 0;
4231
4232exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08004233 platform_device_put(pdev[i]);
4234exit_device_unregister:
4235 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07004236 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08004237 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004238 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004239exit_unregister:
4240 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004241 return err;
4242}
4243
4244static void __exit sensors_nct6775_exit(void)
4245{
Guenter Roeck698a7c22013-04-05 07:35:25 -07004246 int i;
4247
4248 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
4249 if (pdev[i])
4250 platform_device_unregister(pdev[i]);
4251 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004252 platform_driver_unregister(&nct6775_driver);
4253}
4254
4255MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeck8aefb932014-11-16 09:50:04 -08004256MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004257MODULE_LICENSE("GPL");
4258
4259module_init(sensors_nct6775_init);
4260module_exit(sensors_nct6775_exit);