blob: b3b4f2b41dcfb82d720083bba7e3e7c1bb671e71 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
Guenter Roecke7e1ca62011-02-04 13:24:30 -08003 the Winbond W83627EHF Super-I/O chip
Jean Delvare08e7e272005-04-25 22:43:25 +02004 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Guenter Roecke7e1ca62011-02-04 13:24:30 -08006 Rudolf Marek <r.marek@assembler.cz>
7 David Hubbard <david.c.hubbard@gmail.com>
Daniel J Blueman41e9a062009-12-14 18:01:37 -08008 Daniel J Blueman <daniel.blueman@gmail.com>
Guenter Roeckec3e5a12011-02-02 08:46:49 -08009 Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
Jean Delvare08e7e272005-04-25 22:43:25 +020010
11 Shamelessly ripped from the w83627hf driver
12 Copyright (C) 2003 Mark Studebaker
13
14 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
15 in testing and debugging this driver.
16
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020017 This driver also supports the W83627EHG, which is the lead-free
18 version of the W83627EHF.
19
Jean Delvare08e7e272005-04-25 22:43:25 +020020 This program is free software; you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 2 of the License, or
23 (at your option) any later version.
24
25 This program is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33
34
35 Supports the following chips:
36
David Hubbard657c93b2007-02-14 21:15:04 +010037 Chip #vin #fan #pwm #temp chip IDs man ID
38 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
Guenter Roecke7e1ca62011-02-04 13:24:30 -080039 0x8860 0xa1
David Hubbard657c93b2007-02-14 21:15:04 +010040 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvarec1e48dc2009-06-15 18:39:50 +020041 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
Gong Jun237c8d2f2009-03-30 21:46:42 +020042 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Guenter Roeckd36cf322011-02-07 15:08:54 -080043 w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
Guenter Roeckec3e5a12011-02-02 08:46:49 -080044 nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3
45 nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020046*/
47
Joe Perchesabdc6fd2010-10-20 06:51:54 +000048#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
Jean Delvare08e7e272005-04-25 22:43:25 +020050#include <linux/module.h>
51#include <linux/init.h>
52#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020053#include <linux/jiffies.h>
54#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040055#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010056#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020057#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040058#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010059#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010060#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020061#include <linux/io.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020062#include "lm75.h"
63
Guenter Roeckec3e5a12011-02-02 08:46:49 -080064enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775,
65 nct6776 };
David Hubbard1ea6dd32007-06-24 11:16:15 +020066
67/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
Guenter Roecke7e1ca62011-02-04 13:24:30 -080068static const char * const w83627ehf_device_names[] = {
David Hubbard1ea6dd32007-06-24 11:16:15 +020069 "w83627ehf",
70 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020071 "w83627dhg",
Gong Jun237c8d2f2009-03-30 21:46:42 +020072 "w83667hg",
Guenter Roeckc39aeda2010-08-14 21:08:55 +020073 "w83667hg",
Guenter Roeckec3e5a12011-02-02 08:46:49 -080074 "nct6775",
75 "nct6776",
David Hubbard1ea6dd32007-06-24 11:16:15 +020076};
77
Jean Delvare67b671b2007-12-06 23:13:42 +010078static unsigned short force_id;
79module_param(force_id, ushort, 0);
80MODULE_PARM_DESC(force_id, "Override the detected device ID");
81
David Hubbard1ea6dd32007-06-24 11:16:15 +020082#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020083
84/*
85 * Super-I/O constants and functions
86 */
87
Jean Delvare08e7e272005-04-25 22:43:25 +020088#define W83627EHF_LD_HWM 0x0b
Guenter Roecke7e1ca62011-02-04 13:24:30 -080089#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020090
91#define SIO_REG_LDSEL 0x07 /* Logical device select */
92#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020093#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020094#define SIO_REG_ENABLE 0x30 /* Logical device enable */
95#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020096#define SIO_REG_VID_CTRL 0xF0 /* VID control */
97#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020098
David Hubbard657c93b2007-02-14 21:15:04 +010099#define SIO_W83627EHF_ID 0x8850
100#define SIO_W83627EHG_ID 0x8860
101#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +0200102#define SIO_W83627DHG_P_ID 0xb070
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800103#define SIO_W83667HG_ID 0xa510
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200104#define SIO_W83667HG_B_ID 0xb350
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800105#define SIO_NCT6775_ID 0xb470
106#define SIO_NCT6776_ID 0xc330
David Hubbard657c93b2007-02-14 21:15:04 +0100107#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +0200108
109static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200110superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +0200111{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200112 outb(reg, ioreg);
113 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200114}
115
116static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200117superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200118{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200119 outb(reg, ioreg);
120 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200121}
122
123static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200124superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200125{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200126 outb(SIO_REG_LDSEL, ioreg);
127 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200128}
129
130static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200131superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200132{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200133 outb(0x87, ioreg);
134 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200135}
136
137static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200138superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200139{
Jonas Jonsson022b75a2010-09-17 17:24:13 +0200140 outb(0xaa, ioreg);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200141 outb(0x02, ioreg);
142 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200143}
144
145/*
146 * ISA constants
147 */
148
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800149#define IOREGION_ALIGNMENT (~7)
Jean Delvare1a641fc2007-04-23 14:41:16 -0700150#define IOREGION_OFFSET 5
151#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200152#define ADDR_REG_OFFSET 0
153#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200154
155#define W83627EHF_REG_BANK 0x4E
156#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100157
158/* Not currently used:
159 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
160 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
161 * REG_MAN_ID is at port 0x4f
162 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200163
164static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
165static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
166
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100167/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
168#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
169 (0x554 + (((nr) - 7) * 2)))
170#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
171 (0x555 + (((nr) - 7) * 2)))
172#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
173 (0x550 + (nr) - 7))
174
Guenter Roeckd36cf322011-02-07 15:08:54 -0800175static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
176static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
177static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
178static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
Jean Delvare08e7e272005-04-25 22:43:25 +0200179
180/* Fan clock dividers are spread over the following five registers */
181#define W83627EHF_REG_FANDIV1 0x47
182#define W83627EHF_REG_FANDIV2 0x4B
183#define W83627EHF_REG_VBAT 0x5D
184#define W83627EHF_REG_DIODE 0x59
185#define W83627EHF_REG_SMI_OVT 0x4C
186
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800187/* NCT6775F has its own fan divider registers */
188#define NCT6775_REG_FANDIV1 0x506
189#define NCT6775_REG_FANDIV2 0x507
190
Jean Delvarea4589db2006-03-23 16:30:29 +0100191#define W83627EHF_REG_ALARM1 0x459
192#define W83627EHF_REG_ALARM2 0x45A
193#define W83627EHF_REG_ALARM3 0x45B
194
Rudolf Marek08c79952006-07-05 18:14:31 +0200195/* SmartFan registers */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800196#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
197#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
198
Rudolf Marek08c79952006-07-05 18:14:31 +0200199/* DC or PWM output fan configuration */
200static const u8 W83627EHF_REG_PWM_ENABLE[] = {
201 0x04, /* SYS FAN0 output mode and PWM mode */
202 0x04, /* CPU FAN0 output mode and PWM mode */
203 0x12, /* AUX FAN mode */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800204 0x62, /* CPU FAN1 mode */
Rudolf Marek08c79952006-07-05 18:14:31 +0200205};
206
207static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
208static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
209
210/* FAN Duty Cycle, be used to control */
Guenter Roeck279af1a2011-02-13 22:34:47 -0800211static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
212static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
Rudolf Marek08c79952006-07-05 18:14:31 +0200213static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
214
Rudolf Marek08c79952006-07-05 18:14:31 +0200215/* Advanced Fan control, some values are common for all fans */
Guenter Roeck279af1a2011-02-13 22:34:47 -0800216static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
217static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
218static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200219
Guenter Roeck279af1a2011-02-13 22:34:47 -0800220static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200221 = { 0xff, 0x67, 0xff, 0x69 };
Guenter Roeck279af1a2011-02-13 22:34:47 -0800222static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200223 = { 0xff, 0x68, 0xff, 0x6a };
224
Guenter Roeck279af1a2011-02-13 22:34:47 -0800225static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
226static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
227 = { 0x68, 0x6a, 0x6c };
Rudolf Marek08c79952006-07-05 18:14:31 +0200228
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800229static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
230static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
231static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
232static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
233static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
234static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
235static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
236static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
237static const u16 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
238static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
239
240static const u16 NCT6775_REG_TEMP[]
241 = { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
242static const u16 NCT6775_REG_TEMP_CONFIG[]
243 = { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
244static const u16 NCT6775_REG_TEMP_HYST[]
245 = { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
246static const u16 NCT6775_REG_TEMP_OVER[]
247 = { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
248static const u16 NCT6775_REG_TEMP_SOURCE[]
249 = { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
250
Guenter Roeckd36cf322011-02-07 15:08:54 -0800251static const char *const w83667hg_b_temp_label[] = {
252 "SYSTIN",
253 "CPUTIN",
254 "AUXTIN",
255 "AMDTSI",
256 "PECI Agent 1",
257 "PECI Agent 2",
258 "PECI Agent 3",
259 "PECI Agent 4"
260};
261
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800262static const char *const nct6775_temp_label[] = {
263 "",
264 "SYSTIN",
265 "CPUTIN",
266 "AUXTIN",
267 "AMD SB-TSI",
268 "PECI Agent 0",
269 "PECI Agent 1",
270 "PECI Agent 2",
271 "PECI Agent 3",
272 "PECI Agent 4",
273 "PECI Agent 5",
274 "PECI Agent 6",
275 "PECI Agent 7",
276 "PCH_CHIP_CPU_MAX_TEMP",
277 "PCH_CHIP_TEMP",
278 "PCH_CPU_TEMP",
279 "PCH_MCH_TEMP",
280 "PCH_DIM0_TEMP",
281 "PCH_DIM1_TEMP",
282 "PCH_DIM2_TEMP",
283 "PCH_DIM3_TEMP"
284};
285
286static const char *const nct6776_temp_label[] = {
287 "",
288 "SYSTIN",
289 "CPUTIN",
290 "AUXTIN",
291 "SMBUSMASTER 0",
292 "SMBUSMASTER 1",
293 "SMBUSMASTER 2",
294 "SMBUSMASTER 3",
295 "SMBUSMASTER 4",
296 "SMBUSMASTER 5",
297 "SMBUSMASTER 6",
298 "SMBUSMASTER 7",
299 "PECI Agent 0",
300 "PECI Agent 1",
301 "PCH_CHIP_CPU_MAX_TEMP",
302 "PCH_CHIP_TEMP",
303 "PCH_CPU_TEMP",
304 "PCH_MCH_TEMP",
305 "PCH_DIM0_TEMP",
306 "PCH_DIM1_TEMP",
307 "PCH_DIM2_TEMP",
308 "PCH_DIM3_TEMP",
309 "BYTE_TEMP"
310};
311
312#define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP)
Guenter Roeckd36cf322011-02-07 15:08:54 -0800313
Guenter Roeckbce26c52011-02-04 12:54:14 -0800314static inline int is_word_sized(u16 reg)
315{
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800316 return ((((reg & 0xff00) == 0x100
Guenter Roeckbce26c52011-02-04 12:54:14 -0800317 || (reg & 0xff00) == 0x200)
318 && ((reg & 0x00ff) == 0x50
319 || (reg & 0x00ff) == 0x53
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800320 || (reg & 0x00ff) == 0x55))
321 || (reg & 0xfff0) == 0x630
322 || reg == 0x640 || reg == 0x642
323 || ((reg & 0xfff0) == 0x650
324 && (reg & 0x000f) >= 0x06)
325 || reg == 0x73 || reg == 0x75 || reg == 0x77
326 );
Guenter Roeckbce26c52011-02-04 12:54:14 -0800327}
328
Jean Delvare08e7e272005-04-25 22:43:25 +0200329/*
330 * Conversions
331 */
332
Rudolf Marek08c79952006-07-05 18:14:31 +0200333/* 1 is PWM mode, output in ms */
334static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
335{
336 return mode ? 100 * reg : 400 * reg;
337}
338
339static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
340{
341 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
342 (msec + 200) / 400), 1, 255);
343}
344
Jean Delvare08e7e272005-04-25 22:43:25 +0200345static inline unsigned int
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800346fan_from_reg(int reg, u16 val, unsigned int div)
Jean Delvare08e7e272005-04-25 22:43:25 +0200347{
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800348 if (val == 0)
Jean Delvare08e7e272005-04-25 22:43:25 +0200349 return 0;
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800350 if (is_word_sized(reg)) {
351 if ((val & 0xff1f) == 0xff1f)
352 return 0;
353 val = (val & 0x1f) | ((val & 0xff00) >> 3);
354 } else {
355 if (val == 255 || div == 0)
356 return 0;
357 val *= div;
358 }
359 return 1350000U / val;
Jean Delvare08e7e272005-04-25 22:43:25 +0200360}
361
362static inline unsigned int
363div_from_reg(u8 reg)
364{
365 return 1 << reg;
366}
367
368static inline int
Guenter Roeckbce26c52011-02-04 12:54:14 -0800369temp_from_reg(u16 reg, s16 regval)
Jean Delvare08e7e272005-04-25 22:43:25 +0200370{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800371 if (is_word_sized(reg))
372 return LM75_TEMP_FROM_REG(regval);
373 return regval * 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200374}
375
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800376static inline u16
Guenter Roeckbce26c52011-02-04 12:54:14 -0800377temp_to_reg(u16 reg, long temp)
Jean Delvare08e7e272005-04-25 22:43:25 +0200378{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800379 if (is_word_sized(reg))
380 return LM75_TEMP_TO_REG(temp);
381 return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
Jean Delvare08e7e272005-04-25 22:43:25 +0200382}
383
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100384/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
385
386static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
387
388static inline long in_from_reg(u8 reg, u8 nr)
389{
390 return reg * scale_in[nr];
391}
392
393static inline u8 in_to_reg(u32 val, u8 nr)
394{
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800395 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
396 255);
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100397}
398
Jean Delvare08e7e272005-04-25 22:43:25 +0200399/*
400 * Data structures and manipulation thereof
401 */
402
403struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200404 int addr; /* IO base of hw monitor block */
405 const char *name;
406
Tony Jones1beeffe2007-08-20 13:46:20 -0700407 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100408 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200409
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800410 u16 reg_temp[NUM_REG_TEMP];
411 u16 reg_temp_over[NUM_REG_TEMP];
412 u16 reg_temp_hyst[NUM_REG_TEMP];
413 u16 reg_temp_config[NUM_REG_TEMP];
Guenter Roeckd36cf322011-02-07 15:08:54 -0800414 u8 temp_src[NUM_REG_TEMP];
415 const char * const *temp_label;
416
Guenter Roeck279af1a2011-02-13 22:34:47 -0800417 const u16 *REG_PWM;
418 const u16 *REG_TARGET;
419 const u16 *REG_FAN;
420 const u16 *REG_FAN_MIN;
421 const u16 *REG_FAN_START_OUTPUT;
422 const u16 *REG_FAN_STOP_OUTPUT;
423 const u16 *REG_FAN_STOP_TIME;
424 const u16 *REG_FAN_MAX_OUTPUT;
425 const u16 *REG_FAN_STEP_OUTPUT;
Guenter Roeckda2e0252010-08-14 21:08:55 +0200426
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100427 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200428 char valid; /* !=0 if following fields are valid */
429 unsigned long last_updated; /* In jiffies */
430
431 /* Register values */
Guenter Roeck83cc8982011-02-06 08:10:15 -0800432 u8 bank; /* current register bank */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200433 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100434 u8 in[10]; /* Register value */
435 u8 in_max[10]; /* Register value */
436 u8 in_min[10]; /* Register value */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800437 u16 fan[5];
438 u16 fan_min[5];
Jean Delvare08e7e272005-04-25 22:43:25 +0200439 u8 fan_div[5];
440 u8 has_fan; /* some fan inputs can be disabled */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800441 u8 has_fan_min; /* some fans don't have min register */
Jean Delvareda667362007-06-24 11:21:02 +0200442 u8 temp_type[3];
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800443 s16 temp[9];
444 s16 temp_max[9];
445 s16 temp_max_hyst[9];
Jean Delvarea4589db2006-03-23 16:30:29 +0100446 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200447
448 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
449 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800450 2->thermal cruise mode (also called SmartFan I)
451 3->fan speed cruise mode
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800452 4->variable thermal cruise (also called
Guenter Roeckb84bb512011-02-13 23:01:25 -0800453 SmartFan III)
454 5->enhanced variable thermal cruise (also called
455 SmartFan IV) */
456 u8 pwm_enable_orig[4]; /* original value of pwm_enable */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200457 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200458 u8 pwm[4];
459 u8 target_temp[4];
460 u8 tolerance[4];
461
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800462 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
463 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
464 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
465 u8 fan_max_output[4]; /* maximum fan speed */
466 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200467
468 u8 vid;
469 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200470
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800471 u16 have_temp;
Gong Juna157d062009-03-30 21:46:43 +0200472 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200473};
474
David Hubbard1ea6dd32007-06-24 11:16:15 +0200475struct w83627ehf_sio_data {
476 int sioreg;
477 enum kinds kind;
478};
479
Guenter Roeck83cc8982011-02-06 08:10:15 -0800480/*
481 * On older chips, only registers 0x50-0x5f are banked.
482 * On more recent chips, all registers are banked.
483 * Assume that is the case and set the bank number for each access.
484 * Cache the bank number so it only needs to be set if it changes.
485 */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200486static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200487{
Guenter Roeck83cc8982011-02-06 08:10:15 -0800488 u8 bank = reg >> 8;
489 if (data->bank != bank) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200490 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
Guenter Roeck83cc8982011-02-06 08:10:15 -0800491 outb_p(bank, data->addr + DATA_REG_OFFSET);
492 data->bank = bank;
Jean Delvare08e7e272005-04-25 22:43:25 +0200493 }
494}
495
David Hubbard1ea6dd32007-06-24 11:16:15 +0200496static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200497{
Jean Delvare08e7e272005-04-25 22:43:25 +0200498 int res, word_sized = is_word_sized(reg);
499
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100500 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200501
David Hubbard1ea6dd32007-06-24 11:16:15 +0200502 w83627ehf_set_bank(data, reg);
503 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
504 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200505 if (word_sized) {
506 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200507 data->addr + ADDR_REG_OFFSET);
508 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200509 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200510
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100511 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200512 return res;
513}
514
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800515static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
516 u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200517{
Jean Delvare08e7e272005-04-25 22:43:25 +0200518 int word_sized = is_word_sized(reg);
519
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100520 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200521
David Hubbard1ea6dd32007-06-24 11:16:15 +0200522 w83627ehf_set_bank(data, reg);
523 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200524 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200525 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200526 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200527 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200528 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200529 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200530
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100531 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200532 return 0;
533}
534
535/* This function assumes that the caller holds data->update_lock */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800536static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
537{
538 u8 reg;
539
540 switch (nr) {
541 case 0:
542 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
543 | (data->fan_div[0] & 0x7);
544 w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
545 break;
546 case 1:
547 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
548 | ((data->fan_div[1] << 4) & 0x70);
549 w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
550 case 2:
551 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
552 | (data->fan_div[2] & 0x7);
553 w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
554 break;
555 case 3:
556 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
557 | ((data->fan_div[3] << 4) & 0x70);
558 w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
559 break;
560 }
561}
562
563/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200564static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200565{
Jean Delvare08e7e272005-04-25 22:43:25 +0200566 u8 reg;
567
568 switch (nr) {
569 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200570 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200571 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200572 /* fan5 input control bit is write only, compute the value */
573 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200574 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
575 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200576 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200577 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200578 break;
579 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200580 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200581 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200582 /* fan5 input control bit is write only, compute the value */
583 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200584 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
585 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200586 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200587 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200588 break;
589 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200590 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200591 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200592 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
593 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200594 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200595 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200596 break;
597 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200598 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200599 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200600 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
601 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200602 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200603 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200604 break;
605 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200606 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700607 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200608 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200609 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200610 break;
611 }
612}
613
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800614static void w83627ehf_write_fan_div_common(struct device *dev,
615 struct w83627ehf_data *data, int nr)
616{
617 struct w83627ehf_sio_data *sio_data = dev->platform_data;
618
619 if (sio_data->kind == nct6776)
620 ; /* no dividers, do nothing */
621 else if (sio_data->kind == nct6775)
622 nct6775_write_fan_div(data, nr);
623 else
624 w83627ehf_write_fan_div(data, nr);
625}
626
627static void nct6775_update_fan_div(struct w83627ehf_data *data)
628{
629 u8 i;
630
631 i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
632 data->fan_div[0] = i & 0x7;
633 data->fan_div[1] = (i & 0x70) >> 4;
634 i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
635 data->fan_div[2] = i & 0x7;
636 if (data->has_fan & (1<<3))
637 data->fan_div[3] = (i & 0x70) >> 4;
638}
639
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400640static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
641{
642 int i;
643
644 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
645 data->fan_div[0] = (i >> 4) & 0x03;
646 data->fan_div[1] = (i >> 6) & 0x03;
647 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
648 data->fan_div[2] = (i >> 6) & 0x03;
649 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
650 data->fan_div[0] |= (i >> 3) & 0x04;
651 data->fan_div[1] |= (i >> 4) & 0x04;
652 data->fan_div[2] |= (i >> 5) & 0x04;
653 if (data->has_fan & ((1 << 3) | (1 << 4))) {
654 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
655 data->fan_div[3] = i & 0x03;
656 data->fan_div[4] = ((i >> 2) & 0x03)
657 | ((i >> 5) & 0x04);
658 }
659 if (data->has_fan & (1 << 3)) {
660 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
661 data->fan_div[3] |= (i >> 5) & 0x04;
662 }
663}
664
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800665static void w83627ehf_update_fan_div_common(struct device *dev,
666 struct w83627ehf_data *data)
667{
668 struct w83627ehf_sio_data *sio_data = dev->platform_data;
669
670 if (sio_data->kind == nct6776)
671 ; /* no dividers, do nothing */
672 else if (sio_data->kind == nct6775)
673 nct6775_update_fan_div(data);
674 else
675 w83627ehf_update_fan_div(data);
676}
677
678static void nct6775_update_pwm(struct w83627ehf_data *data)
679{
680 int i;
681 int pwmcfg, fanmodecfg;
682
683 for (i = 0; i < data->pwm_num; i++) {
684 pwmcfg = w83627ehf_read_value(data,
685 W83627EHF_REG_PWM_ENABLE[i]);
686 fanmodecfg = w83627ehf_read_value(data,
687 NCT6775_REG_FAN_MODE[i]);
688 data->pwm_mode[i] =
689 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
690 data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
691 data->tolerance[i] = fanmodecfg & 0x0f;
692 data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
693 }
694}
695
696static void w83627ehf_update_pwm(struct w83627ehf_data *data)
697{
698 int i;
699 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
700
701 for (i = 0; i < data->pwm_num; i++) {
702 if (!(data->has_fan & (1 << i)))
703 continue;
704
705 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
706 if (i != 1) {
707 pwmcfg = w83627ehf_read_value(data,
708 W83627EHF_REG_PWM_ENABLE[i]);
709 tolerance = w83627ehf_read_value(data,
710 W83627EHF_REG_TOLERANCE[i]);
711 }
712 data->pwm_mode[i] =
713 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
714 data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
715 & 3) + 1;
716 data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
717
718 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
719 }
720}
721
722static void w83627ehf_update_pwm_common(struct device *dev,
723 struct w83627ehf_data *data)
724{
725 struct w83627ehf_sio_data *sio_data = dev->platform_data;
726
727 if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
728 nct6775_update_pwm(data);
729 else
730 w83627ehf_update_pwm(data);
731}
732
Jean Delvare08e7e272005-04-25 22:43:25 +0200733static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
734{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200735 struct w83627ehf_data *data = dev_get_drvdata(dev);
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800736 struct w83627ehf_sio_data *sio_data = dev->platform_data;
737
Jean Delvare08e7e272005-04-25 22:43:25 +0200738 int i;
739
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100740 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200741
Jean Delvare6b3e4642007-06-24 11:19:01 +0200742 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200743 || !data->valid) {
744 /* Fan clock dividers */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800745 w83627ehf_update_fan_div_common(dev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200746
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100747 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200748 for (i = 0; i < data->in_num; i++) {
749 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100750 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200751 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100752 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200753 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100754 W83627EHF_REG_IN_MAX(i));
755 }
756
Jean Delvare08e7e272005-04-25 22:43:25 +0200757 /* Measured fan speeds and limits */
758 for (i = 0; i < 5; i++) {
759 if (!(data->has_fan & (1 << i)))
760 continue;
761
David Hubbard1ea6dd32007-06-24 11:16:15 +0200762 data->fan[i] = w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800763 data->REG_FAN[i]);
764
765 if (data->has_fan_min & (1 << i))
766 data->fan_min[i] = w83627ehf_read_value(data,
Guenter Roeck279af1a2011-02-13 22:34:47 -0800767 data->REG_FAN_MIN[i]);
Jean Delvare08e7e272005-04-25 22:43:25 +0200768
769 /* If we failed to measure the fan speed and clock
770 divider can be increased, let's try that for next
771 time */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800772 if (!is_word_sized(data->REG_FAN[i])
773 && (data->fan[i] == 0xff
774 || (sio_data->kind == nct6775
775 && data->fan[i] == 0x00))
776 && data->fan_div[i] < 0x07) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800777 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200778 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700779 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200780 div_from_reg(data->fan_div[i] + 1));
781 data->fan_div[i]++;
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800782 w83627ehf_write_fan_div_common(dev, data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200783 /* Preserve min limit if possible */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800784 if ((data->has_fan_min & (1 << i))
785 && data->fan_min[i] >= 2
Jean Delvare08e7e272005-04-25 22:43:25 +0200786 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200787 w83627ehf_write_value(data,
Guenter Roeck279af1a2011-02-13 22:34:47 -0800788 data->REG_FAN_MIN[i],
Jean Delvare08e7e272005-04-25 22:43:25 +0200789 (data->fan_min[i] /= 2));
790 }
791 }
792
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800793 w83627ehf_update_pwm_common(dev, data);
794
Guenter Roeckda2e0252010-08-14 21:08:55 +0200795 for (i = 0; i < data->pwm_num; i++) {
796 if (!(data->has_fan & (1 << i)))
797 continue;
798
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800799 data->fan_start_output[i] =
800 w83627ehf_read_value(data,
801 data->REG_FAN_START_OUTPUT[i]);
802 data->fan_stop_output[i] =
803 w83627ehf_read_value(data,
804 data->REG_FAN_STOP_OUTPUT[i]);
805 data->fan_stop_time[i] =
806 w83627ehf_read_value(data,
807 data->REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200808
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800809 if (data->REG_FAN_MAX_OUTPUT &&
810 data->REG_FAN_MAX_OUTPUT[i] != 0xff)
Guenter Roeckda2e0252010-08-14 21:08:55 +0200811 data->fan_max_output[i] =
812 w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800813 data->REG_FAN_MAX_OUTPUT[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200814
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800815 if (data->REG_FAN_STEP_OUTPUT &&
816 data->REG_FAN_STEP_OUTPUT[i] != 0xff)
Guenter Roeckda2e0252010-08-14 21:08:55 +0200817 data->fan_step_output[i] =
818 w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800819 data->REG_FAN_STEP_OUTPUT[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200820
Rudolf Marek08c79952006-07-05 18:14:31 +0200821 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200822 w83627ehf_read_value(data,
Guenter Roeck279af1a2011-02-13 22:34:47 -0800823 data->REG_TARGET[i]) &
Rudolf Marek08c79952006-07-05 18:14:31 +0200824 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
Rudolf Marek08c79952006-07-05 18:14:31 +0200825 }
826
Jean Delvare08e7e272005-04-25 22:43:25 +0200827 /* Measured temperatures and limits */
Guenter Roeckd36cf322011-02-07 15:08:54 -0800828 for (i = 0; i < NUM_REG_TEMP; i++) {
829 if (!(data->have_temp & (1 << i)))
830 continue;
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800831 data->temp[i] = w83627ehf_read_value(data,
832 data->reg_temp[i]);
833 if (data->reg_temp_over[i])
834 data->temp_max[i]
835 = w83627ehf_read_value(data,
836 data->reg_temp_over[i]);
837 if (data->reg_temp_hyst[i])
838 data->temp_max_hyst[i]
839 = w83627ehf_read_value(data,
840 data->reg_temp_hyst[i]);
Jean Delvare08e7e272005-04-25 22:43:25 +0200841 }
842
David Hubbard1ea6dd32007-06-24 11:16:15 +0200843 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100844 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200845 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100846 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200847 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100848 W83627EHF_REG_ALARM3) << 16);
849
Jean Delvare08e7e272005-04-25 22:43:25 +0200850 data->last_updated = jiffies;
851 data->valid = 1;
852 }
853
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100854 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200855 return data;
856}
857
858/*
859 * Sysfs callback functions
860 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100861#define show_in_reg(reg) \
862static ssize_t \
863show_##reg(struct device *dev, struct device_attribute *attr, \
864 char *buf) \
865{ \
866 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800867 struct sensor_device_attribute *sensor_attr = \
868 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100869 int nr = sensor_attr->index; \
870 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
871}
872show_in_reg(in)
873show_in_reg(in_min)
874show_in_reg(in_max)
875
876#define store_in_reg(REG, reg) \
877static ssize_t \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800878store_in_##reg(struct device *dev, struct device_attribute *attr, \
879 const char *buf, size_t count) \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100880{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200881 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800882 struct sensor_device_attribute *sensor_attr = \
883 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100884 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800885 unsigned long val; \
886 int err; \
887 err = strict_strtoul(buf, 10, &val); \
888 if (err < 0) \
889 return err; \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100890 mutex_lock(&data->update_lock); \
891 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200892 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100893 data->in_##reg[nr]); \
894 mutex_unlock(&data->update_lock); \
895 return count; \
896}
897
898store_in_reg(MIN, min)
899store_in_reg(MAX, max)
900
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800901static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
902 char *buf)
Jean Delvarea4589db2006-03-23 16:30:29 +0100903{
904 struct w83627ehf_data *data = w83627ehf_update_device(dev);
905 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
906 int nr = sensor_attr->index;
907 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
908}
909
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100910static struct sensor_device_attribute sda_in_input[] = {
911 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
912 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
913 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
914 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
915 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
916 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
917 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
918 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
919 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
920 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
921};
922
Jean Delvarea4589db2006-03-23 16:30:29 +0100923static struct sensor_device_attribute sda_in_alarm[] = {
924 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
925 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
926 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
927 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
928 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
929 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
930 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
931 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
932 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
933 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
934};
935
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100936static struct sensor_device_attribute sda_in_min[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800937 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
938 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
939 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
940 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
941 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
942 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
943 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
944 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
945 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
946 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100947};
948
949static struct sensor_device_attribute sda_in_max[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800950 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
951 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
952 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
953 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
954 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
955 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
956 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
957 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
958 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
959 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100960};
961
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800962static ssize_t
963show_fan(struct device *dev, struct device_attribute *attr, char *buf)
964{
965 struct w83627ehf_data *data = w83627ehf_update_device(dev);
966 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
967 int nr = sensor_attr->index;
968 return sprintf(buf, "%d\n",
969 fan_from_reg(data->REG_FAN[nr],
970 data->fan[nr],
971 div_from_reg(data->fan_div[nr])));
Jean Delvare08e7e272005-04-25 22:43:25 +0200972}
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800973
974static ssize_t
975show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
976{
977 struct w83627ehf_data *data = w83627ehf_update_device(dev);
978 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
979 int nr = sensor_attr->index;
980 return sprintf(buf, "%d\n",
981 fan_from_reg(data->REG_FAN_MIN[nr],
982 data->fan_min[nr],
983 div_from_reg(data->fan_div[nr])));
984}
Jean Delvare08e7e272005-04-25 22:43:25 +0200985
986static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100987show_fan_div(struct device *dev, struct device_attribute *attr,
988 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200989{
990 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100991 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
992 int nr = sensor_attr->index;
993 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200994}
995
996static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100997store_fan_min(struct device *dev, struct device_attribute *attr,
998 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200999{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001000 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +01001001 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1002 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001003 unsigned long val;
1004 int err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001005 unsigned int reg;
1006 u8 new_div;
1007
Guenter Roeckbce26c52011-02-04 12:54:14 -08001008 err = strict_strtoul(buf, 10, &val);
1009 if (err < 0)
1010 return err;
1011
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001012 mutex_lock(&data->update_lock);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001013 if (is_word_sized(data->REG_FAN_MIN[nr])) {
1014 if (!val) {
1015 val = 0xff1f;
1016 } else {
1017 if (val > 1350000U)
1018 val = 135000U;
1019 val = 1350000U / val;
1020 val = (val & 0x1f) | ((val << 3) & 0xff00);
1021 }
1022 data->fan_min[nr] = val;
1023 goto done; /* Leave fan divider alone */
1024 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001025 if (!val) {
1026 /* No min limit, alarm disabled */
1027 data->fan_min[nr] = 255;
1028 new_div = data->fan_div[nr]; /* No change */
1029 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1030 } else if ((reg = 1350000U / val) >= 128 * 255) {
1031 /* Speed below this value cannot possibly be represented,
1032 even with the highest divider (128) */
1033 data->fan_min[nr] = 254;
1034 new_div = 7; /* 128 == (1 << 7) */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001035 dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001036 "minimum\n", nr + 1, val,
1037 fan_from_reg(data->REG_FAN_MIN[nr], 254, 128));
Jean Delvare08e7e272005-04-25 22:43:25 +02001038 } else if (!reg) {
1039 /* Speed above this value cannot possibly be represented,
1040 even with the lowest divider (1) */
1041 data->fan_min[nr] = 1;
1042 new_div = 0; /* 1 == (1 << 0) */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001043 dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001044 "maximum\n", nr + 1, val,
1045 fan_from_reg(data->REG_FAN_MIN[nr], 1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +02001046 } else {
1047 /* Automatically pick the best divider, i.e. the one such
1048 that the min limit will correspond to a register value
1049 in the 96..192 range */
1050 new_div = 0;
1051 while (reg > 192 && new_div < 7) {
1052 reg >>= 1;
1053 new_div++;
1054 }
1055 data->fan_min[nr] = reg;
1056 }
1057
1058 /* Write both the fan clock divider (if it changed) and the new
1059 fan min (unconditionally) */
1060 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +02001061 /* Preserve the fan speed reading */
1062 if (data->fan[nr] != 0xff) {
1063 if (new_div > data->fan_div[nr])
1064 data->fan[nr] >>= new_div - data->fan_div[nr];
1065 else if (data->fan[nr] & 0x80)
1066 data->fan[nr] = 0xff;
1067 else
1068 data->fan[nr] <<= data->fan_div[nr] - new_div;
1069 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001070
1071 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1072 nr + 1, div_from_reg(data->fan_div[nr]),
1073 div_from_reg(new_div));
1074 data->fan_div[nr] = new_div;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001075 w83627ehf_write_fan_div_common(dev, data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +02001076 /* Give the chip time to sample a new speed value */
1077 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +02001078 }
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001079done:
Guenter Roeck279af1a2011-02-13 22:34:47 -08001080 w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +02001081 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001082 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +02001083
1084 return count;
1085}
1086
Yuan Mu412fec82006-02-05 23:24:16 +01001087static struct sensor_device_attribute sda_fan_input[] = {
1088 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
1089 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
1090 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
1091 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
1092 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
1093};
Jean Delvare08e7e272005-04-25 22:43:25 +02001094
Jean Delvarea4589db2006-03-23 16:30:29 +01001095static struct sensor_device_attribute sda_fan_alarm[] = {
1096 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
1097 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
1098 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
1099 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
1100 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
1101};
1102
Yuan Mu412fec82006-02-05 23:24:16 +01001103static struct sensor_device_attribute sda_fan_min[] = {
1104 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
1105 store_fan_min, 0),
1106 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
1107 store_fan_min, 1),
1108 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
1109 store_fan_min, 2),
1110 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
1111 store_fan_min, 3),
1112 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
1113 store_fan_min, 4),
1114};
Jean Delvare08e7e272005-04-25 22:43:25 +02001115
Yuan Mu412fec82006-02-05 23:24:16 +01001116static struct sensor_device_attribute sda_fan_div[] = {
1117 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
1118 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
1119 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
1120 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
1121 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
1122};
Jean Delvare08e7e272005-04-25 22:43:25 +02001123
Guenter Roeckd36cf322011-02-07 15:08:54 -08001124static ssize_t
1125show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1126{
1127 struct w83627ehf_data *data = w83627ehf_update_device(dev);
1128 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1129 int nr = sensor_attr->index;
1130 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1131}
1132
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001133#define show_temp_reg(addr, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001134static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +01001135show_##reg(struct device *dev, struct device_attribute *attr, \
1136 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001137{ \
1138 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001139 struct sensor_device_attribute *sensor_attr = \
1140 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +01001141 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +02001142 return sprintf(buf, "%d\n", \
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001143 temp_from_reg(data->addr[nr], data->reg[nr])); \
Jean Delvare08e7e272005-04-25 22:43:25 +02001144}
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001145show_temp_reg(reg_temp, temp);
1146show_temp_reg(reg_temp_over, temp_max);
1147show_temp_reg(reg_temp_hyst, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +02001148
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001149#define store_temp_reg(addr, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001150static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +01001151store_##reg(struct device *dev, struct device_attribute *attr, \
1152 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001153{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001154 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001155 struct sensor_device_attribute *sensor_attr = \
1156 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +01001157 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001158 int err; \
1159 long val; \
1160 err = strict_strtol(buf, 10, &val); \
1161 if (err < 0) \
1162 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001163 mutex_lock(&data->update_lock); \
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001164 data->reg[nr] = temp_to_reg(data->addr[nr], val); \
1165 w83627ehf_write_value(data, data->addr[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +02001166 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001167 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +02001168 return count; \
1169}
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001170store_temp_reg(reg_temp_over, temp_max);
1171store_temp_reg(reg_temp_hyst, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +02001172
Jean Delvareda667362007-06-24 11:21:02 +02001173static ssize_t
1174show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
1175{
1176 struct w83627ehf_data *data = w83627ehf_update_device(dev);
1177 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1178 int nr = sensor_attr->index;
1179 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
1180}
1181
Gong Juna157d062009-03-30 21:46:43 +02001182static struct sensor_device_attribute sda_temp_input[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -08001183 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
1184 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
1185 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
Guenter Roeckd36cf322011-02-07 15:08:54 -08001186 SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001187 SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
1188 SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
1189 SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
1190 SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
1191 SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
Guenter Roeckd36cf322011-02-07 15:08:54 -08001192};
1193
1194static struct sensor_device_attribute sda_temp_label[] = {
1195 SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
1196 SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
1197 SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
1198 SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001199 SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
1200 SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
1201 SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
1202 SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
1203 SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
Gong Juna157d062009-03-30 21:46:43 +02001204};
1205
1206static struct sensor_device_attribute sda_temp_max[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -08001207 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +01001208 store_temp_max, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001209 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +01001210 store_temp_max, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001211 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
1212 store_temp_max, 2),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001213 SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
1214 store_temp_max, 3),
1215 SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
1216 store_temp_max, 4),
1217 SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
1218 store_temp_max, 5),
1219 SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
1220 store_temp_max, 6),
1221 SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
1222 store_temp_max, 7),
1223 SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
1224 store_temp_max, 8),
Gong Juna157d062009-03-30 21:46:43 +02001225};
1226
1227static struct sensor_device_attribute sda_temp_max_hyst[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -08001228 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +01001229 store_temp_max_hyst, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001230 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +01001231 store_temp_max_hyst, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001232 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1233 store_temp_max_hyst, 2),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001234 SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1235 store_temp_max_hyst, 3),
1236 SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1237 store_temp_max_hyst, 4),
1238 SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1239 store_temp_max_hyst, 5),
1240 SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1241 store_temp_max_hyst, 6),
1242 SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1243 store_temp_max_hyst, 7),
1244 SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1245 store_temp_max_hyst, 8),
Gong Juna157d062009-03-30 21:46:43 +02001246};
1247
1248static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +01001249 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
1250 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
1251 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +02001252};
1253
1254static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +02001255 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
1256 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
1257 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +01001258};
Jean Delvare08e7e272005-04-25 22:43:25 +02001259
Rudolf Marek08c79952006-07-05 18:14:31 +02001260#define show_pwm_reg(reg) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001261static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1262 char *buf) \
Rudolf Marek08c79952006-07-05 18:14:31 +02001263{ \
1264 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001265 struct sensor_device_attribute *sensor_attr = \
1266 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001267 int nr = sensor_attr->index; \
1268 return sprintf(buf, "%d\n", data->reg[nr]); \
1269}
1270
1271show_pwm_reg(pwm_mode)
1272show_pwm_reg(pwm_enable)
1273show_pwm_reg(pwm)
1274
1275static ssize_t
1276store_pwm_mode(struct device *dev, struct device_attribute *attr,
1277 const char *buf, size_t count)
1278{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001279 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001280 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1281 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001282 unsigned long val;
1283 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001284 u16 reg;
1285
Guenter Roeckbce26c52011-02-04 12:54:14 -08001286 err = strict_strtoul(buf, 10, &val);
1287 if (err < 0)
1288 return err;
1289
Rudolf Marek08c79952006-07-05 18:14:31 +02001290 if (val > 1)
1291 return -EINVAL;
1292 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001293 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001294 data->pwm_mode[nr] = val;
1295 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
1296 if (!val)
1297 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001298 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001299 mutex_unlock(&data->update_lock);
1300 return count;
1301}
1302
1303static ssize_t
1304store_pwm(struct device *dev, struct device_attribute *attr,
1305 const char *buf, size_t count)
1306{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001307 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001308 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1309 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001310 unsigned long val;
1311 int err;
1312
1313 err = strict_strtoul(buf, 10, &val);
1314 if (err < 0)
1315 return err;
1316
1317 val = SENSORS_LIMIT(val, 0, 255);
Rudolf Marek08c79952006-07-05 18:14:31 +02001318
1319 mutex_lock(&data->update_lock);
1320 data->pwm[nr] = val;
Guenter Roeck279af1a2011-02-13 22:34:47 -08001321 w83627ehf_write_value(data, data->REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001322 mutex_unlock(&data->update_lock);
1323 return count;
1324}
1325
1326static ssize_t
1327store_pwm_enable(struct device *dev, struct device_attribute *attr,
1328 const char *buf, size_t count)
1329{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001330 struct w83627ehf_data *data = dev_get_drvdata(dev);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001331 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Rudolf Marek08c79952006-07-05 18:14:31 +02001332 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1333 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001334 unsigned long val;
1335 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001336 u16 reg;
1337
Guenter Roeckbce26c52011-02-04 12:54:14 -08001338 err = strict_strtoul(buf, 10, &val);
1339 if (err < 0)
1340 return err;
1341
Guenter Roeckb84bb512011-02-13 23:01:25 -08001342 if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
Rudolf Marek08c79952006-07-05 18:14:31 +02001343 return -EINVAL;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001344 /* SmartFan III mode is not supported on NCT6776F */
1345 if (sio_data->kind == nct6776 && val == 4)
1346 return -EINVAL;
1347
Rudolf Marek08c79952006-07-05 18:14:31 +02001348 mutex_lock(&data->update_lock);
Rudolf Marek08c79952006-07-05 18:14:31 +02001349 data->pwm_enable[nr] = val;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001350 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1351 reg = w83627ehf_read_value(data,
1352 NCT6775_REG_FAN_MODE[nr]);
1353 reg &= 0x0f;
1354 reg |= (val - 1) << 4;
1355 w83627ehf_write_value(data,
1356 NCT6775_REG_FAN_MODE[nr], reg);
1357 } else {
1358 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
1359 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1360 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
1361 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
1362 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001363 mutex_unlock(&data->update_lock);
1364 return count;
1365}
1366
1367
1368#define show_tol_temp(reg) \
1369static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1370 char *buf) \
1371{ \
1372 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001373 struct sensor_device_attribute *sensor_attr = \
1374 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001375 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001376 return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001377}
1378
1379show_tol_temp(tolerance)
1380show_tol_temp(target_temp)
1381
1382static ssize_t
1383store_target_temp(struct device *dev, struct device_attribute *attr,
1384 const char *buf, size_t count)
1385{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001386 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001387 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1388 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001389 long val;
1390 int err;
1391
1392 err = strict_strtol(buf, 10, &val);
1393 if (err < 0)
1394 return err;
1395
1396 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
Rudolf Marek08c79952006-07-05 18:14:31 +02001397
1398 mutex_lock(&data->update_lock);
1399 data->target_temp[nr] = val;
Guenter Roeck279af1a2011-02-13 22:34:47 -08001400 w83627ehf_write_value(data, data->REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001401 mutex_unlock(&data->update_lock);
1402 return count;
1403}
1404
1405static ssize_t
1406store_tolerance(struct device *dev, struct device_attribute *attr,
1407 const char *buf, size_t count)
1408{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001409 struct w83627ehf_data *data = dev_get_drvdata(dev);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001410 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Rudolf Marek08c79952006-07-05 18:14:31 +02001411 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1412 int nr = sensor_attr->index;
1413 u16 reg;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001414 long val;
1415 int err;
1416
1417 err = strict_strtol(buf, 10, &val);
1418 if (err < 0)
1419 return err;
1420
Rudolf Marek08c79952006-07-05 18:14:31 +02001421 /* Limit the temp to 0C - 15C */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001422 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
Rudolf Marek08c79952006-07-05 18:14:31 +02001423
1424 mutex_lock(&data->update_lock);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001425 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1426 /* Limit tolerance further for NCT6776F */
1427 if (sio_data->kind == nct6776 && val > 7)
1428 val = 7;
1429 reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001430 reg = (reg & 0xf0) | val;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001431 w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
1432 } else {
1433 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
1434 if (nr == 1)
1435 reg = (reg & 0x0f) | (val << 4);
1436 else
1437 reg = (reg & 0xf0) | val;
1438 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
1439 }
1440 data->tolerance[nr] = val;
Rudolf Marek08c79952006-07-05 18:14:31 +02001441 mutex_unlock(&data->update_lock);
1442 return count;
1443}
1444
1445static struct sensor_device_attribute sda_pwm[] = {
1446 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1447 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1448 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1449 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1450};
1451
1452static struct sensor_device_attribute sda_pwm_mode[] = {
1453 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1454 store_pwm_mode, 0),
1455 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1456 store_pwm_mode, 1),
1457 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1458 store_pwm_mode, 2),
1459 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1460 store_pwm_mode, 3),
1461};
1462
1463static struct sensor_device_attribute sda_pwm_enable[] = {
1464 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1465 store_pwm_enable, 0),
1466 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1467 store_pwm_enable, 1),
1468 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1469 store_pwm_enable, 2),
1470 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1471 store_pwm_enable, 3),
1472};
1473
1474static struct sensor_device_attribute sda_target_temp[] = {
1475 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1476 store_target_temp, 0),
1477 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1478 store_target_temp, 1),
1479 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1480 store_target_temp, 2),
1481 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1482 store_target_temp, 3),
1483};
1484
1485static struct sensor_device_attribute sda_tolerance[] = {
1486 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1487 store_tolerance, 0),
1488 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1489 store_tolerance, 1),
1490 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1491 store_tolerance, 2),
1492 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1493 store_tolerance, 3),
1494};
1495
Rudolf Marek08c79952006-07-05 18:14:31 +02001496/* Smart Fan registers */
1497
1498#define fan_functions(reg, REG) \
1499static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1500 char *buf) \
1501{ \
1502 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001503 struct sensor_device_attribute *sensor_attr = \
1504 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001505 int nr = sensor_attr->index; \
1506 return sprintf(buf, "%d\n", data->reg[nr]); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001507} \
Rudolf Marek08c79952006-07-05 18:14:31 +02001508static ssize_t \
1509store_##reg(struct device *dev, struct device_attribute *attr, \
1510 const char *buf, size_t count) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001511{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001512 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001513 struct sensor_device_attribute *sensor_attr = \
1514 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001515 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001516 unsigned long val; \
1517 int err; \
1518 err = strict_strtoul(buf, 10, &val); \
1519 if (err < 0) \
1520 return err; \
1521 val = SENSORS_LIMIT(val, 1, 255); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001522 mutex_lock(&data->update_lock); \
1523 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001524 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001525 mutex_unlock(&data->update_lock); \
1526 return count; \
1527}
1528
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001529fan_functions(fan_start_output, FAN_START_OUTPUT)
1530fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1531fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1532fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001533
1534#define fan_time_functions(reg, REG) \
1535static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1536 char *buf) \
1537{ \
1538 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001539 struct sensor_device_attribute *sensor_attr = \
1540 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001541 int nr = sensor_attr->index; \
1542 return sprintf(buf, "%d\n", \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001543 step_time_from_reg(data->reg[nr], \
1544 data->pwm_mode[nr])); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001545} \
1546\
1547static ssize_t \
1548store_##reg(struct device *dev, struct device_attribute *attr, \
1549 const char *buf, size_t count) \
1550{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001551 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001552 struct sensor_device_attribute *sensor_attr = \
1553 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001554 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001555 unsigned long val; \
1556 int err; \
1557 err = strict_strtoul(buf, 10, &val); \
1558 if (err < 0) \
1559 return err; \
1560 val = step_time_to_reg(val, data->pwm_mode[nr]); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001561 mutex_lock(&data->update_lock); \
1562 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001563 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001564 mutex_unlock(&data->update_lock); \
1565 return count; \
1566} \
1567
1568fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1569
David Hubbard1ea6dd32007-06-24 11:16:15 +02001570static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1571 char *buf)
1572{
1573 struct w83627ehf_data *data = dev_get_drvdata(dev);
1574
1575 return sprintf(buf, "%s\n", data->name);
1576}
1577static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001578
1579static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1580 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1581 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001582 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1583 store_fan_start_output, 3),
1584 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1585 store_fan_stop_output, 3),
1586 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1587 store_fan_max_output, 3),
1588 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1589 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001590};
1591
1592static struct sensor_device_attribute sda_sf3_arrays[] = {
1593 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1594 store_fan_stop_time, 0),
1595 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1596 store_fan_stop_time, 1),
1597 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1598 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001599 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1600 store_fan_start_output, 0),
1601 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1602 store_fan_start_output, 1),
1603 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1604 store_fan_start_output, 2),
1605 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1606 store_fan_stop_output, 0),
1607 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1608 store_fan_stop_output, 1),
1609 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1610 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001611};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001612
Guenter Roeckda2e0252010-08-14 21:08:55 +02001613
1614/*
1615 * pwm1 and pwm3 don't support max and step settings on all chips.
1616 * Need to check support while generating/removing attribute files.
1617 */
1618static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1619 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1620 store_fan_max_output, 0),
1621 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1622 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001623 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1624 store_fan_max_output, 1),
1625 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1626 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001627 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1628 store_fan_max_output, 2),
1629 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1630 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001631};
1632
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001633static ssize_t
1634show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1635{
1636 struct w83627ehf_data *data = dev_get_drvdata(dev);
1637 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1638}
1639static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1640
Jean Delvare08e7e272005-04-25 22:43:25 +02001641/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001642 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001643 */
1644
David Hubbardc18beb52006-09-24 21:04:38 +02001645static void w83627ehf_device_remove_files(struct device *dev)
1646{
1647 /* some entries in the following arrays may not have been used in
1648 * device_create_file(), but device_remove_file() will ignore them */
1649 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001650 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001651
1652 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1653 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001654 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1655 struct sensor_device_attribute *attr =
1656 &sda_sf3_max_step_arrays[i];
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001657 if (data->REG_FAN_STEP_OUTPUT &&
1658 data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
Guenter Roeckda2e0252010-08-14 21:08:55 +02001659 device_remove_file(dev, &attr->dev_attr);
1660 }
David Hubbardc18beb52006-09-24 21:04:38 +02001661 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1662 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001663 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001664 if ((i == 6) && data->in6_skip)
1665 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001666 device_remove_file(dev, &sda_in_input[i].dev_attr);
1667 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1668 device_remove_file(dev, &sda_in_min[i].dev_attr);
1669 device_remove_file(dev, &sda_in_max[i].dev_attr);
1670 }
1671 for (i = 0; i < 5; i++) {
1672 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1673 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1674 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1675 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1676 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001677 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001678 device_remove_file(dev, &sda_pwm[i].dev_attr);
1679 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1680 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1681 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1682 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1683 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08001684 for (i = 0; i < NUM_REG_TEMP; i++) {
1685 if (!(data->have_temp & (1 << i)))
Gong Juna157d062009-03-30 21:46:43 +02001686 continue;
1687 device_remove_file(dev, &sda_temp_input[i].dev_attr);
Guenter Roeckd36cf322011-02-07 15:08:54 -08001688 device_remove_file(dev, &sda_temp_label[i].dev_attr);
Gong Juna157d062009-03-30 21:46:43 +02001689 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1690 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001691 if (i > 2)
1692 continue;
Gong Juna157d062009-03-30 21:46:43 +02001693 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1694 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1695 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001696
1697 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001698 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001699}
1700
David Hubbard1ea6dd32007-06-24 11:16:15 +02001701/* Get the monitoring functions started */
1702static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001703{
1704 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001705 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001706
1707 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001708 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001709 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001710 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001711 tmp | 0x01);
1712
Guenter Roeckd36cf322011-02-07 15:08:54 -08001713 /* Enable temperature sensors if needed */
1714 for (i = 0; i < NUM_REG_TEMP; i++) {
1715 if (!(data->have_temp & (1 << i)))
1716 continue;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001717 if (!data->reg_temp_config[i])
Guenter Roeckd36cf322011-02-07 15:08:54 -08001718 continue;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001719 tmp = w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001720 data->reg_temp_config[i]);
Jean Delvare08e7e272005-04-25 22:43:25 +02001721 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001722 w83627ehf_write_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001723 data->reg_temp_config[i],
Jean Delvare08e7e272005-04-25 22:43:25 +02001724 tmp & 0xfe);
1725 }
Jean Delvared3130f02007-06-24 11:20:13 +02001726
1727 /* Enable VBAT monitoring if needed */
1728 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1729 if (!(tmp & 0x01))
1730 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001731
1732 /* Get thermal sensor types */
1733 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1734 for (i = 0; i < 3; i++) {
1735 if ((tmp & (0x02 << i)))
1736 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1737 else
1738 data->temp_type[i] = 4; /* thermistor */
1739 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001740}
1741
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001742static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
1743 int r1, int r2)
1744{
1745 u16 tmp;
1746
1747 tmp = data->temp_src[r1];
1748 data->temp_src[r1] = data->temp_src[r2];
1749 data->temp_src[r2] = tmp;
1750
1751 tmp = data->reg_temp[r1];
1752 data->reg_temp[r1] = data->reg_temp[r2];
1753 data->reg_temp[r2] = tmp;
1754
1755 tmp = data->reg_temp_over[r1];
1756 data->reg_temp_over[r1] = data->reg_temp_over[r2];
1757 data->reg_temp_over[r2] = tmp;
1758
1759 tmp = data->reg_temp_hyst[r1];
1760 data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
1761 data->reg_temp_hyst[r2] = tmp;
1762
1763 tmp = data->reg_temp_config[r1];
1764 data->reg_temp_config[r1] = data->reg_temp_config[r2];
1765 data->reg_temp_config[r2] = tmp;
1766}
1767
David Hubbard1ea6dd32007-06-24 11:16:15 +02001768static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001769{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001770 struct device *dev = &pdev->dev;
1771 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001772 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001773 struct resource *res;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001774 u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001775 int i, err = 0;
1776
David Hubbard1ea6dd32007-06-24 11:16:15 +02001777 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1778 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001779 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001780 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1781 (unsigned long)res->start,
1782 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001783 goto exit;
1784 }
1785
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001786 data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
1787 if (!data) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001788 err = -ENOMEM;
1789 goto exit_release;
1790 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001791
David Hubbard1ea6dd32007-06-24 11:16:15 +02001792 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001793 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001794 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001795 data->name = w83627ehf_device_names[sio_data->kind];
1796 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001797
Gong Jun237c8d2f2009-03-30 21:46:42 +02001798 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1799 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001800 /* 667HG, NCT6775F, and NCT6776F have 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001801 data->pwm_num = (sio_data->kind == w83667hg
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001802 || sio_data->kind == w83667hg_b
1803 || sio_data->kind == nct6775
1804 || sio_data->kind == nct6776) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001805
Guenter Roeckd36cf322011-02-07 15:08:54 -08001806 data->have_temp = 0x07;
Gong Juna157d062009-03-30 21:46:43 +02001807 /* Check temp3 configuration bit for 667HG */
Guenter Roeckd36cf322011-02-07 15:08:54 -08001808 if (sio_data->kind == w83667hg) {
1809 u8 reg;
1810
1811 reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1812 if (reg & 0x01)
1813 data->have_temp &= ~(1 << 2);
1814 else
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001815 data->in6_skip = 1; /* either temp3 or in6 */
1816 }
1817
1818 /* Deal with temperature register setup first. */
1819 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1820 int mask = 0;
1821
1822 /*
1823 * Display temperature sensor output only if it monitors
1824 * a source other than one already reported. Always display
1825 * first three temperature registers, though.
1826 */
1827 for (i = 0; i < NUM_REG_TEMP; i++) {
1828 u8 src;
1829
1830 data->reg_temp[i] = NCT6775_REG_TEMP[i];
1831 data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
1832 data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
1833 data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
1834
1835 src = w83627ehf_read_value(data,
1836 NCT6775_REG_TEMP_SOURCE[i]);
1837 src &= 0x1f;
1838 if (src && !(mask & (1 << src))) {
1839 data->have_temp |= 1 << i;
1840 mask |= 1 << src;
1841 }
1842
1843 data->temp_src[i] = src;
1844
1845 /*
1846 * Now do some register swapping if index 0..2 don't
1847 * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
1848 * Idea is to have the first three attributes
1849 * report SYSTIN, CPUIN, and AUXIN if possible
1850 * without overriding the basic system configuration.
1851 */
1852 if (i > 0 && data->temp_src[0] != 1
1853 && data->temp_src[i] == 1)
1854 w82627ehf_swap_tempreg(data, 0, i);
1855 if (i > 1 && data->temp_src[1] != 2
1856 && data->temp_src[i] == 2)
1857 w82627ehf_swap_tempreg(data, 1, i);
1858 if (i > 2 && data->temp_src[2] != 3
1859 && data->temp_src[i] == 3)
1860 w82627ehf_swap_tempreg(data, 2, i);
1861 }
1862 if (sio_data->kind == nct6776) {
1863 /*
1864 * On NCT6776, AUXTIN and VIN3 pins are shared.
1865 * Only way to detect it is to check if AUXTIN is used
1866 * as a temperature source, and if that source is
1867 * enabled.
1868 *
1869 * If that is the case, disable in6, which reports VIN3.
1870 * Otherwise disable temp3.
1871 */
1872 if (data->temp_src[2] == 3) {
1873 u8 reg;
1874
1875 if (data->reg_temp_config[2])
1876 reg = w83627ehf_read_value(data,
1877 data->reg_temp_config[2]);
1878 else
1879 reg = 0; /* Assume AUXTIN is used */
1880
1881 if (reg & 0x01)
1882 data->have_temp &= ~(1 << 2);
1883 else
1884 data->in6_skip = 1;
1885 }
1886 }
1887
1888 data->temp_label = nct6776_temp_label;
Guenter Roeckd36cf322011-02-07 15:08:54 -08001889 } else if (sio_data->kind == w83667hg_b) {
1890 u8 reg;
1891
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001892 /*
1893 * Temperature sources are selected with bank 0, registers 0x49
1894 * and 0x4a.
1895 */
1896 for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
1897 data->reg_temp[i] = W83627EHF_REG_TEMP[i];
1898 data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
1899 data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
1900 data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
1901 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08001902 reg = w83627ehf_read_value(data, 0x4a);
1903 data->temp_src[0] = reg >> 5;
1904 reg = w83627ehf_read_value(data, 0x49);
1905 data->temp_src[1] = reg & 0x07;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001906 data->temp_src[2] = (reg >> 4) & 0x07;
Guenter Roeckd36cf322011-02-07 15:08:54 -08001907
1908 /*
1909 * W83667HG-B has another temperature register at 0x7e.
1910 * The temperature source is selected with register 0x7d.
1911 * Support it if the source differs from already reported
1912 * sources.
1913 */
1914 reg = w83627ehf_read_value(data, 0x7d);
1915 reg &= 0x07;
1916 if (reg != data->temp_src[0] && reg != data->temp_src[1]
1917 && reg != data->temp_src[2]) {
1918 data->temp_src[3] = reg;
1919 data->have_temp |= 1 << 3;
1920 }
1921
1922 /*
1923 * Chip supports either AUXTIN or VIN3. Try to find out which
1924 * one.
1925 */
1926 reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1927 if (data->temp_src[2] == 2 && (reg & 0x01))
1928 data->have_temp &= ~(1 << 2);
1929
1930 if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
1931 || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
1932 data->in6_skip = 1;
1933
1934 data->temp_label = w83667hg_b_temp_label;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001935 } else {
1936 /* Temperature sources are fixed */
1937 for (i = 0; i < 3; i++) {
1938 data->reg_temp[i] = W83627EHF_REG_TEMP[i];
1939 data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
1940 data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
1941 data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
1942 }
Gong Juna157d062009-03-30 21:46:43 +02001943 }
1944
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001945 if (sio_data->kind == nct6775) {
1946 data->REG_PWM = NCT6775_REG_PWM;
1947 data->REG_TARGET = NCT6775_REG_TARGET;
1948 data->REG_FAN = W83627EHF_REG_FAN;
1949 data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
1950 data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
1951 data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
1952 data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
1953 data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
1954 data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
1955 } else if (sio_data->kind == nct6776) {
1956 data->REG_PWM = NCT6775_REG_PWM;
1957 data->REG_TARGET = NCT6775_REG_TARGET;
1958 data->REG_FAN = NCT6776_REG_FAN;
1959 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
1960 data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
1961 data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
1962 data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
1963 } else if (sio_data->kind == w83667hg_b) {
1964 data->REG_PWM = W83627EHF_REG_PWM;
1965 data->REG_TARGET = W83627EHF_REG_TARGET;
1966 data->REG_FAN = W83627EHF_REG_FAN;
1967 data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
1968 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1969 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
1970 data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001971 data->REG_FAN_MAX_OUTPUT =
1972 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1973 data->REG_FAN_STEP_OUTPUT =
1974 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1975 } else {
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001976 data->REG_PWM = W83627EHF_REG_PWM;
1977 data->REG_TARGET = W83627EHF_REG_TARGET;
1978 data->REG_FAN = W83627EHF_REG_FAN;
1979 data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
1980 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1981 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
1982 data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001983 data->REG_FAN_MAX_OUTPUT =
1984 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1985 data->REG_FAN_STEP_OUTPUT =
1986 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1987 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001988
Jean Delvare08e7e272005-04-25 22:43:25 +02001989 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001990 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001991
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001992 data->vrm = vid_which_vrm();
1993 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001994 /* Read VID value */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001995 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
1996 sio_data->kind == nct6775 || sio_data->kind == nct6776) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001997 /* W83667HG has different pins for VID input and output, so
1998 we can get the VID input values directly at logical device D
1999 0xe3. */
2000 superio_select(sio_data->sioreg, W83667HG_LD_VID);
2001 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01002002 err = device_create_file(dev, &dev_attr_cpu0_vid);
2003 if (err)
2004 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05002005 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02002006 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
2007 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
2008 /* Set VID input sensibility if needed. In theory the
2009 BIOS should have set it, but in practice it's not
2010 always the case. We only do it for the W83627EHF/EHG
2011 because the W83627DHG is more complex in this
2012 respect. */
2013 if (sio_data->kind == w83627ehf) {
2014 en_vrm10 = superio_inb(sio_data->sioreg,
2015 SIO_REG_EN_VRM10);
2016 if ((en_vrm10 & 0x08) && data->vrm == 90) {
2017 dev_warn(dev, "Setting VID input "
2018 "voltage to TTL\n");
2019 superio_outb(sio_data->sioreg,
2020 SIO_REG_EN_VRM10,
2021 en_vrm10 & ~0x08);
2022 } else if (!(en_vrm10 & 0x08)
2023 && data->vrm == 100) {
2024 dev_warn(dev, "Setting VID input "
2025 "voltage to VRM10\n");
2026 superio_outb(sio_data->sioreg,
2027 SIO_REG_EN_VRM10,
2028 en_vrm10 | 0x08);
2029 }
2030 }
2031
2032 data->vid = superio_inb(sio_data->sioreg,
2033 SIO_REG_VID_DATA);
2034 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
2035 data->vid &= 0x3f;
2036
2037 err = device_create_file(dev, &dev_attr_cpu0_vid);
2038 if (err)
2039 goto exit_release;
2040 } else {
2041 dev_info(dev, "VID pins in output mode, CPU VID not "
2042 "available\n");
2043 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02002044 }
2045
Rudolf Marek08c79952006-07-05 18:14:31 +02002046 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002047 if (sio_data->kind == nct6775) {
2048 /* On NCT6775, fan4 shares pins with the fdc interface */
2049 fan3pin = 1;
2050 fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
2051 fan4min = 0;
2052 fan5pin = 0;
2053 } else if (sio_data->kind == nct6776) {
2054 fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
2055 fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
2056 fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
2057 fan4min = fan4pin;
2058 } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
2059 fan3pin = 1;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002060 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002061 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
2062 fan4min = fan4pin;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002063 } else {
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002064 fan3pin = 1;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002065 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002066 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
2067 fan4min = fan4pin;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002068 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02002069 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02002070
Jean Delvare08e7e272005-04-25 22:43:25 +02002071 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02002072 as fan on/off switches, but fan5 control is write only :/
2073 We assume that if the serial interface is disabled, designers
2074 connected fan5 as input unless they are emitting log 1, which
2075 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02002076
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002077 data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
2078
2079 data->has_fan |= (fan3pin << 2);
2080 data->has_fan_min |= (fan3pin << 2);
2081
2082 /*
2083 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
2084 */
2085 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
2086 data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
2087 data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
2088 } else {
2089 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
2090 if ((i & (1 << 2)) && fan4pin) {
2091 data->has_fan |= (1 << 3);
2092 data->has_fan_min |= (1 << 3);
2093 }
2094 if (!(i & (1 << 1)) && fan5pin) {
2095 data->has_fan |= (1 << 4);
2096 data->has_fan_min |= (1 << 4);
2097 }
2098 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002099
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04002100 /* Read fan clock dividers immediately */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002101 w83627ehf_update_fan_div_common(dev, data);
2102
2103 /* Read pwm data to save original values */
2104 w83627ehf_update_pwm_common(dev, data);
2105 for (i = 0; i < data->pwm_num; i++)
2106 data->pwm_enable_orig[i] = data->pwm_enable[i];
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04002107
Guenter Roeckb84bb512011-02-13 23:01:25 -08002108 /* Read pwm data to save original values */
2109 w83627ehf_update_pwm_common(dev, data);
2110 for (i = 0; i < data->pwm_num; i++)
2111 data->pwm_enable_orig[i] = data->pwm_enable[i];
2112
Jean Delvare08e7e272005-04-25 22:43:25 +02002113 /* Register sysfs hooks */
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002114 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
2115 err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
2116 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02002117 goto exit_remove;
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002118 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002119
Guenter Roeckda2e0252010-08-14 21:08:55 +02002120 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
2121 struct sensor_device_attribute *attr =
2122 &sda_sf3_max_step_arrays[i];
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002123 if (data->REG_FAN_STEP_OUTPUT &&
2124 data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
Guenter Roeckda2e0252010-08-14 21:08:55 +02002125 err = device_create_file(dev, &attr->dev_attr);
2126 if (err)
2127 goto exit_remove;
2128 }
2129 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002130 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02002131 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02002132 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002133 err = device_create_file(dev,
2134 &sda_sf3_arrays_fan4[i].dev_attr);
2135 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02002136 goto exit_remove;
2137 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002138
Gong Juna157d062009-03-30 21:46:43 +02002139 for (i = 0; i < data->in_num; i++) {
2140 if ((i == 6) && data->in6_skip)
2141 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02002142 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
2143 || (err = device_create_file(dev,
2144 &sda_in_alarm[i].dev_attr))
2145 || (err = device_create_file(dev,
2146 &sda_in_min[i].dev_attr))
2147 || (err = device_create_file(dev,
2148 &sda_in_max[i].dev_attr)))
2149 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02002150 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01002151
Yuan Mu412fec82006-02-05 23:24:16 +01002152 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02002153 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02002154 if ((err = device_create_file(dev,
2155 &sda_fan_input[i].dev_attr))
2156 || (err = device_create_file(dev,
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002157 &sda_fan_alarm[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02002158 goto exit_remove;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002159 if (sio_data->kind != nct6776) {
2160 err = device_create_file(dev,
2161 &sda_fan_div[i].dev_attr);
2162 if (err)
2163 goto exit_remove;
2164 }
2165 if (data->has_fan_min & (1 << i)) {
2166 err = device_create_file(dev,
2167 &sda_fan_min[i].dev_attr);
2168 if (err)
2169 goto exit_remove;
2170 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02002171 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02002172 ((err = device_create_file(dev,
2173 &sda_pwm[i].dev_attr))
2174 || (err = device_create_file(dev,
2175 &sda_pwm_mode[i].dev_attr))
2176 || (err = device_create_file(dev,
2177 &sda_pwm_enable[i].dev_attr))
2178 || (err = device_create_file(dev,
2179 &sda_target_temp[i].dev_attr))
2180 || (err = device_create_file(dev,
2181 &sda_tolerance[i].dev_attr))))
2182 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02002183 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002184 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002185
Guenter Roeckd36cf322011-02-07 15:08:54 -08002186 for (i = 0; i < NUM_REG_TEMP; i++) {
2187 if (!(data->have_temp & (1 << i)))
Gong Juna157d062009-03-30 21:46:43 +02002188 continue;
Guenter Roeckd36cf322011-02-07 15:08:54 -08002189 err = device_create_file(dev, &sda_temp_input[i].dev_attr);
2190 if (err)
2191 goto exit_remove;
2192 if (data->temp_label) {
2193 err = device_create_file(dev,
2194 &sda_temp_label[i].dev_attr);
2195 if (err)
2196 goto exit_remove;
2197 }
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002198 if (data->reg_temp_over[i]) {
2199 err = device_create_file(dev,
2200 &sda_temp_max[i].dev_attr);
2201 if (err)
2202 goto exit_remove;
2203 }
2204 if (data->reg_temp_hyst[i]) {
2205 err = device_create_file(dev,
2206 &sda_temp_max_hyst[i].dev_attr);
2207 if (err)
2208 goto exit_remove;
2209 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08002210 if (i > 2)
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002211 continue;
2212 if ((err = device_create_file(dev,
Gong Juna157d062009-03-30 21:46:43 +02002213 &sda_temp_alarm[i].dev_attr))
2214 || (err = device_create_file(dev,
2215 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02002216 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02002217 }
David Hubbardc18beb52006-09-24 21:04:38 +02002218
David Hubbard1ea6dd32007-06-24 11:16:15 +02002219 err = device_create_file(dev, &dev_attr_name);
2220 if (err)
2221 goto exit_remove;
2222
Tony Jones1beeffe2007-08-20 13:46:20 -07002223 data->hwmon_dev = hwmon_device_register(dev);
2224 if (IS_ERR(data->hwmon_dev)) {
2225 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02002226 goto exit_remove;
2227 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002228
2229 return 0;
2230
David Hubbardc18beb52006-09-24 21:04:38 +02002231exit_remove:
2232 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02002233 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002234 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02002235exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02002236 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02002237exit:
2238 return err;
2239}
2240
David Hubbard1ea6dd32007-06-24 11:16:15 +02002241static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02002242{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002243 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02002244
Tony Jones1beeffe2007-08-20 13:46:20 -07002245 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002246 w83627ehf_device_remove_files(&pdev->dev);
2247 release_region(data->addr, IOREGION_LENGTH);
2248 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04002249 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02002250
2251 return 0;
2252}
2253
David Hubbard1ea6dd32007-06-24 11:16:15 +02002254static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01002255 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02002256 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02002257 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01002258 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02002259 .probe = w83627ehf_probe,
2260 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02002261};
2262
David Hubbard1ea6dd32007-06-24 11:16:15 +02002263/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
2264static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
2265 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02002266{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002267 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
2268 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
2269 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02002270 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d2f2009-03-30 21:46:42 +02002271 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02002272 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002273 static const char __initdata sio_name_NCT6775[] = "NCT6775F";
2274 static const char __initdata sio_name_NCT6776[] = "NCT6776F";
David Hubbard1ea6dd32007-06-24 11:16:15 +02002275
Jean Delvare08e7e272005-04-25 22:43:25 +02002276 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02002277 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02002278
David Hubbard1ea6dd32007-06-24 11:16:15 +02002279 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02002280
Jean Delvare67b671b2007-12-06 23:13:42 +01002281 if (force_id)
2282 val = force_id;
2283 else
2284 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
2285 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01002286 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01002287 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02002288 sio_data->kind = w83627ehf;
2289 sio_name = sio_name_W83627EHF;
2290 break;
David Hubbard657c93b2007-02-14 21:15:04 +01002291 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02002292 sio_data->kind = w83627ehf;
2293 sio_name = sio_name_W83627EHG;
2294 break;
2295 case SIO_W83627DHG_ID:
2296 sio_data->kind = w83627dhg;
2297 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01002298 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02002299 case SIO_W83627DHG_P_ID:
2300 sio_data->kind = w83627dhg_p;
2301 sio_name = sio_name_W83627DHG_P;
2302 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002303 case SIO_W83667HG_ID:
2304 sio_data->kind = w83667hg;
2305 sio_name = sio_name_W83667HG;
2306 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02002307 case SIO_W83667HG_B_ID:
2308 sio_data->kind = w83667hg_b;
2309 sio_name = sio_name_W83667HG_B;
2310 break;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002311 case SIO_NCT6775_ID:
2312 sio_data->kind = nct6775;
2313 sio_name = sio_name_NCT6775;
2314 break;
2315 case SIO_NCT6776_ID:
2316 sio_data->kind = nct6776;
2317 sio_name = sio_name_NCT6776;
2318 break;
David Hubbard657c93b2007-02-14 21:15:04 +01002319 default:
Jean Delvare9f660362007-06-24 11:23:41 +02002320 if (val != 0xffff)
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002321 pr_debug("unsupported chip ID: 0x%04x\n", val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002322 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02002323 return -ENODEV;
2324 }
2325
David Hubbard1ea6dd32007-06-24 11:16:15 +02002326 /* We have a known chip, find the HWM I/O address */
2327 superio_select(sioaddr, W83627EHF_LD_HWM);
2328 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
2329 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07002330 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02002331 if (*addr == 0) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002332 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002333 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02002334 return -ENODEV;
2335 }
2336
2337 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02002338 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02002339 if (!(val & 0x01)) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002340 pr_warn("Forcibly enabling Super-I/O. "
2341 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002342 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02002343 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002344
David Hubbard1ea6dd32007-06-24 11:16:15 +02002345 superio_exit(sioaddr);
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002346 pr_info("Found %s chip at %#x\n", sio_name, *addr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002347 sio_data->sioreg = sioaddr;
2348
Jean Delvare08e7e272005-04-25 22:43:25 +02002349 return 0;
2350}
2351
David Hubbard1ea6dd32007-06-24 11:16:15 +02002352/* when Super-I/O functions move to a separate file, the Super-I/O
2353 * bus will manage the lifetime of the device and this module will only keep
2354 * track of the w83627ehf driver. But since we platform_device_alloc(), we
2355 * must keep track of the device */
2356static struct platform_device *pdev;
2357
Jean Delvare08e7e272005-04-25 22:43:25 +02002358static int __init sensors_w83627ehf_init(void)
2359{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002360 int err;
2361 unsigned short address;
2362 struct resource res;
2363 struct w83627ehf_sio_data sio_data;
2364
2365 /* initialize sio_data->kind and sio_data->sioreg.
2366 *
2367 * when Super-I/O functions move to a separate file, the Super-I/O
2368 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
2369 * w83627ehf hardware monitor, and call probe() */
2370 if (w83627ehf_find(0x2e, &address, &sio_data) &&
2371 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02002372 return -ENODEV;
2373
David Hubbard1ea6dd32007-06-24 11:16:15 +02002374 err = platform_driver_register(&w83627ehf_driver);
2375 if (err)
2376 goto exit;
2377
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002378 pdev = platform_device_alloc(DRVNAME, address);
2379 if (!pdev) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02002380 err = -ENOMEM;
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002381 pr_err("Device allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002382 goto exit_unregister;
2383 }
2384
2385 err = platform_device_add_data(pdev, &sio_data,
2386 sizeof(struct w83627ehf_sio_data));
2387 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002388 pr_err("Platform data allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002389 goto exit_device_put;
2390 }
2391
2392 memset(&res, 0, sizeof(res));
2393 res.name = DRVNAME;
2394 res.start = address + IOREGION_OFFSET;
2395 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
2396 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01002397
2398 err = acpi_check_resource_conflict(&res);
2399 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002400 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002401
David Hubbard1ea6dd32007-06-24 11:16:15 +02002402 err = platform_device_add_resources(pdev, &res, 1);
2403 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002404 pr_err("Device resource addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002405 goto exit_device_put;
2406 }
2407
2408 /* platform_device_add calls probe() */
2409 err = platform_device_add(pdev);
2410 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002411 pr_err("Device addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002412 goto exit_device_put;
2413 }
2414
2415 return 0;
2416
2417exit_device_put:
2418 platform_device_put(pdev);
2419exit_unregister:
2420 platform_driver_unregister(&w83627ehf_driver);
2421exit:
2422 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02002423}
2424
2425static void __exit sensors_w83627ehf_exit(void)
2426{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002427 platform_device_unregister(pdev);
2428 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02002429}
2430
2431MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
2432MODULE_DESCRIPTION("W83627EHF driver");
2433MODULE_LICENSE("GPL");
2434
2435module_init(sensors_w83627ehf_init);
2436module_exit(sensors_w83627ehf_exit);