blob: 460292bad74ab0ac5619aa81750c3f05079f5224 [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 };
Guenter Roeck26bc4402011-02-11 08:00:58 -0800237static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800238static 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
Guenter Roeck26bc4402011-02-11 08:00:58 -0800345static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200346{
Guenter Roeck26bc4402011-02-11 08:00:58 -0800347 if (reg == 0 || reg == 255)
Jean Delvare08e7e272005-04-25 22:43:25 +0200348 return 0;
Guenter Roeck26bc4402011-02-11 08:00:58 -0800349 return 1350000U / (reg << divreg);
350}
351
352static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
353{
354 if ((reg & 0xff1f) == 0xff1f)
355 return 0;
356
357 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
358
359 if (reg == 0)
360 return 0;
361
362 return 1350000U / reg;
363}
364
365static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
366{
367 if (reg == 0 || reg == 0xffff)
368 return 0;
369
370 /*
371 * Even though the registers are 16 bit wide, the fan divisor
372 * still applies.
373 */
374 return 1350000U / (reg << divreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200375}
376
377static inline unsigned int
378div_from_reg(u8 reg)
379{
380 return 1 << reg;
381}
382
383static inline int
Guenter Roeckbce26c52011-02-04 12:54:14 -0800384temp_from_reg(u16 reg, s16 regval)
Jean Delvare08e7e272005-04-25 22:43:25 +0200385{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800386 if (is_word_sized(reg))
387 return LM75_TEMP_FROM_REG(regval);
388 return regval * 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200389}
390
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800391static inline u16
Guenter Roeckbce26c52011-02-04 12:54:14 -0800392temp_to_reg(u16 reg, long temp)
Jean Delvare08e7e272005-04-25 22:43:25 +0200393{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800394 if (is_word_sized(reg))
395 return LM75_TEMP_TO_REG(temp);
396 return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
Jean Delvare08e7e272005-04-25 22:43:25 +0200397}
398
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100399/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
400
401static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
402
403static inline long in_from_reg(u8 reg, u8 nr)
404{
405 return reg * scale_in[nr];
406}
407
408static inline u8 in_to_reg(u32 val, u8 nr)
409{
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800410 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
411 255);
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100412}
413
Jean Delvare08e7e272005-04-25 22:43:25 +0200414/*
415 * Data structures and manipulation thereof
416 */
417
418struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200419 int addr; /* IO base of hw monitor block */
420 const char *name;
421
Tony Jones1beeffe2007-08-20 13:46:20 -0700422 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100423 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200424
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800425 u16 reg_temp[NUM_REG_TEMP];
426 u16 reg_temp_over[NUM_REG_TEMP];
427 u16 reg_temp_hyst[NUM_REG_TEMP];
428 u16 reg_temp_config[NUM_REG_TEMP];
Guenter Roeckd36cf322011-02-07 15:08:54 -0800429 u8 temp_src[NUM_REG_TEMP];
430 const char * const *temp_label;
431
Guenter Roeck279af1a2011-02-13 22:34:47 -0800432 const u16 *REG_PWM;
433 const u16 *REG_TARGET;
434 const u16 *REG_FAN;
435 const u16 *REG_FAN_MIN;
436 const u16 *REG_FAN_START_OUTPUT;
437 const u16 *REG_FAN_STOP_OUTPUT;
438 const u16 *REG_FAN_STOP_TIME;
439 const u16 *REG_FAN_MAX_OUTPUT;
440 const u16 *REG_FAN_STEP_OUTPUT;
Guenter Roeckda2e0252010-08-14 21:08:55 +0200441
Guenter Roeck26bc4402011-02-11 08:00:58 -0800442 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
443 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
444
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100445 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200446 char valid; /* !=0 if following fields are valid */
447 unsigned long last_updated; /* In jiffies */
448
449 /* Register values */
Guenter Roeck83cc8982011-02-06 08:10:15 -0800450 u8 bank; /* current register bank */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200451 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100452 u8 in[10]; /* Register value */
453 u8 in_max[10]; /* Register value */
454 u8 in_min[10]; /* Register value */
Guenter Roeck3382a912011-02-13 13:08:23 -0800455 unsigned int rpm[5];
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800456 u16 fan_min[5];
Jean Delvare08e7e272005-04-25 22:43:25 +0200457 u8 fan_div[5];
458 u8 has_fan; /* some fan inputs can be disabled */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800459 u8 has_fan_min; /* some fans don't have min register */
Guenter Roeck26bc4402011-02-11 08:00:58 -0800460 bool has_fan_div;
Jean Delvareda667362007-06-24 11:21:02 +0200461 u8 temp_type[3];
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800462 s16 temp[9];
463 s16 temp_max[9];
464 s16 temp_max_hyst[9];
Jean Delvarea4589db2006-03-23 16:30:29 +0100465 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200466
467 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
468 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800469 2->thermal cruise mode (also called SmartFan I)
470 3->fan speed cruise mode
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800471 4->variable thermal cruise (also called
Guenter Roeckb84bb512011-02-13 23:01:25 -0800472 SmartFan III)
473 5->enhanced variable thermal cruise (also called
474 SmartFan IV) */
475 u8 pwm_enable_orig[4]; /* original value of pwm_enable */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200476 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200477 u8 pwm[4];
478 u8 target_temp[4];
479 u8 tolerance[4];
480
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800481 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
482 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
483 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
484 u8 fan_max_output[4]; /* maximum fan speed */
485 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200486
487 u8 vid;
488 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200489
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800490 u16 have_temp;
Gong Juna157d062009-03-30 21:46:43 +0200491 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200492};
493
David Hubbard1ea6dd32007-06-24 11:16:15 +0200494struct w83627ehf_sio_data {
495 int sioreg;
496 enum kinds kind;
497};
498
Guenter Roeck83cc8982011-02-06 08:10:15 -0800499/*
500 * On older chips, only registers 0x50-0x5f are banked.
501 * On more recent chips, all registers are banked.
502 * Assume that is the case and set the bank number for each access.
503 * Cache the bank number so it only needs to be set if it changes.
504 */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200505static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200506{
Guenter Roeck83cc8982011-02-06 08:10:15 -0800507 u8 bank = reg >> 8;
508 if (data->bank != bank) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200509 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
Guenter Roeck83cc8982011-02-06 08:10:15 -0800510 outb_p(bank, data->addr + DATA_REG_OFFSET);
511 data->bank = bank;
Jean Delvare08e7e272005-04-25 22:43:25 +0200512 }
513}
514
David Hubbard1ea6dd32007-06-24 11:16:15 +0200515static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200516{
Jean Delvare08e7e272005-04-25 22:43:25 +0200517 int res, word_sized = is_word_sized(reg);
518
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100519 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200520
David Hubbard1ea6dd32007-06-24 11:16:15 +0200521 w83627ehf_set_bank(data, reg);
522 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
523 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200524 if (word_sized) {
525 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200526 data->addr + ADDR_REG_OFFSET);
527 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200528 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200529
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100530 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200531 return res;
532}
533
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800534static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
535 u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200536{
Jean Delvare08e7e272005-04-25 22:43:25 +0200537 int word_sized = is_word_sized(reg);
538
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100539 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200540
David Hubbard1ea6dd32007-06-24 11:16:15 +0200541 w83627ehf_set_bank(data, reg);
542 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200543 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200544 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200545 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200546 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200547 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200548 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200549
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100550 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200551 return 0;
552}
553
554/* This function assumes that the caller holds data->update_lock */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800555static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
556{
557 u8 reg;
558
559 switch (nr) {
560 case 0:
561 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
562 | (data->fan_div[0] & 0x7);
563 w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
564 break;
565 case 1:
566 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
567 | ((data->fan_div[1] << 4) & 0x70);
568 w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
569 case 2:
570 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
571 | (data->fan_div[2] & 0x7);
572 w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
573 break;
574 case 3:
575 reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
576 | ((data->fan_div[3] << 4) & 0x70);
577 w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
578 break;
579 }
580}
581
582/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200583static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200584{
Jean Delvare08e7e272005-04-25 22:43:25 +0200585 u8 reg;
586
587 switch (nr) {
588 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200589 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200590 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200591 /* fan5 input control bit is write only, compute the value */
592 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200593 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
594 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200595 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200596 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200597 break;
598 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200599 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200600 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200601 /* fan5 input control bit is write only, compute the value */
602 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200603 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
604 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200605 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200606 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200607 break;
608 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200609 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200610 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200611 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
612 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200613 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200614 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200615 break;
616 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200617 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200618 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200619 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
620 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200621 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200622 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200623 break;
624 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200625 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700626 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200627 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200628 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200629 break;
630 }
631}
632
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800633static void w83627ehf_write_fan_div_common(struct device *dev,
634 struct w83627ehf_data *data, int nr)
635{
636 struct w83627ehf_sio_data *sio_data = dev->platform_data;
637
638 if (sio_data->kind == nct6776)
639 ; /* no dividers, do nothing */
640 else if (sio_data->kind == nct6775)
641 nct6775_write_fan_div(data, nr);
642 else
643 w83627ehf_write_fan_div(data, nr);
644}
645
646static void nct6775_update_fan_div(struct w83627ehf_data *data)
647{
648 u8 i;
649
650 i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
651 data->fan_div[0] = i & 0x7;
652 data->fan_div[1] = (i & 0x70) >> 4;
653 i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
654 data->fan_div[2] = i & 0x7;
655 if (data->has_fan & (1<<3))
656 data->fan_div[3] = (i & 0x70) >> 4;
657}
658
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400659static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
660{
661 int i;
662
663 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
664 data->fan_div[0] = (i >> 4) & 0x03;
665 data->fan_div[1] = (i >> 6) & 0x03;
666 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
667 data->fan_div[2] = (i >> 6) & 0x03;
668 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
669 data->fan_div[0] |= (i >> 3) & 0x04;
670 data->fan_div[1] |= (i >> 4) & 0x04;
671 data->fan_div[2] |= (i >> 5) & 0x04;
672 if (data->has_fan & ((1 << 3) | (1 << 4))) {
673 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
674 data->fan_div[3] = i & 0x03;
675 data->fan_div[4] = ((i >> 2) & 0x03)
676 | ((i >> 5) & 0x04);
677 }
678 if (data->has_fan & (1 << 3)) {
679 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
680 data->fan_div[3] |= (i >> 5) & 0x04;
681 }
682}
683
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800684static void w83627ehf_update_fan_div_common(struct device *dev,
685 struct w83627ehf_data *data)
686{
687 struct w83627ehf_sio_data *sio_data = dev->platform_data;
688
689 if (sio_data->kind == nct6776)
690 ; /* no dividers, do nothing */
691 else if (sio_data->kind == nct6775)
692 nct6775_update_fan_div(data);
693 else
694 w83627ehf_update_fan_div(data);
695}
696
697static void nct6775_update_pwm(struct w83627ehf_data *data)
698{
699 int i;
700 int pwmcfg, fanmodecfg;
701
702 for (i = 0; i < data->pwm_num; i++) {
703 pwmcfg = w83627ehf_read_value(data,
704 W83627EHF_REG_PWM_ENABLE[i]);
705 fanmodecfg = w83627ehf_read_value(data,
706 NCT6775_REG_FAN_MODE[i]);
707 data->pwm_mode[i] =
708 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
709 data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
710 data->tolerance[i] = fanmodecfg & 0x0f;
711 data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
712 }
713}
714
715static void w83627ehf_update_pwm(struct w83627ehf_data *data)
716{
717 int i;
718 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
719
720 for (i = 0; i < data->pwm_num; i++) {
721 if (!(data->has_fan & (1 << i)))
722 continue;
723
724 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
725 if (i != 1) {
726 pwmcfg = w83627ehf_read_value(data,
727 W83627EHF_REG_PWM_ENABLE[i]);
728 tolerance = w83627ehf_read_value(data,
729 W83627EHF_REG_TOLERANCE[i]);
730 }
731 data->pwm_mode[i] =
732 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
733 data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
734 & 3) + 1;
735 data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
736
737 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
738 }
739}
740
741static void w83627ehf_update_pwm_common(struct device *dev,
742 struct w83627ehf_data *data)
743{
744 struct w83627ehf_sio_data *sio_data = dev->platform_data;
745
746 if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
747 nct6775_update_pwm(data);
748 else
749 w83627ehf_update_pwm(data);
750}
751
Jean Delvare08e7e272005-04-25 22:43:25 +0200752static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
753{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200754 struct w83627ehf_data *data = dev_get_drvdata(dev);
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800755 struct w83627ehf_sio_data *sio_data = dev->platform_data;
756
Jean Delvare08e7e272005-04-25 22:43:25 +0200757 int i;
758
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100759 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200760
Jean Delvare6b3e4642007-06-24 11:19:01 +0200761 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200762 || !data->valid) {
763 /* Fan clock dividers */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800764 w83627ehf_update_fan_div_common(dev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200765
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100766 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200767 for (i = 0; i < data->in_num; i++) {
768 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100769 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200770 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100771 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200772 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100773 W83627EHF_REG_IN_MAX(i));
774 }
775
Jean Delvare08e7e272005-04-25 22:43:25 +0200776 /* Measured fan speeds and limits */
777 for (i = 0; i < 5; i++) {
Guenter Roeck3382a912011-02-13 13:08:23 -0800778 u16 reg;
779
Jean Delvare08e7e272005-04-25 22:43:25 +0200780 if (!(data->has_fan & (1 << i)))
781 continue;
782
Guenter Roeck3382a912011-02-13 13:08:23 -0800783 reg = w83627ehf_read_value(data, data->REG_FAN[i]);
784 data->rpm[i] = data->fan_from_reg(reg,
785 data->fan_div[i]);
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800786
787 if (data->has_fan_min & (1 << i))
788 data->fan_min[i] = w83627ehf_read_value(data,
Guenter Roeck279af1a2011-02-13 22:34:47 -0800789 data->REG_FAN_MIN[i]);
Jean Delvare08e7e272005-04-25 22:43:25 +0200790
791 /* If we failed to measure the fan speed and clock
792 divider can be increased, let's try that for next
793 time */
Guenter Roeck26bc4402011-02-11 08:00:58 -0800794 if (data->has_fan_div
Guenter Roeck3382a912011-02-13 13:08:23 -0800795 && (reg >= 0xff || (sio_data->kind == nct6775
796 && reg == 0x00))
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800797 && data->fan_div[i] < 0x07) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800798 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200799 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700800 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200801 div_from_reg(data->fan_div[i] + 1));
802 data->fan_div[i]++;
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800803 w83627ehf_write_fan_div_common(dev, data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200804 /* Preserve min limit if possible */
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800805 if ((data->has_fan_min & (1 << i))
806 && data->fan_min[i] >= 2
Jean Delvare08e7e272005-04-25 22:43:25 +0200807 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200808 w83627ehf_write_value(data,
Guenter Roeck279af1a2011-02-13 22:34:47 -0800809 data->REG_FAN_MIN[i],
Jean Delvare08e7e272005-04-25 22:43:25 +0200810 (data->fan_min[i] /= 2));
811 }
812 }
813
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800814 w83627ehf_update_pwm_common(dev, data);
815
Guenter Roeckda2e0252010-08-14 21:08:55 +0200816 for (i = 0; i < data->pwm_num; i++) {
817 if (!(data->has_fan & (1 << i)))
818 continue;
819
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800820 data->fan_start_output[i] =
821 w83627ehf_read_value(data,
822 data->REG_FAN_START_OUTPUT[i]);
823 data->fan_stop_output[i] =
824 w83627ehf_read_value(data,
825 data->REG_FAN_STOP_OUTPUT[i]);
826 data->fan_stop_time[i] =
827 w83627ehf_read_value(data,
828 data->REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200829
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800830 if (data->REG_FAN_MAX_OUTPUT &&
831 data->REG_FAN_MAX_OUTPUT[i] != 0xff)
Guenter Roeckda2e0252010-08-14 21:08:55 +0200832 data->fan_max_output[i] =
833 w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800834 data->REG_FAN_MAX_OUTPUT[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200835
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800836 if (data->REG_FAN_STEP_OUTPUT &&
837 data->REG_FAN_STEP_OUTPUT[i] != 0xff)
Guenter Roeckda2e0252010-08-14 21:08:55 +0200838 data->fan_step_output[i] =
839 w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800840 data->REG_FAN_STEP_OUTPUT[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200841
Rudolf Marek08c79952006-07-05 18:14:31 +0200842 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200843 w83627ehf_read_value(data,
Guenter Roeck279af1a2011-02-13 22:34:47 -0800844 data->REG_TARGET[i]) &
Rudolf Marek08c79952006-07-05 18:14:31 +0200845 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
Rudolf Marek08c79952006-07-05 18:14:31 +0200846 }
847
Jean Delvare08e7e272005-04-25 22:43:25 +0200848 /* Measured temperatures and limits */
Guenter Roeckd36cf322011-02-07 15:08:54 -0800849 for (i = 0; i < NUM_REG_TEMP; i++) {
850 if (!(data->have_temp & (1 << i)))
851 continue;
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800852 data->temp[i] = w83627ehf_read_value(data,
853 data->reg_temp[i]);
854 if (data->reg_temp_over[i])
855 data->temp_max[i]
856 = w83627ehf_read_value(data,
857 data->reg_temp_over[i]);
858 if (data->reg_temp_hyst[i])
859 data->temp_max_hyst[i]
860 = w83627ehf_read_value(data,
861 data->reg_temp_hyst[i]);
Jean Delvare08e7e272005-04-25 22:43:25 +0200862 }
863
David Hubbard1ea6dd32007-06-24 11:16:15 +0200864 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100865 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200866 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100867 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200868 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100869 W83627EHF_REG_ALARM3) << 16);
870
Jean Delvare08e7e272005-04-25 22:43:25 +0200871 data->last_updated = jiffies;
872 data->valid = 1;
873 }
874
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100875 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200876 return data;
877}
878
879/*
880 * Sysfs callback functions
881 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100882#define show_in_reg(reg) \
883static ssize_t \
884show_##reg(struct device *dev, struct device_attribute *attr, \
885 char *buf) \
886{ \
887 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800888 struct sensor_device_attribute *sensor_attr = \
889 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100890 int nr = sensor_attr->index; \
891 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
892}
893show_in_reg(in)
894show_in_reg(in_min)
895show_in_reg(in_max)
896
897#define store_in_reg(REG, reg) \
898static ssize_t \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800899store_in_##reg(struct device *dev, struct device_attribute *attr, \
900 const char *buf, size_t count) \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100901{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200902 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800903 struct sensor_device_attribute *sensor_attr = \
904 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100905 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800906 unsigned long val; \
907 int err; \
908 err = strict_strtoul(buf, 10, &val); \
909 if (err < 0) \
910 return err; \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100911 mutex_lock(&data->update_lock); \
912 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200913 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100914 data->in_##reg[nr]); \
915 mutex_unlock(&data->update_lock); \
916 return count; \
917}
918
919store_in_reg(MIN, min)
920store_in_reg(MAX, max)
921
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800922static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
923 char *buf)
Jean Delvarea4589db2006-03-23 16:30:29 +0100924{
925 struct w83627ehf_data *data = w83627ehf_update_device(dev);
926 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
927 int nr = sensor_attr->index;
928 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
929}
930
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100931static struct sensor_device_attribute sda_in_input[] = {
932 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
933 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
934 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
935 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
936 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
937 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
938 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
939 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
940 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
941 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
942};
943
Jean Delvarea4589db2006-03-23 16:30:29 +0100944static struct sensor_device_attribute sda_in_alarm[] = {
945 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
946 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
947 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
948 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
949 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
950 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
951 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
952 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
953 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
954 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
955};
956
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100957static struct sensor_device_attribute sda_in_min[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800958 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
959 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
960 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
961 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
962 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
963 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
964 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
965 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
966 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
967 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100968};
969
970static struct sensor_device_attribute sda_in_max[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800971 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
972 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
973 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
974 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
975 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
976 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
977 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
978 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
979 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
980 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100981};
982
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800983static ssize_t
984show_fan(struct device *dev, struct device_attribute *attr, char *buf)
985{
986 struct w83627ehf_data *data = w83627ehf_update_device(dev);
987 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
988 int nr = sensor_attr->index;
Guenter Roeck3382a912011-02-13 13:08:23 -0800989 return sprintf(buf, "%d\n", data->rpm[nr]);
Jean Delvare08e7e272005-04-25 22:43:25 +0200990}
Guenter Roeckec3e5a12011-02-02 08:46:49 -0800991
992static ssize_t
993show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
994{
995 struct w83627ehf_data *data = w83627ehf_update_device(dev);
996 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
997 int nr = sensor_attr->index;
998 return sprintf(buf, "%d\n",
Guenter Roeck26bc4402011-02-11 08:00:58 -0800999 data->fan_from_reg_min(data->fan_min[nr],
1000 data->fan_div[nr]));
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001001}
Jean Delvare08e7e272005-04-25 22:43:25 +02001002
1003static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +01001004show_fan_div(struct device *dev, struct device_attribute *attr,
1005 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +02001006{
1007 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +01001008 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1009 int nr = sensor_attr->index;
1010 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +02001011}
1012
1013static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +01001014store_fan_min(struct device *dev, struct device_attribute *attr,
1015 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +02001016{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001017 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +01001018 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1019 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001020 unsigned long val;
1021 int err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001022 unsigned int reg;
1023 u8 new_div;
1024
Guenter Roeckbce26c52011-02-04 12:54:14 -08001025 err = strict_strtoul(buf, 10, &val);
1026 if (err < 0)
1027 return err;
1028
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001029 mutex_lock(&data->update_lock);
Guenter Roeck26bc4402011-02-11 08:00:58 -08001030 if (!data->has_fan_div) {
1031 /*
1032 * Only NCT6776F for now, so we know that this is a 13 bit
1033 * register
1034 */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001035 if (!val) {
1036 val = 0xff1f;
1037 } else {
1038 if (val > 1350000U)
1039 val = 135000U;
1040 val = 1350000U / val;
1041 val = (val & 0x1f) | ((val << 3) & 0xff00);
1042 }
1043 data->fan_min[nr] = val;
1044 goto done; /* Leave fan divider alone */
1045 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001046 if (!val) {
1047 /* No min limit, alarm disabled */
1048 data->fan_min[nr] = 255;
1049 new_div = data->fan_div[nr]; /* No change */
1050 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
1051 } else if ((reg = 1350000U / val) >= 128 * 255) {
1052 /* Speed below this value cannot possibly be represented,
1053 even with the highest divider (128) */
1054 data->fan_min[nr] = 254;
1055 new_div = 7; /* 128 == (1 << 7) */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001056 dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001057 "minimum\n", nr + 1, val,
Guenter Roeck26bc4402011-02-11 08:00:58 -08001058 data->fan_from_reg_min(254, 7));
Jean Delvare08e7e272005-04-25 22:43:25 +02001059 } else if (!reg) {
1060 /* Speed above this value cannot possibly be represented,
1061 even with the lowest divider (1) */
1062 data->fan_min[nr] = 1;
1063 new_div = 0; /* 1 == (1 << 0) */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001064 dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001065 "maximum\n", nr + 1, val,
Guenter Roeck26bc4402011-02-11 08:00:58 -08001066 data->fan_from_reg_min(1, 0));
Jean Delvare08e7e272005-04-25 22:43:25 +02001067 } else {
1068 /* Automatically pick the best divider, i.e. the one such
1069 that the min limit will correspond to a register value
1070 in the 96..192 range */
1071 new_div = 0;
1072 while (reg > 192 && new_div < 7) {
1073 reg >>= 1;
1074 new_div++;
1075 }
1076 data->fan_min[nr] = reg;
1077 }
1078
1079 /* Write both the fan clock divider (if it changed) and the new
1080 fan min (unconditionally) */
1081 if (new_div != data->fan_div[nr]) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001082 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
1083 nr + 1, div_from_reg(data->fan_div[nr]),
1084 div_from_reg(new_div));
1085 data->fan_div[nr] = new_div;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001086 w83627ehf_write_fan_div_common(dev, data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +02001087 /* Give the chip time to sample a new speed value */
1088 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +02001089 }
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001090done:
Guenter Roeck279af1a2011-02-13 22:34:47 -08001091 w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +02001092 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001093 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +02001094
1095 return count;
1096}
1097
Yuan Mu412fec82006-02-05 23:24:16 +01001098static struct sensor_device_attribute sda_fan_input[] = {
1099 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
1100 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
1101 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
1102 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
1103 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
1104};
Jean Delvare08e7e272005-04-25 22:43:25 +02001105
Jean Delvarea4589db2006-03-23 16:30:29 +01001106static struct sensor_device_attribute sda_fan_alarm[] = {
1107 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
1108 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
1109 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
1110 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
1111 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
1112};
1113
Yuan Mu412fec82006-02-05 23:24:16 +01001114static struct sensor_device_attribute sda_fan_min[] = {
1115 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
1116 store_fan_min, 0),
1117 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
1118 store_fan_min, 1),
1119 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
1120 store_fan_min, 2),
1121 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
1122 store_fan_min, 3),
1123 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
1124 store_fan_min, 4),
1125};
Jean Delvare08e7e272005-04-25 22:43:25 +02001126
Yuan Mu412fec82006-02-05 23:24:16 +01001127static struct sensor_device_attribute sda_fan_div[] = {
1128 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
1129 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
1130 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
1131 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
1132 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
1133};
Jean Delvare08e7e272005-04-25 22:43:25 +02001134
Guenter Roeckd36cf322011-02-07 15:08:54 -08001135static ssize_t
1136show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1137{
1138 struct w83627ehf_data *data = w83627ehf_update_device(dev);
1139 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1140 int nr = sensor_attr->index;
1141 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1142}
1143
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001144#define show_temp_reg(addr, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001145static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +01001146show_##reg(struct device *dev, struct device_attribute *attr, \
1147 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001148{ \
1149 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001150 struct sensor_device_attribute *sensor_attr = \
1151 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +01001152 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +02001153 return sprintf(buf, "%d\n", \
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001154 temp_from_reg(data->addr[nr], data->reg[nr])); \
Jean Delvare08e7e272005-04-25 22:43:25 +02001155}
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001156show_temp_reg(reg_temp, temp);
1157show_temp_reg(reg_temp_over, temp_max);
1158show_temp_reg(reg_temp_hyst, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +02001159
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001160#define store_temp_reg(addr, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001161static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +01001162store_##reg(struct device *dev, struct device_attribute *attr, \
1163 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +02001164{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001165 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001166 struct sensor_device_attribute *sensor_attr = \
1167 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +01001168 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001169 int err; \
1170 long val; \
1171 err = strict_strtol(buf, 10, &val); \
1172 if (err < 0) \
1173 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001174 mutex_lock(&data->update_lock); \
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001175 data->reg[nr] = temp_to_reg(data->addr[nr], val); \
1176 w83627ehf_write_value(data, data->addr[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +02001177 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001178 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +02001179 return count; \
1180}
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001181store_temp_reg(reg_temp_over, temp_max);
1182store_temp_reg(reg_temp_hyst, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +02001183
Jean Delvareda667362007-06-24 11:21:02 +02001184static ssize_t
1185show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
1186{
1187 struct w83627ehf_data *data = w83627ehf_update_device(dev);
1188 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1189 int nr = sensor_attr->index;
1190 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
1191}
1192
Gong Juna157d062009-03-30 21:46:43 +02001193static struct sensor_device_attribute sda_temp_input[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -08001194 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
1195 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
1196 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
Guenter Roeckd36cf322011-02-07 15:08:54 -08001197 SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001198 SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
1199 SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
1200 SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
1201 SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
1202 SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
Guenter Roeckd36cf322011-02-07 15:08:54 -08001203};
1204
1205static struct sensor_device_attribute sda_temp_label[] = {
1206 SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
1207 SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
1208 SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
1209 SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001210 SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
1211 SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
1212 SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
1213 SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
1214 SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
Gong Juna157d062009-03-30 21:46:43 +02001215};
1216
1217static struct sensor_device_attribute sda_temp_max[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -08001218 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +01001219 store_temp_max, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001220 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +01001221 store_temp_max, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001222 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
1223 store_temp_max, 2),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001224 SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
1225 store_temp_max, 3),
1226 SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
1227 store_temp_max, 4),
1228 SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
1229 store_temp_max, 5),
1230 SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
1231 store_temp_max, 6),
1232 SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
1233 store_temp_max, 7),
1234 SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
1235 store_temp_max, 8),
Gong Juna157d062009-03-30 21:46:43 +02001236};
1237
1238static struct sensor_device_attribute sda_temp_max_hyst[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -08001239 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +01001240 store_temp_max_hyst, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001241 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +01001242 store_temp_max_hyst, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -08001243 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1244 store_temp_max_hyst, 2),
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001245 SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1246 store_temp_max_hyst, 3),
1247 SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1248 store_temp_max_hyst, 4),
1249 SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1250 store_temp_max_hyst, 5),
1251 SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1252 store_temp_max_hyst, 6),
1253 SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1254 store_temp_max_hyst, 7),
1255 SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1256 store_temp_max_hyst, 8),
Gong Juna157d062009-03-30 21:46:43 +02001257};
1258
1259static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +01001260 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
1261 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
1262 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +02001263};
1264
1265static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +02001266 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
1267 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
1268 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +01001269};
Jean Delvare08e7e272005-04-25 22:43:25 +02001270
Rudolf Marek08c79952006-07-05 18:14:31 +02001271#define show_pwm_reg(reg) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001272static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1273 char *buf) \
Rudolf Marek08c79952006-07-05 18:14:31 +02001274{ \
1275 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001276 struct sensor_device_attribute *sensor_attr = \
1277 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001278 int nr = sensor_attr->index; \
1279 return sprintf(buf, "%d\n", data->reg[nr]); \
1280}
1281
1282show_pwm_reg(pwm_mode)
1283show_pwm_reg(pwm_enable)
1284show_pwm_reg(pwm)
1285
1286static ssize_t
1287store_pwm_mode(struct device *dev, struct device_attribute *attr,
1288 const char *buf, size_t count)
1289{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001290 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001291 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1292 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001293 unsigned long val;
1294 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001295 u16 reg;
1296
Guenter Roeckbce26c52011-02-04 12:54:14 -08001297 err = strict_strtoul(buf, 10, &val);
1298 if (err < 0)
1299 return err;
1300
Rudolf Marek08c79952006-07-05 18:14:31 +02001301 if (val > 1)
1302 return -EINVAL;
1303 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001304 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001305 data->pwm_mode[nr] = val;
1306 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
1307 if (!val)
1308 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001309 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001310 mutex_unlock(&data->update_lock);
1311 return count;
1312}
1313
1314static ssize_t
1315store_pwm(struct device *dev, struct device_attribute *attr,
1316 const char *buf, size_t count)
1317{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001318 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001319 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1320 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001321 unsigned long val;
1322 int err;
1323
1324 err = strict_strtoul(buf, 10, &val);
1325 if (err < 0)
1326 return err;
1327
1328 val = SENSORS_LIMIT(val, 0, 255);
Rudolf Marek08c79952006-07-05 18:14:31 +02001329
1330 mutex_lock(&data->update_lock);
1331 data->pwm[nr] = val;
Guenter Roeck279af1a2011-02-13 22:34:47 -08001332 w83627ehf_write_value(data, data->REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001333 mutex_unlock(&data->update_lock);
1334 return count;
1335}
1336
1337static ssize_t
1338store_pwm_enable(struct device *dev, struct device_attribute *attr,
1339 const char *buf, size_t count)
1340{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001341 struct w83627ehf_data *data = dev_get_drvdata(dev);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001342 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Rudolf Marek08c79952006-07-05 18:14:31 +02001343 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1344 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001345 unsigned long val;
1346 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001347 u16 reg;
1348
Guenter Roeckbce26c52011-02-04 12:54:14 -08001349 err = strict_strtoul(buf, 10, &val);
1350 if (err < 0)
1351 return err;
1352
Guenter Roeckb84bb512011-02-13 23:01:25 -08001353 if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
Rudolf Marek08c79952006-07-05 18:14:31 +02001354 return -EINVAL;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001355 /* SmartFan III mode is not supported on NCT6776F */
1356 if (sio_data->kind == nct6776 && val == 4)
1357 return -EINVAL;
1358
Rudolf Marek08c79952006-07-05 18:14:31 +02001359 mutex_lock(&data->update_lock);
Rudolf Marek08c79952006-07-05 18:14:31 +02001360 data->pwm_enable[nr] = val;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001361 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1362 reg = w83627ehf_read_value(data,
1363 NCT6775_REG_FAN_MODE[nr]);
1364 reg &= 0x0f;
1365 reg |= (val - 1) << 4;
1366 w83627ehf_write_value(data,
1367 NCT6775_REG_FAN_MODE[nr], reg);
1368 } else {
1369 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
1370 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1371 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
1372 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
1373 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001374 mutex_unlock(&data->update_lock);
1375 return count;
1376}
1377
1378
1379#define show_tol_temp(reg) \
1380static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1381 char *buf) \
1382{ \
1383 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001384 struct sensor_device_attribute *sensor_attr = \
1385 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001386 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001387 return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001388}
1389
1390show_tol_temp(tolerance)
1391show_tol_temp(target_temp)
1392
1393static ssize_t
1394store_target_temp(struct device *dev, struct device_attribute *attr,
1395 const char *buf, size_t count)
1396{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001397 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001398 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1399 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001400 long val;
1401 int err;
1402
1403 err = strict_strtol(buf, 10, &val);
1404 if (err < 0)
1405 return err;
1406
1407 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
Rudolf Marek08c79952006-07-05 18:14:31 +02001408
1409 mutex_lock(&data->update_lock);
1410 data->target_temp[nr] = val;
Guenter Roeck279af1a2011-02-13 22:34:47 -08001411 w83627ehf_write_value(data, data->REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001412 mutex_unlock(&data->update_lock);
1413 return count;
1414}
1415
1416static ssize_t
1417store_tolerance(struct device *dev, struct device_attribute *attr,
1418 const char *buf, size_t count)
1419{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001420 struct w83627ehf_data *data = dev_get_drvdata(dev);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001421 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Rudolf Marek08c79952006-07-05 18:14:31 +02001422 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1423 int nr = sensor_attr->index;
1424 u16 reg;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001425 long val;
1426 int err;
1427
1428 err = strict_strtol(buf, 10, &val);
1429 if (err < 0)
1430 return err;
1431
Rudolf Marek08c79952006-07-05 18:14:31 +02001432 /* Limit the temp to 0C - 15C */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001433 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
Rudolf Marek08c79952006-07-05 18:14:31 +02001434
1435 mutex_lock(&data->update_lock);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001436 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1437 /* Limit tolerance further for NCT6776F */
1438 if (sio_data->kind == nct6776 && val > 7)
1439 val = 7;
1440 reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001441 reg = (reg & 0xf0) | val;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001442 w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
1443 } else {
1444 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
1445 if (nr == 1)
1446 reg = (reg & 0x0f) | (val << 4);
1447 else
1448 reg = (reg & 0xf0) | val;
1449 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
1450 }
1451 data->tolerance[nr] = val;
Rudolf Marek08c79952006-07-05 18:14:31 +02001452 mutex_unlock(&data->update_lock);
1453 return count;
1454}
1455
1456static struct sensor_device_attribute sda_pwm[] = {
1457 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1458 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1459 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1460 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1461};
1462
1463static struct sensor_device_attribute sda_pwm_mode[] = {
1464 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1465 store_pwm_mode, 0),
1466 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1467 store_pwm_mode, 1),
1468 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1469 store_pwm_mode, 2),
1470 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1471 store_pwm_mode, 3),
1472};
1473
1474static struct sensor_device_attribute sda_pwm_enable[] = {
1475 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1476 store_pwm_enable, 0),
1477 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1478 store_pwm_enable, 1),
1479 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1480 store_pwm_enable, 2),
1481 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1482 store_pwm_enable, 3),
1483};
1484
1485static struct sensor_device_attribute sda_target_temp[] = {
1486 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1487 store_target_temp, 0),
1488 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1489 store_target_temp, 1),
1490 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1491 store_target_temp, 2),
1492 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1493 store_target_temp, 3),
1494};
1495
1496static struct sensor_device_attribute sda_tolerance[] = {
1497 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1498 store_tolerance, 0),
1499 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1500 store_tolerance, 1),
1501 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1502 store_tolerance, 2),
1503 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1504 store_tolerance, 3),
1505};
1506
Rudolf Marek08c79952006-07-05 18:14:31 +02001507/* Smart Fan registers */
1508
1509#define fan_functions(reg, REG) \
1510static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1511 char *buf) \
1512{ \
1513 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001514 struct sensor_device_attribute *sensor_attr = \
1515 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001516 int nr = sensor_attr->index; \
1517 return sprintf(buf, "%d\n", data->reg[nr]); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001518} \
Rudolf Marek08c79952006-07-05 18:14:31 +02001519static ssize_t \
1520store_##reg(struct device *dev, struct device_attribute *attr, \
1521 const char *buf, size_t count) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001522{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001523 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001524 struct sensor_device_attribute *sensor_attr = \
1525 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001526 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001527 unsigned long val; \
1528 int err; \
1529 err = strict_strtoul(buf, 10, &val); \
1530 if (err < 0) \
1531 return err; \
1532 val = SENSORS_LIMIT(val, 1, 255); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001533 mutex_lock(&data->update_lock); \
1534 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001535 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001536 mutex_unlock(&data->update_lock); \
1537 return count; \
1538}
1539
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001540fan_functions(fan_start_output, FAN_START_OUTPUT)
1541fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1542fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1543fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001544
1545#define fan_time_functions(reg, REG) \
1546static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1547 char *buf) \
1548{ \
1549 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001550 struct sensor_device_attribute *sensor_attr = \
1551 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001552 int nr = sensor_attr->index; \
1553 return sprintf(buf, "%d\n", \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001554 step_time_from_reg(data->reg[nr], \
1555 data->pwm_mode[nr])); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001556} \
1557\
1558static ssize_t \
1559store_##reg(struct device *dev, struct device_attribute *attr, \
1560 const char *buf, size_t count) \
1561{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001562 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001563 struct sensor_device_attribute *sensor_attr = \
1564 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001565 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001566 unsigned long val; \
1567 int err; \
1568 err = strict_strtoul(buf, 10, &val); \
1569 if (err < 0) \
1570 return err; \
1571 val = step_time_to_reg(val, data->pwm_mode[nr]); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001572 mutex_lock(&data->update_lock); \
1573 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001574 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001575 mutex_unlock(&data->update_lock); \
1576 return count; \
1577} \
1578
1579fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1580
David Hubbard1ea6dd32007-06-24 11:16:15 +02001581static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1582 char *buf)
1583{
1584 struct w83627ehf_data *data = dev_get_drvdata(dev);
1585
1586 return sprintf(buf, "%s\n", data->name);
1587}
1588static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001589
1590static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1591 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1592 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001593 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1594 store_fan_start_output, 3),
1595 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1596 store_fan_stop_output, 3),
1597 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1598 store_fan_max_output, 3),
1599 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1600 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001601};
1602
1603static struct sensor_device_attribute sda_sf3_arrays[] = {
1604 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1605 store_fan_stop_time, 0),
1606 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1607 store_fan_stop_time, 1),
1608 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1609 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001610 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1611 store_fan_start_output, 0),
1612 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1613 store_fan_start_output, 1),
1614 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1615 store_fan_start_output, 2),
1616 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1617 store_fan_stop_output, 0),
1618 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1619 store_fan_stop_output, 1),
1620 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1621 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001622};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001623
Guenter Roeckda2e0252010-08-14 21:08:55 +02001624
1625/*
1626 * pwm1 and pwm3 don't support max and step settings on all chips.
1627 * Need to check support while generating/removing attribute files.
1628 */
1629static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1630 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1631 store_fan_max_output, 0),
1632 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1633 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001634 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1635 store_fan_max_output, 1),
1636 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1637 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001638 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1639 store_fan_max_output, 2),
1640 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1641 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001642};
1643
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001644static ssize_t
1645show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1646{
1647 struct w83627ehf_data *data = dev_get_drvdata(dev);
1648 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1649}
1650static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1651
Jean Delvare08e7e272005-04-25 22:43:25 +02001652/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001653 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001654 */
1655
David Hubbardc18beb52006-09-24 21:04:38 +02001656static void w83627ehf_device_remove_files(struct device *dev)
1657{
1658 /* some entries in the following arrays may not have been used in
1659 * device_create_file(), but device_remove_file() will ignore them */
1660 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001661 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001662
1663 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1664 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001665 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1666 struct sensor_device_attribute *attr =
1667 &sda_sf3_max_step_arrays[i];
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001668 if (data->REG_FAN_STEP_OUTPUT &&
1669 data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
Guenter Roeckda2e0252010-08-14 21:08:55 +02001670 device_remove_file(dev, &attr->dev_attr);
1671 }
David Hubbardc18beb52006-09-24 21:04:38 +02001672 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1673 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001674 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001675 if ((i == 6) && data->in6_skip)
1676 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001677 device_remove_file(dev, &sda_in_input[i].dev_attr);
1678 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1679 device_remove_file(dev, &sda_in_min[i].dev_attr);
1680 device_remove_file(dev, &sda_in_max[i].dev_attr);
1681 }
1682 for (i = 0; i < 5; i++) {
1683 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1684 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1685 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1686 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1687 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001688 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001689 device_remove_file(dev, &sda_pwm[i].dev_attr);
1690 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1691 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1692 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1693 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1694 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08001695 for (i = 0; i < NUM_REG_TEMP; i++) {
1696 if (!(data->have_temp & (1 << i)))
Gong Juna157d062009-03-30 21:46:43 +02001697 continue;
1698 device_remove_file(dev, &sda_temp_input[i].dev_attr);
Guenter Roeckd36cf322011-02-07 15:08:54 -08001699 device_remove_file(dev, &sda_temp_label[i].dev_attr);
Gong Juna157d062009-03-30 21:46:43 +02001700 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1701 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001702 if (i > 2)
1703 continue;
Gong Juna157d062009-03-30 21:46:43 +02001704 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1705 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1706 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001707
1708 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001709 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001710}
1711
David Hubbard1ea6dd32007-06-24 11:16:15 +02001712/* Get the monitoring functions started */
1713static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001714{
1715 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001716 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001717
1718 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001719 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001720 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001721 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001722 tmp | 0x01);
1723
Guenter Roeckd36cf322011-02-07 15:08:54 -08001724 /* Enable temperature sensors if needed */
1725 for (i = 0; i < NUM_REG_TEMP; i++) {
1726 if (!(data->have_temp & (1 << i)))
1727 continue;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001728 if (!data->reg_temp_config[i])
Guenter Roeckd36cf322011-02-07 15:08:54 -08001729 continue;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001730 tmp = w83627ehf_read_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001731 data->reg_temp_config[i]);
Jean Delvare08e7e272005-04-25 22:43:25 +02001732 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001733 w83627ehf_write_value(data,
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001734 data->reg_temp_config[i],
Jean Delvare08e7e272005-04-25 22:43:25 +02001735 tmp & 0xfe);
1736 }
Jean Delvared3130f02007-06-24 11:20:13 +02001737
1738 /* Enable VBAT monitoring if needed */
1739 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1740 if (!(tmp & 0x01))
1741 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001742
1743 /* Get thermal sensor types */
1744 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1745 for (i = 0; i < 3; i++) {
1746 if ((tmp & (0x02 << i)))
1747 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1748 else
1749 data->temp_type[i] = 4; /* thermistor */
1750 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001751}
1752
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001753static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
1754 int r1, int r2)
1755{
1756 u16 tmp;
1757
1758 tmp = data->temp_src[r1];
1759 data->temp_src[r1] = data->temp_src[r2];
1760 data->temp_src[r2] = tmp;
1761
1762 tmp = data->reg_temp[r1];
1763 data->reg_temp[r1] = data->reg_temp[r2];
1764 data->reg_temp[r2] = tmp;
1765
1766 tmp = data->reg_temp_over[r1];
1767 data->reg_temp_over[r1] = data->reg_temp_over[r2];
1768 data->reg_temp_over[r2] = tmp;
1769
1770 tmp = data->reg_temp_hyst[r1];
1771 data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
1772 data->reg_temp_hyst[r2] = tmp;
1773
1774 tmp = data->reg_temp_config[r1];
1775 data->reg_temp_config[r1] = data->reg_temp_config[r2];
1776 data->reg_temp_config[r2] = tmp;
1777}
1778
David Hubbard1ea6dd32007-06-24 11:16:15 +02001779static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001780{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001781 struct device *dev = &pdev->dev;
1782 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001783 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001784 struct resource *res;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001785 u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001786 int i, err = 0;
1787
David Hubbard1ea6dd32007-06-24 11:16:15 +02001788 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1789 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001790 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001791 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1792 (unsigned long)res->start,
1793 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001794 goto exit;
1795 }
1796
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001797 data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
1798 if (!data) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001799 err = -ENOMEM;
1800 goto exit_release;
1801 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001802
David Hubbard1ea6dd32007-06-24 11:16:15 +02001803 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001804 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001805 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001806 data->name = w83627ehf_device_names[sio_data->kind];
1807 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001808
Gong Jun237c8d2f2009-03-30 21:46:42 +02001809 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1810 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001811 /* 667HG, NCT6775F, and NCT6776F have 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001812 data->pwm_num = (sio_data->kind == w83667hg
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001813 || sio_data->kind == w83667hg_b
1814 || sio_data->kind == nct6775
1815 || sio_data->kind == nct6776) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001816
Guenter Roeckd36cf322011-02-07 15:08:54 -08001817 data->have_temp = 0x07;
Gong Juna157d062009-03-30 21:46:43 +02001818 /* Check temp3 configuration bit for 667HG */
Guenter Roeckd36cf322011-02-07 15:08:54 -08001819 if (sio_data->kind == w83667hg) {
1820 u8 reg;
1821
1822 reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1823 if (reg & 0x01)
1824 data->have_temp &= ~(1 << 2);
1825 else
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001826 data->in6_skip = 1; /* either temp3 or in6 */
1827 }
1828
1829 /* Deal with temperature register setup first. */
1830 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1831 int mask = 0;
1832
1833 /*
1834 * Display temperature sensor output only if it monitors
1835 * a source other than one already reported. Always display
1836 * first three temperature registers, though.
1837 */
1838 for (i = 0; i < NUM_REG_TEMP; i++) {
1839 u8 src;
1840
1841 data->reg_temp[i] = NCT6775_REG_TEMP[i];
1842 data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
1843 data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
1844 data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
1845
1846 src = w83627ehf_read_value(data,
1847 NCT6775_REG_TEMP_SOURCE[i]);
1848 src &= 0x1f;
1849 if (src && !(mask & (1 << src))) {
1850 data->have_temp |= 1 << i;
1851 mask |= 1 << src;
1852 }
1853
1854 data->temp_src[i] = src;
1855
1856 /*
1857 * Now do some register swapping if index 0..2 don't
1858 * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
1859 * Idea is to have the first three attributes
1860 * report SYSTIN, CPUIN, and AUXIN if possible
1861 * without overriding the basic system configuration.
1862 */
1863 if (i > 0 && data->temp_src[0] != 1
1864 && data->temp_src[i] == 1)
1865 w82627ehf_swap_tempreg(data, 0, i);
1866 if (i > 1 && data->temp_src[1] != 2
1867 && data->temp_src[i] == 2)
1868 w82627ehf_swap_tempreg(data, 1, i);
1869 if (i > 2 && data->temp_src[2] != 3
1870 && data->temp_src[i] == 3)
1871 w82627ehf_swap_tempreg(data, 2, i);
1872 }
1873 if (sio_data->kind == nct6776) {
1874 /*
1875 * On NCT6776, AUXTIN and VIN3 pins are shared.
1876 * Only way to detect it is to check if AUXTIN is used
1877 * as a temperature source, and if that source is
1878 * enabled.
1879 *
1880 * If that is the case, disable in6, which reports VIN3.
1881 * Otherwise disable temp3.
1882 */
1883 if (data->temp_src[2] == 3) {
1884 u8 reg;
1885
1886 if (data->reg_temp_config[2])
1887 reg = w83627ehf_read_value(data,
1888 data->reg_temp_config[2]);
1889 else
1890 reg = 0; /* Assume AUXTIN is used */
1891
1892 if (reg & 0x01)
1893 data->have_temp &= ~(1 << 2);
1894 else
1895 data->in6_skip = 1;
1896 }
1897 }
1898
1899 data->temp_label = nct6776_temp_label;
Guenter Roeckd36cf322011-02-07 15:08:54 -08001900 } else if (sio_data->kind == w83667hg_b) {
1901 u8 reg;
1902
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001903 /*
1904 * Temperature sources are selected with bank 0, registers 0x49
1905 * and 0x4a.
1906 */
1907 for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
1908 data->reg_temp[i] = W83627EHF_REG_TEMP[i];
1909 data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
1910 data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
1911 data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
1912 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08001913 reg = w83627ehf_read_value(data, 0x4a);
1914 data->temp_src[0] = reg >> 5;
1915 reg = w83627ehf_read_value(data, 0x49);
1916 data->temp_src[1] = reg & 0x07;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001917 data->temp_src[2] = (reg >> 4) & 0x07;
Guenter Roeckd36cf322011-02-07 15:08:54 -08001918
1919 /*
1920 * W83667HG-B has another temperature register at 0x7e.
1921 * The temperature source is selected with register 0x7d.
1922 * Support it if the source differs from already reported
1923 * sources.
1924 */
1925 reg = w83627ehf_read_value(data, 0x7d);
1926 reg &= 0x07;
1927 if (reg != data->temp_src[0] && reg != data->temp_src[1]
1928 && reg != data->temp_src[2]) {
1929 data->temp_src[3] = reg;
1930 data->have_temp |= 1 << 3;
1931 }
1932
1933 /*
1934 * Chip supports either AUXTIN or VIN3. Try to find out which
1935 * one.
1936 */
1937 reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1938 if (data->temp_src[2] == 2 && (reg & 0x01))
1939 data->have_temp &= ~(1 << 2);
1940
1941 if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
1942 || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
1943 data->in6_skip = 1;
1944
1945 data->temp_label = w83667hg_b_temp_label;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001946 } else {
1947 /* Temperature sources are fixed */
1948 for (i = 0; i < 3; i++) {
1949 data->reg_temp[i] = W83627EHF_REG_TEMP[i];
1950 data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
1951 data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
1952 data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
1953 }
Gong Juna157d062009-03-30 21:46:43 +02001954 }
1955
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001956 if (sio_data->kind == nct6775) {
Guenter Roeck26bc4402011-02-11 08:00:58 -08001957 data->has_fan_div = true;
1958 data->fan_from_reg = fan_from_reg16;
1959 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001960 data->REG_PWM = NCT6775_REG_PWM;
1961 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck26bc4402011-02-11 08:00:58 -08001962 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001963 data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
1964 data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
1965 data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
1966 data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
1967 data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
1968 data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
1969 } else if (sio_data->kind == nct6776) {
Guenter Roeck26bc4402011-02-11 08:00:58 -08001970 data->has_fan_div = false;
1971 data->fan_from_reg = fan_from_reg13;
1972 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001973 data->REG_PWM = NCT6775_REG_PWM;
1974 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck26bc4402011-02-11 08:00:58 -08001975 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001976 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
1977 data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
1978 data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
1979 data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
1980 } else if (sio_data->kind == w83667hg_b) {
Guenter Roeck26bc4402011-02-11 08:00:58 -08001981 data->has_fan_div = true;
1982 data->fan_from_reg = fan_from_reg8;
1983 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001984 data->REG_PWM = W83627EHF_REG_PWM;
1985 data->REG_TARGET = W83627EHF_REG_TARGET;
1986 data->REG_FAN = W83627EHF_REG_FAN;
1987 data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
1988 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1989 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
1990 data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001991 data->REG_FAN_MAX_OUTPUT =
1992 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1993 data->REG_FAN_STEP_OUTPUT =
1994 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1995 } else {
Guenter Roeck26bc4402011-02-11 08:00:58 -08001996 data->has_fan_div = true;
1997 data->fan_from_reg = fan_from_reg8;
1998 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08001999 data->REG_PWM = W83627EHF_REG_PWM;
2000 data->REG_TARGET = W83627EHF_REG_TARGET;
2001 data->REG_FAN = W83627EHF_REG_FAN;
2002 data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
2003 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
2004 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
2005 data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02002006 data->REG_FAN_MAX_OUTPUT =
2007 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
2008 data->REG_FAN_STEP_OUTPUT =
2009 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
2010 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02002011
Jean Delvare08e7e272005-04-25 22:43:25 +02002012 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02002013 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02002014
Jean Delvarefc18d6c2007-06-24 11:19:42 +02002015 data->vrm = vid_which_vrm();
2016 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02002017 /* Read VID value */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002018 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
2019 sio_data->kind == nct6775 || sio_data->kind == nct6776) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02002020 /* W83667HG has different pins for VID input and output, so
2021 we can get the VID input values directly at logical device D
2022 0xe3. */
2023 superio_select(sio_data->sioreg, W83667HG_LD_VID);
2024 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01002025 err = device_create_file(dev, &dev_attr_cpu0_vid);
2026 if (err)
2027 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05002028 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02002029 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
2030 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
2031 /* Set VID input sensibility if needed. In theory the
2032 BIOS should have set it, but in practice it's not
2033 always the case. We only do it for the W83627EHF/EHG
2034 because the W83627DHG is more complex in this
2035 respect. */
2036 if (sio_data->kind == w83627ehf) {
2037 en_vrm10 = superio_inb(sio_data->sioreg,
2038 SIO_REG_EN_VRM10);
2039 if ((en_vrm10 & 0x08) && data->vrm == 90) {
2040 dev_warn(dev, "Setting VID input "
2041 "voltage to TTL\n");
2042 superio_outb(sio_data->sioreg,
2043 SIO_REG_EN_VRM10,
2044 en_vrm10 & ~0x08);
2045 } else if (!(en_vrm10 & 0x08)
2046 && data->vrm == 100) {
2047 dev_warn(dev, "Setting VID input "
2048 "voltage to VRM10\n");
2049 superio_outb(sio_data->sioreg,
2050 SIO_REG_EN_VRM10,
2051 en_vrm10 | 0x08);
2052 }
2053 }
2054
2055 data->vid = superio_inb(sio_data->sioreg,
2056 SIO_REG_VID_DATA);
2057 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
2058 data->vid &= 0x3f;
2059
2060 err = device_create_file(dev, &dev_attr_cpu0_vid);
2061 if (err)
2062 goto exit_release;
2063 } else {
2064 dev_info(dev, "VID pins in output mode, CPU VID not "
2065 "available\n");
2066 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02002067 }
2068
Rudolf Marek08c79952006-07-05 18:14:31 +02002069 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002070 if (sio_data->kind == nct6775) {
2071 /* On NCT6775, fan4 shares pins with the fdc interface */
2072 fan3pin = 1;
2073 fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
2074 fan4min = 0;
2075 fan5pin = 0;
2076 } else if (sio_data->kind == nct6776) {
2077 fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
2078 fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
2079 fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
2080 fan4min = fan4pin;
2081 } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
2082 fan3pin = 1;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002083 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002084 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
2085 fan4min = fan4pin;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002086 } else {
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002087 fan3pin = 1;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002088 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002089 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
2090 fan4min = fan4pin;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002091 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02002092 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02002093
Jean Delvare08e7e272005-04-25 22:43:25 +02002094 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02002095 as fan on/off switches, but fan5 control is write only :/
2096 We assume that if the serial interface is disabled, designers
2097 connected fan5 as input unless they are emitting log 1, which
2098 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02002099
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002100 data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
2101
2102 data->has_fan |= (fan3pin << 2);
2103 data->has_fan_min |= (fan3pin << 2);
2104
2105 /*
2106 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
2107 */
2108 if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
2109 data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
2110 data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
2111 } else {
2112 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
2113 if ((i & (1 << 2)) && fan4pin) {
2114 data->has_fan |= (1 << 3);
2115 data->has_fan_min |= (1 << 3);
2116 }
2117 if (!(i & (1 << 1)) && fan5pin) {
2118 data->has_fan |= (1 << 4);
2119 data->has_fan_min |= (1 << 4);
2120 }
2121 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002122
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04002123 /* Read fan clock dividers immediately */
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002124 w83627ehf_update_fan_div_common(dev, data);
2125
2126 /* Read pwm data to save original values */
2127 w83627ehf_update_pwm_common(dev, data);
2128 for (i = 0; i < data->pwm_num; i++)
2129 data->pwm_enable_orig[i] = data->pwm_enable[i];
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04002130
Guenter Roeckb84bb512011-02-13 23:01:25 -08002131 /* Read pwm data to save original values */
2132 w83627ehf_update_pwm_common(dev, data);
2133 for (i = 0; i < data->pwm_num; i++)
2134 data->pwm_enable_orig[i] = data->pwm_enable[i];
2135
Jean Delvare08e7e272005-04-25 22:43:25 +02002136 /* Register sysfs hooks */
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002137 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
2138 err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
2139 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02002140 goto exit_remove;
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002141 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002142
Guenter Roeckda2e0252010-08-14 21:08:55 +02002143 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
2144 struct sensor_device_attribute *attr =
2145 &sda_sf3_max_step_arrays[i];
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002146 if (data->REG_FAN_STEP_OUTPUT &&
2147 data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
Guenter Roeckda2e0252010-08-14 21:08:55 +02002148 err = device_create_file(dev, &attr->dev_attr);
2149 if (err)
2150 goto exit_remove;
2151 }
2152 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002153 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02002154 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02002155 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002156 err = device_create_file(dev,
2157 &sda_sf3_arrays_fan4[i].dev_attr);
2158 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02002159 goto exit_remove;
2160 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002161
Gong Juna157d062009-03-30 21:46:43 +02002162 for (i = 0; i < data->in_num; i++) {
2163 if ((i == 6) && data->in6_skip)
2164 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02002165 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
2166 || (err = device_create_file(dev,
2167 &sda_in_alarm[i].dev_attr))
2168 || (err = device_create_file(dev,
2169 &sda_in_min[i].dev_attr))
2170 || (err = device_create_file(dev,
2171 &sda_in_max[i].dev_attr)))
2172 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02002173 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01002174
Yuan Mu412fec82006-02-05 23:24:16 +01002175 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02002176 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02002177 if ((err = device_create_file(dev,
2178 &sda_fan_input[i].dev_attr))
2179 || (err = device_create_file(dev,
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002180 &sda_fan_alarm[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02002181 goto exit_remove;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002182 if (sio_data->kind != nct6776) {
2183 err = device_create_file(dev,
2184 &sda_fan_div[i].dev_attr);
2185 if (err)
2186 goto exit_remove;
2187 }
2188 if (data->has_fan_min & (1 << i)) {
2189 err = device_create_file(dev,
2190 &sda_fan_min[i].dev_attr);
2191 if (err)
2192 goto exit_remove;
2193 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02002194 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02002195 ((err = device_create_file(dev,
2196 &sda_pwm[i].dev_attr))
2197 || (err = device_create_file(dev,
2198 &sda_pwm_mode[i].dev_attr))
2199 || (err = device_create_file(dev,
2200 &sda_pwm_enable[i].dev_attr))
2201 || (err = device_create_file(dev,
2202 &sda_target_temp[i].dev_attr))
2203 || (err = device_create_file(dev,
2204 &sda_tolerance[i].dev_attr))))
2205 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02002206 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002207 }
Rudolf Marek08c79952006-07-05 18:14:31 +02002208
Guenter Roeckd36cf322011-02-07 15:08:54 -08002209 for (i = 0; i < NUM_REG_TEMP; i++) {
2210 if (!(data->have_temp & (1 << i)))
Gong Juna157d062009-03-30 21:46:43 +02002211 continue;
Guenter Roeckd36cf322011-02-07 15:08:54 -08002212 err = device_create_file(dev, &sda_temp_input[i].dev_attr);
2213 if (err)
2214 goto exit_remove;
2215 if (data->temp_label) {
2216 err = device_create_file(dev,
2217 &sda_temp_label[i].dev_attr);
2218 if (err)
2219 goto exit_remove;
2220 }
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002221 if (data->reg_temp_over[i]) {
2222 err = device_create_file(dev,
2223 &sda_temp_max[i].dev_attr);
2224 if (err)
2225 goto exit_remove;
2226 }
2227 if (data->reg_temp_hyst[i]) {
2228 err = device_create_file(dev,
2229 &sda_temp_max_hyst[i].dev_attr);
2230 if (err)
2231 goto exit_remove;
2232 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08002233 if (i > 2)
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002234 continue;
2235 if ((err = device_create_file(dev,
Gong Juna157d062009-03-30 21:46:43 +02002236 &sda_temp_alarm[i].dev_attr))
2237 || (err = device_create_file(dev,
2238 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02002239 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02002240 }
David Hubbardc18beb52006-09-24 21:04:38 +02002241
David Hubbard1ea6dd32007-06-24 11:16:15 +02002242 err = device_create_file(dev, &dev_attr_name);
2243 if (err)
2244 goto exit_remove;
2245
Tony Jones1beeffe2007-08-20 13:46:20 -07002246 data->hwmon_dev = hwmon_device_register(dev);
2247 if (IS_ERR(data->hwmon_dev)) {
2248 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02002249 goto exit_remove;
2250 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002251
2252 return 0;
2253
David Hubbardc18beb52006-09-24 21:04:38 +02002254exit_remove:
2255 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02002256 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002257 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02002258exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02002259 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02002260exit:
2261 return err;
2262}
2263
David Hubbard1ea6dd32007-06-24 11:16:15 +02002264static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02002265{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002266 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02002267
Tony Jones1beeffe2007-08-20 13:46:20 -07002268 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002269 w83627ehf_device_remove_files(&pdev->dev);
2270 release_region(data->addr, IOREGION_LENGTH);
2271 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04002272 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02002273
2274 return 0;
2275}
2276
David Hubbard1ea6dd32007-06-24 11:16:15 +02002277static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01002278 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02002279 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02002280 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01002281 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02002282 .probe = w83627ehf_probe,
2283 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02002284};
2285
David Hubbard1ea6dd32007-06-24 11:16:15 +02002286/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
2287static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
2288 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02002289{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002290 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
2291 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
2292 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02002293 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d2f2009-03-30 21:46:42 +02002294 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02002295 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002296 static const char __initdata sio_name_NCT6775[] = "NCT6775F";
2297 static const char __initdata sio_name_NCT6776[] = "NCT6776F";
David Hubbard1ea6dd32007-06-24 11:16:15 +02002298
Jean Delvare08e7e272005-04-25 22:43:25 +02002299 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02002300 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02002301
David Hubbard1ea6dd32007-06-24 11:16:15 +02002302 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02002303
Jean Delvare67b671b2007-12-06 23:13:42 +01002304 if (force_id)
2305 val = force_id;
2306 else
2307 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
2308 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01002309 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01002310 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02002311 sio_data->kind = w83627ehf;
2312 sio_name = sio_name_W83627EHF;
2313 break;
David Hubbard657c93b2007-02-14 21:15:04 +01002314 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02002315 sio_data->kind = w83627ehf;
2316 sio_name = sio_name_W83627EHG;
2317 break;
2318 case SIO_W83627DHG_ID:
2319 sio_data->kind = w83627dhg;
2320 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01002321 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02002322 case SIO_W83627DHG_P_ID:
2323 sio_data->kind = w83627dhg_p;
2324 sio_name = sio_name_W83627DHG_P;
2325 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02002326 case SIO_W83667HG_ID:
2327 sio_data->kind = w83667hg;
2328 sio_name = sio_name_W83667HG;
2329 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02002330 case SIO_W83667HG_B_ID:
2331 sio_data->kind = w83667hg_b;
2332 sio_name = sio_name_W83667HG_B;
2333 break;
Guenter Roeckec3e5a12011-02-02 08:46:49 -08002334 case SIO_NCT6775_ID:
2335 sio_data->kind = nct6775;
2336 sio_name = sio_name_NCT6775;
2337 break;
2338 case SIO_NCT6776_ID:
2339 sio_data->kind = nct6776;
2340 sio_name = sio_name_NCT6776;
2341 break;
David Hubbard657c93b2007-02-14 21:15:04 +01002342 default:
Jean Delvare9f660362007-06-24 11:23:41 +02002343 if (val != 0xffff)
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002344 pr_debug("unsupported chip ID: 0x%04x\n", val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002345 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02002346 return -ENODEV;
2347 }
2348
David Hubbard1ea6dd32007-06-24 11:16:15 +02002349 /* We have a known chip, find the HWM I/O address */
2350 superio_select(sioaddr, W83627EHF_LD_HWM);
2351 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
2352 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07002353 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02002354 if (*addr == 0) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002355 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 +02002356 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02002357 return -ENODEV;
2358 }
2359
2360 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02002361 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02002362 if (!(val & 0x01)) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002363 pr_warn("Forcibly enabling Super-I/O. "
2364 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002365 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02002366 }
Jean Delvare08e7e272005-04-25 22:43:25 +02002367
David Hubbard1ea6dd32007-06-24 11:16:15 +02002368 superio_exit(sioaddr);
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002369 pr_info("Found %s chip at %#x\n", sio_name, *addr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002370 sio_data->sioreg = sioaddr;
2371
Jean Delvare08e7e272005-04-25 22:43:25 +02002372 return 0;
2373}
2374
David Hubbard1ea6dd32007-06-24 11:16:15 +02002375/* when Super-I/O functions move to a separate file, the Super-I/O
2376 * bus will manage the lifetime of the device and this module will only keep
2377 * track of the w83627ehf driver. But since we platform_device_alloc(), we
2378 * must keep track of the device */
2379static struct platform_device *pdev;
2380
Jean Delvare08e7e272005-04-25 22:43:25 +02002381static int __init sensors_w83627ehf_init(void)
2382{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002383 int err;
2384 unsigned short address;
2385 struct resource res;
2386 struct w83627ehf_sio_data sio_data;
2387
2388 /* initialize sio_data->kind and sio_data->sioreg.
2389 *
2390 * when Super-I/O functions move to a separate file, the Super-I/O
2391 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
2392 * w83627ehf hardware monitor, and call probe() */
2393 if (w83627ehf_find(0x2e, &address, &sio_data) &&
2394 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02002395 return -ENODEV;
2396
David Hubbard1ea6dd32007-06-24 11:16:15 +02002397 err = platform_driver_register(&w83627ehf_driver);
2398 if (err)
2399 goto exit;
2400
Guenter Roecke7e1ca62011-02-04 13:24:30 -08002401 pdev = platform_device_alloc(DRVNAME, address);
2402 if (!pdev) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02002403 err = -ENOMEM;
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002404 pr_err("Device allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002405 goto exit_unregister;
2406 }
2407
2408 err = platform_device_add_data(pdev, &sio_data,
2409 sizeof(struct w83627ehf_sio_data));
2410 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002411 pr_err("Platform data allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02002412 goto exit_device_put;
2413 }
2414
2415 memset(&res, 0, sizeof(res));
2416 res.name = DRVNAME;
2417 res.start = address + IOREGION_OFFSET;
2418 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
2419 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01002420
2421 err = acpi_check_resource_conflict(&res);
2422 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002423 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002424
David Hubbard1ea6dd32007-06-24 11:16:15 +02002425 err = platform_device_add_resources(pdev, &res, 1);
2426 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002427 pr_err("Device resource addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002428 goto exit_device_put;
2429 }
2430
2431 /* platform_device_add calls probe() */
2432 err = platform_device_add(pdev);
2433 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00002434 pr_err("Device addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02002435 goto exit_device_put;
2436 }
2437
2438 return 0;
2439
2440exit_device_put:
2441 platform_device_put(pdev);
2442exit_unregister:
2443 platform_driver_unregister(&w83627ehf_driver);
2444exit:
2445 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02002446}
2447
2448static void __exit sensors_w83627ehf_exit(void)
2449{
David Hubbard1ea6dd32007-06-24 11:16:15 +02002450 platform_device_unregister(pdev);
2451 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02002452}
2453
2454MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
2455MODULE_DESCRIPTION("W83627EHF driver");
2456MODULE_LICENSE("GPL");
2457
2458module_init(sensors_w83627ehf_init);
2459module_exit(sensors_w83627ehf_exit);