blob: 66e6855f9397fcd369f43025953e5944f4eeb164 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
3 the Winbond W83627EHF Super-I/O chip
4 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Jean Delvare7188cc62006-12-12 18:18:30 +01006 Rudolf Marek <r.marek@assembler.cz>
David Hubbardc18beb52006-09-24 21:04:38 +02007 David Hubbard <david.c.hubbard@gmail.com>
Daniel J Blueman41e9a062009-12-14 18:01:37 -08008 Daniel J Blueman <daniel.blueman@gmail.com>
Jean Delvare08e7e272005-04-25 22:43:25 +02009
10 Shamelessly ripped from the w83627hf driver
11 Copyright (C) 2003 Mark Studebaker
12
13 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
14 in testing and debugging this driver.
15
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020016 This driver also supports the W83627EHG, which is the lead-free
17 version of the W83627EHF.
18
Jean Delvare08e7e272005-04-25 22:43:25 +020019 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32
33
34 Supports the following chips:
35
David Hubbard657c93b2007-02-14 21:15:04 +010036 Chip #vin #fan #pwm #temp chip IDs man ID
37 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
38 0x8860 0xa1
39 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvarec1e48dc2009-06-15 18:39:50 +020040 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
Gong Jun237c8d22009-03-30 21:46:42 +020041 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Guenter Roeckc39aeda2010-08-14 21:08:55 +020042 w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020043*/
44
Joe Perchesabdc6fd2010-10-20 06:51:54 +000045#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
46
Jean Delvare08e7e272005-04-25 22:43:25 +020047#include <linux/module.h>
48#include <linux/init.h>
49#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020050#include <linux/jiffies.h>
51#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040052#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010053#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020054#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040055#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010056#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010057#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020058#include <linux/io.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020059#include "lm75.h"
60
Guenter Roeckc39aeda2010-08-14 21:08:55 +020061enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
David Hubbard1ea6dd32007-06-24 11:16:15 +020062
63/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
64static const char * w83627ehf_device_names[] = {
65 "w83627ehf",
66 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020067 "w83627dhg",
Gong Jun237c8d22009-03-30 21:46:42 +020068 "w83667hg",
Guenter Roeckc39aeda2010-08-14 21:08:55 +020069 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020070};
71
Jean Delvare67b671b2007-12-06 23:13:42 +010072static unsigned short force_id;
73module_param(force_id, ushort, 0);
74MODULE_PARM_DESC(force_id, "Override the detected device ID");
75
David Hubbard1ea6dd32007-06-24 11:16:15 +020076#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020077
78/*
79 * Super-I/O constants and functions
80 */
81
Jean Delvare08e7e272005-04-25 22:43:25 +020082#define W83627EHF_LD_HWM 0x0b
Gong Jun237c8d22009-03-30 21:46:42 +020083#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020084
85#define SIO_REG_LDSEL 0x07 /* Logical device select */
86#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020087#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020088#define SIO_REG_ENABLE 0x30 /* Logical device enable */
89#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020090#define SIO_REG_VID_CTRL 0xF0 /* VID control */
91#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020092
David Hubbard657c93b2007-02-14 21:15:04 +010093#define SIO_W83627EHF_ID 0x8850
94#define SIO_W83627EHG_ID 0x8860
95#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +020096#define SIO_W83627DHG_P_ID 0xb070
Gong Jun237c8d22009-03-30 21:46:42 +020097#define SIO_W83667HG_ID 0xa510
Guenter Roeckc39aeda2010-08-14 21:08:55 +020098#define SIO_W83667HG_B_ID 0xb350
David Hubbard657c93b2007-02-14 21:15:04 +010099#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +0200100
101static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +0200103{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200104 outb(reg, ioreg);
105 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200106}
107
108static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200110{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200111 outb(reg, ioreg);
112 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200113}
114
115static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200117{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200118 outb(SIO_REG_LDSEL, ioreg);
119 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200120}
121
122static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200123superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200124{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200125 outb(0x87, ioreg);
126 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200127}
128
129static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200130superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200131{
Jonas Jonsson022b75a2010-09-17 17:24:13 +0200132 outb(0xaa, ioreg);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200133 outb(0x02, ioreg);
134 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200135}
136
137/*
138 * ISA constants
139 */
140
Jean Delvare1a641fc2007-04-23 14:41:16 -0700141#define IOREGION_ALIGNMENT ~7
142#define IOREGION_OFFSET 5
143#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200144#define ADDR_REG_OFFSET 0
145#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200146
147#define W83627EHF_REG_BANK 0x4E
148#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100149
150/* Not currently used:
151 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
152 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
153 * REG_MAN_ID is at port 0x4f
154 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200155
156static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
157static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
158
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100159/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
160#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
161 (0x554 + (((nr) - 7) * 2)))
162#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
163 (0x555 + (((nr) - 7) * 2)))
164#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
165 (0x550 + (nr) - 7))
166
Guenter Roeckbce26c52011-02-04 12:54:14 -0800167static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
168static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
169static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
170static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
Jean Delvare08e7e272005-04-25 22:43:25 +0200171
172/* Fan clock dividers are spread over the following five registers */
173#define W83627EHF_REG_FANDIV1 0x47
174#define W83627EHF_REG_FANDIV2 0x4B
175#define W83627EHF_REG_VBAT 0x5D
176#define W83627EHF_REG_DIODE 0x59
177#define W83627EHF_REG_SMI_OVT 0x4C
178
Jean Delvarea4589db2006-03-23 16:30:29 +0100179#define W83627EHF_REG_ALARM1 0x459
180#define W83627EHF_REG_ALARM2 0x45A
181#define W83627EHF_REG_ALARM3 0x45B
182
Rudolf Marek08c79952006-07-05 18:14:31 +0200183/* SmartFan registers */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800184#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
185#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
186
Rudolf Marek08c79952006-07-05 18:14:31 +0200187/* DC or PWM output fan configuration */
188static const u8 W83627EHF_REG_PWM_ENABLE[] = {
189 0x04, /* SYS FAN0 output mode and PWM mode */
190 0x04, /* CPU FAN0 output mode and PWM mode */
191 0x12, /* AUX FAN mode */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800192 0x62, /* CPU FAN1 mode */
Rudolf Marek08c79952006-07-05 18:14:31 +0200193};
194
195static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
196static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
197
198/* FAN Duty Cycle, be used to control */
199static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
200static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
201static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
202
Rudolf Marek08c79952006-07-05 18:14:31 +0200203/* Advanced Fan control, some values are common for all fans */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800204static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
205static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
206static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200207
208static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
209 = { 0xff, 0x67, 0xff, 0x69 };
210static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
211 = { 0xff, 0x68, 0xff, 0x6a };
212
213static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
214static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
Rudolf Marek08c79952006-07-05 18:14:31 +0200215
Guenter Roeckbce26c52011-02-04 12:54:14 -0800216static inline int is_word_sized(u16 reg)
217{
218 return (((reg & 0xff00) == 0x100
219 || (reg & 0xff00) == 0x200)
220 && ((reg & 0x00ff) == 0x50
221 || (reg & 0x00ff) == 0x53
222 || (reg & 0x00ff) == 0x55));
223}
224
Jean Delvare08e7e272005-04-25 22:43:25 +0200225/*
226 * Conversions
227 */
228
Rudolf Marek08c79952006-07-05 18:14:31 +0200229/* 1 is PWM mode, output in ms */
230static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
231{
232 return mode ? 100 * reg : 400 * reg;
233}
234
235static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
236{
237 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
238 (msec + 200) / 400), 1, 255);
239}
240
Jean Delvare08e7e272005-04-25 22:43:25 +0200241static inline unsigned int
242fan_from_reg(u8 reg, unsigned int div)
243{
244 if (reg == 0 || reg == 255)
245 return 0;
246 return 1350000U / (reg * div);
247}
248
249static inline unsigned int
250div_from_reg(u8 reg)
251{
252 return 1 << reg;
253}
254
255static inline int
Guenter Roeckbce26c52011-02-04 12:54:14 -0800256temp_from_reg(u16 reg, s16 regval)
Jean Delvare08e7e272005-04-25 22:43:25 +0200257{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800258 if (is_word_sized(reg))
259 return LM75_TEMP_FROM_REG(regval);
260 return regval * 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200261}
262
Guenter Roeckbce26c52011-02-04 12:54:14 -0800263static inline s16
264temp_to_reg(u16 reg, long temp)
Jean Delvare08e7e272005-04-25 22:43:25 +0200265{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800266 if (is_word_sized(reg))
267 return LM75_TEMP_TO_REG(temp);
268 return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
Jean Delvare08e7e272005-04-25 22:43:25 +0200269}
270
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100271/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
272
273static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
274
275static inline long in_from_reg(u8 reg, u8 nr)
276{
277 return reg * scale_in[nr];
278}
279
280static inline u8 in_to_reg(u32 val, u8 nr)
281{
282 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
283}
284
Jean Delvare08e7e272005-04-25 22:43:25 +0200285/*
286 * Data structures and manipulation thereof
287 */
288
289struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200290 int addr; /* IO base of hw monitor block */
291 const char *name;
292
Tony Jones1beeffe2007-08-20 13:46:20 -0700293 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100294 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200295
Guenter Roeckda2e0252010-08-14 21:08:55 +0200296 const u8 *REG_FAN_START_OUTPUT;
297 const u8 *REG_FAN_STOP_OUTPUT;
298 const u8 *REG_FAN_MAX_OUTPUT;
299 const u8 *REG_FAN_STEP_OUTPUT;
300
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100301 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200302 char valid; /* !=0 if following fields are valid */
303 unsigned long last_updated; /* In jiffies */
304
305 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200306 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100307 u8 in[10]; /* Register value */
308 u8 in_max[10]; /* Register value */
309 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200310 u8 fan[5];
311 u8 fan_min[5];
312 u8 fan_div[5];
313 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200314 u8 temp_type[3];
Guenter Roeckbce26c52011-02-04 12:54:14 -0800315 s16 temp[3];
316 s16 temp_max[3];
317 s16 temp_max_hyst[3];
Jean Delvarea4589db2006-03-23 16:30:29 +0100318 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200319
320 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
321 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800322 2->thermal cruise mode (also called SmartFan I)
323 3->fan speed cruise mode
324 4->variable thermal cruise (also called SmartFan III) */
Gong Jun237c8d22009-03-30 21:46:42 +0200325 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200326 u8 pwm[4];
327 u8 target_temp[4];
328 u8 tolerance[4];
329
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800330 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
331 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
332 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
333 u8 fan_max_output[4]; /* maximum fan speed */
334 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200335
336 u8 vid;
337 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200338
339 u8 temp3_disable;
340 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200341};
342
David Hubbard1ea6dd32007-06-24 11:16:15 +0200343struct w83627ehf_sio_data {
344 int sioreg;
345 enum kinds kind;
346};
347
Jean Delvare09568952007-08-11 13:57:05 +0200348/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200349static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200350{
Jean Delvare09568952007-08-11 13:57:05 +0200351 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200352 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
353 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200354 }
355}
356
Jean Delvare09568952007-08-11 13:57:05 +0200357/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200358static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200359{
360 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200361 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
362 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200363 }
364}
365
David Hubbard1ea6dd32007-06-24 11:16:15 +0200366static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200367{
Jean Delvare08e7e272005-04-25 22:43:25 +0200368 int res, word_sized = is_word_sized(reg);
369
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100370 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200371
David Hubbard1ea6dd32007-06-24 11:16:15 +0200372 w83627ehf_set_bank(data, reg);
373 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
374 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200375 if (word_sized) {
376 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200377 data->addr + ADDR_REG_OFFSET);
378 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200379 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200380 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200381
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100382 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200383
384 return res;
385}
386
David Hubbard1ea6dd32007-06-24 11:16:15 +0200387static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200388{
Jean Delvare08e7e272005-04-25 22:43:25 +0200389 int word_sized = is_word_sized(reg);
390
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100391 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200392
David Hubbard1ea6dd32007-06-24 11:16:15 +0200393 w83627ehf_set_bank(data, reg);
394 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200395 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200396 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200397 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200398 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200399 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200400 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
401 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200402
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100403 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200404 return 0;
405}
406
407/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200408static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200409{
Jean Delvare08e7e272005-04-25 22:43:25 +0200410 u8 reg;
411
412 switch (nr) {
413 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200414 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200415 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200416 /* fan5 input control bit is write only, compute the value */
417 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200418 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
419 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200420 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200421 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200422 break;
423 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200424 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200425 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200426 /* fan5 input control bit is write only, compute the value */
427 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200428 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
429 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200430 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200431 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200432 break;
433 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200434 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200435 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200436 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
437 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200438 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200439 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200440 break;
441 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200442 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200443 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200444 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
445 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200446 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200447 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200448 break;
449 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200450 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700451 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200452 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200453 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200454 break;
455 }
456}
457
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400458static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
459{
460 int i;
461
462 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
463 data->fan_div[0] = (i >> 4) & 0x03;
464 data->fan_div[1] = (i >> 6) & 0x03;
465 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
466 data->fan_div[2] = (i >> 6) & 0x03;
467 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
468 data->fan_div[0] |= (i >> 3) & 0x04;
469 data->fan_div[1] |= (i >> 4) & 0x04;
470 data->fan_div[2] |= (i >> 5) & 0x04;
471 if (data->has_fan & ((1 << 3) | (1 << 4))) {
472 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
473 data->fan_div[3] = i & 0x03;
474 data->fan_div[4] = ((i >> 2) & 0x03)
475 | ((i >> 5) & 0x04);
476 }
477 if (data->has_fan & (1 << 3)) {
478 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
479 data->fan_div[3] |= (i >> 5) & 0x04;
480 }
481}
482
Jean Delvare08e7e272005-04-25 22:43:25 +0200483static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
484{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200485 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200486 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200487 int i;
488
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100489 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200490
Jean Delvare6b3e4642007-06-24 11:19:01 +0200491 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200492 || !data->valid) {
493 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400494 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200495
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100496 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200497 for (i = 0; i < data->in_num; i++) {
498 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100499 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200500 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100501 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200502 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100503 W83627EHF_REG_IN_MAX(i));
504 }
505
Jean Delvare08e7e272005-04-25 22:43:25 +0200506 /* Measured fan speeds and limits */
507 for (i = 0; i < 5; i++) {
508 if (!(data->has_fan & (1 << i)))
509 continue;
510
David Hubbard1ea6dd32007-06-24 11:16:15 +0200511 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200512 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200513 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200514 W83627EHF_REG_FAN_MIN[i]);
515
516 /* If we failed to measure the fan speed and clock
517 divider can be increased, let's try that for next
518 time */
519 if (data->fan[i] == 0xff
520 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200521 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200522 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700523 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200524 div_from_reg(data->fan_div[i] + 1));
525 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200526 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200527 /* Preserve min limit if possible */
528 if (data->fan_min[i] >= 2
529 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200530 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200531 W83627EHF_REG_FAN_MIN[i],
532 (data->fan_min[i] /= 2));
533 }
534 }
535
Guenter Roeckda2e0252010-08-14 21:08:55 +0200536 for (i = 0; i < data->pwm_num; i++) {
537 if (!(data->has_fan & (1 << i)))
538 continue;
539
Jean Delvare77fa49d2009-01-07 16:37:35 +0100540 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200541 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200542 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200543 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200544 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200545 W83627EHF_REG_TOLERANCE[i]);
546 }
547 data->pwm_mode[i] =
548 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
549 ? 0 : 1;
550 data->pwm_enable[i] =
551 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
552 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200553 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200554 W83627EHF_REG_PWM[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800555 data->fan_start_output[i] = w83627ehf_read_value(data,
556 W83627EHF_REG_FAN_START_OUTPUT[i]);
557 data->fan_stop_output[i] = w83627ehf_read_value(data,
558 W83627EHF_REG_FAN_STOP_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200559 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200560 W83627EHF_REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200561
562 if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
563 data->fan_max_output[i] =
564 w83627ehf_read_value(data,
565 data->REG_FAN_MAX_OUTPUT[i]);
566
567 if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
568 data->fan_step_output[i] =
569 w83627ehf_read_value(data,
570 data->REG_FAN_STEP_OUTPUT[i]);
571
Rudolf Marek08c79952006-07-05 18:14:31 +0200572 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200573 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200574 W83627EHF_REG_TARGET[i]) &
575 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
576 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
577 & 0x0f;
578 }
579
Jean Delvare08e7e272005-04-25 22:43:25 +0200580 /* Measured temperatures and limits */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800581 for (i = 0; i < 3; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200582 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200583 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200584 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200585 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200586 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200587 W83627EHF_REG_TEMP_HYST[i]);
588 }
589
David Hubbard1ea6dd32007-06-24 11:16:15 +0200590 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100591 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200592 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100593 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200594 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100595 W83627EHF_REG_ALARM3) << 16);
596
Jean Delvare08e7e272005-04-25 22:43:25 +0200597 data->last_updated = jiffies;
598 data->valid = 1;
599 }
600
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100601 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200602 return data;
603}
604
605/*
606 * Sysfs callback functions
607 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100608#define show_in_reg(reg) \
609static ssize_t \
610show_##reg(struct device *dev, struct device_attribute *attr, \
611 char *buf) \
612{ \
613 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
614 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
615 int nr = sensor_attr->index; \
616 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
617}
618show_in_reg(in)
619show_in_reg(in_min)
620show_in_reg(in_max)
621
622#define store_in_reg(REG, reg) \
623static ssize_t \
624store_in_##reg (struct device *dev, struct device_attribute *attr, \
625 const char *buf, size_t count) \
626{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200627 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100628 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
629 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800630 unsigned long val; \
631 int err; \
632 err = strict_strtoul(buf, 10, &val); \
633 if (err < 0) \
634 return err; \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100635 mutex_lock(&data->update_lock); \
636 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200637 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100638 data->in_##reg[nr]); \
639 mutex_unlock(&data->update_lock); \
640 return count; \
641}
642
643store_in_reg(MIN, min)
644store_in_reg(MAX, max)
645
Jean Delvarea4589db2006-03-23 16:30:29 +0100646static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
647{
648 struct w83627ehf_data *data = w83627ehf_update_device(dev);
649 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
650 int nr = sensor_attr->index;
651 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
652}
653
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100654static struct sensor_device_attribute sda_in_input[] = {
655 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
656 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
657 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
658 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
659 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
660 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
661 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
662 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
663 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
664 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
665};
666
Jean Delvarea4589db2006-03-23 16:30:29 +0100667static struct sensor_device_attribute sda_in_alarm[] = {
668 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
669 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
670 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
671 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
672 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
673 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
674 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
675 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
676 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
677 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
678};
679
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100680static struct sensor_device_attribute sda_in_min[] = {
681 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
682 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
683 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
684 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
685 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
686 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
687 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
688 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
689 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
690 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
691};
692
693static struct sensor_device_attribute sda_in_max[] = {
694 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
695 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
696 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
697 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
698 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
699 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
700 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
701 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
702 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
703 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
704};
705
Jean Delvare08e7e272005-04-25 22:43:25 +0200706#define show_fan_reg(reg) \
707static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100708show_##reg(struct device *dev, struct device_attribute *attr, \
709 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200710{ \
711 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100712 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
713 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200714 return sprintf(buf, "%d\n", \
715 fan_from_reg(data->reg[nr], \
716 div_from_reg(data->fan_div[nr]))); \
717}
718show_fan_reg(fan);
719show_fan_reg(fan_min);
720
721static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100722show_fan_div(struct device *dev, struct device_attribute *attr,
723 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200724{
725 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100726 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
727 int nr = sensor_attr->index;
728 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200729}
730
731static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100732store_fan_min(struct device *dev, struct device_attribute *attr,
733 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200734{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200735 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100736 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
737 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800738 unsigned long val;
739 int err;
Jean Delvare08e7e272005-04-25 22:43:25 +0200740 unsigned int reg;
741 u8 new_div;
742
Guenter Roeckbce26c52011-02-04 12:54:14 -0800743 err = strict_strtoul(buf, 10, &val);
744 if (err < 0)
745 return err;
746
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100747 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200748 if (!val) {
749 /* No min limit, alarm disabled */
750 data->fan_min[nr] = 255;
751 new_div = data->fan_div[nr]; /* No change */
752 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
753 } else if ((reg = 1350000U / val) >= 128 * 255) {
754 /* Speed below this value cannot possibly be represented,
755 even with the highest divider (128) */
756 data->fan_min[nr] = 254;
757 new_div = 7; /* 128 == (1 << 7) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800758 dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
Jean Delvare08e7e272005-04-25 22:43:25 +0200759 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
760 } else if (!reg) {
761 /* Speed above this value cannot possibly be represented,
762 even with the lowest divider (1) */
763 data->fan_min[nr] = 1;
764 new_div = 0; /* 1 == (1 << 0) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800765 dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200766 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200767 } else {
768 /* Automatically pick the best divider, i.e. the one such
769 that the min limit will correspond to a register value
770 in the 96..192 range */
771 new_div = 0;
772 while (reg > 192 && new_div < 7) {
773 reg >>= 1;
774 new_div++;
775 }
776 data->fan_min[nr] = reg;
777 }
778
779 /* Write both the fan clock divider (if it changed) and the new
780 fan min (unconditionally) */
781 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200782 /* Preserve the fan speed reading */
783 if (data->fan[nr] != 0xff) {
784 if (new_div > data->fan_div[nr])
785 data->fan[nr] >>= new_div - data->fan_div[nr];
786 else if (data->fan[nr] & 0x80)
787 data->fan[nr] = 0xff;
788 else
789 data->fan[nr] <<= data->fan_div[nr] - new_div;
790 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200791
792 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
793 nr + 1, div_from_reg(data->fan_div[nr]),
794 div_from_reg(new_div));
795 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200796 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200797 /* Give the chip time to sample a new speed value */
798 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200799 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200800 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200801 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100802 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200803
804 return count;
805}
806
Yuan Mu412fec82006-02-05 23:24:16 +0100807static struct sensor_device_attribute sda_fan_input[] = {
808 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
809 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
810 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
811 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
812 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
813};
Jean Delvare08e7e272005-04-25 22:43:25 +0200814
Jean Delvarea4589db2006-03-23 16:30:29 +0100815static struct sensor_device_attribute sda_fan_alarm[] = {
816 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
817 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
818 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
819 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
820 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
821};
822
Yuan Mu412fec82006-02-05 23:24:16 +0100823static struct sensor_device_attribute sda_fan_min[] = {
824 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
825 store_fan_min, 0),
826 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
827 store_fan_min, 1),
828 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
829 store_fan_min, 2),
830 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
831 store_fan_min, 3),
832 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
833 store_fan_min, 4),
834};
Jean Delvare08e7e272005-04-25 22:43:25 +0200835
Yuan Mu412fec82006-02-05 23:24:16 +0100836static struct sensor_device_attribute sda_fan_div[] = {
837 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
838 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
839 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
840 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
841 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
842};
Jean Delvare08e7e272005-04-25 22:43:25 +0200843
Guenter Roeckbce26c52011-02-04 12:54:14 -0800844#define show_temp_reg(REG, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200845static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100846show_##reg(struct device *dev, struct device_attribute *attr, \
847 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200848{ \
849 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100850 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
851 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200852 return sprintf(buf, "%d\n", \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800853 temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200854}
Guenter Roeckbce26c52011-02-04 12:54:14 -0800855show_temp_reg(TEMP, temp);
856show_temp_reg(TEMP_OVER, temp_max);
857show_temp_reg(TEMP_HYST, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +0200858
859#define store_temp_reg(REG, reg) \
860static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100861store_##reg(struct device *dev, struct device_attribute *attr, \
862 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200863{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200864 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100865 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
866 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800867 int err; \
868 long val; \
869 err = strict_strtol(buf, 10, &val); \
870 if (err < 0) \
871 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100872 mutex_lock(&data->update_lock); \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800873 data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200874 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200875 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100876 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200877 return count; \
878}
879store_temp_reg(OVER, temp_max);
880store_temp_reg(HYST, temp_max_hyst);
881
Jean Delvareda667362007-06-24 11:21:02 +0200882static ssize_t
883show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
884{
885 struct w83627ehf_data *data = w83627ehf_update_device(dev);
886 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
887 int nr = sensor_attr->index;
888 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
889}
890
Gong Juna157d062009-03-30 21:46:43 +0200891static struct sensor_device_attribute sda_temp_input[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800892 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
893 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
894 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
Gong Juna157d062009-03-30 21:46:43 +0200895};
896
897static struct sensor_device_attribute sda_temp_max[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800898 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100899 store_temp_max, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800900 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100901 store_temp_max, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800902 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
903 store_temp_max, 2),
Gong Juna157d062009-03-30 21:46:43 +0200904};
905
906static struct sensor_device_attribute sda_temp_max_hyst[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800907 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100908 store_temp_max_hyst, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800909 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100910 store_temp_max_hyst, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800911 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
912 store_temp_max_hyst, 2),
Gong Juna157d062009-03-30 21:46:43 +0200913};
914
915static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100916 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
917 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
918 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200919};
920
921static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200922 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
923 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
924 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100925};
Jean Delvare08e7e272005-04-25 22:43:25 +0200926
Rudolf Marek08c79952006-07-05 18:14:31 +0200927#define show_pwm_reg(reg) \
928static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
929 char *buf) \
930{ \
931 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
932 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
933 int nr = sensor_attr->index; \
934 return sprintf(buf, "%d\n", data->reg[nr]); \
935}
936
937show_pwm_reg(pwm_mode)
938show_pwm_reg(pwm_enable)
939show_pwm_reg(pwm)
940
941static ssize_t
942store_pwm_mode(struct device *dev, struct device_attribute *attr,
943 const char *buf, size_t count)
944{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200945 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200946 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
947 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800948 unsigned long val;
949 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +0200950 u16 reg;
951
Guenter Roeckbce26c52011-02-04 12:54:14 -0800952 err = strict_strtoul(buf, 10, &val);
953 if (err < 0)
954 return err;
955
Rudolf Marek08c79952006-07-05 18:14:31 +0200956 if (val > 1)
957 return -EINVAL;
958 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200959 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200960 data->pwm_mode[nr] = val;
961 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
962 if (!val)
963 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200964 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200965 mutex_unlock(&data->update_lock);
966 return count;
967}
968
969static ssize_t
970store_pwm(struct device *dev, struct device_attribute *attr,
971 const char *buf, size_t count)
972{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200973 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200974 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
975 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800976 unsigned long val;
977 int err;
978
979 err = strict_strtoul(buf, 10, &val);
980 if (err < 0)
981 return err;
982
983 val = SENSORS_LIMIT(val, 0, 255);
Rudolf Marek08c79952006-07-05 18:14:31 +0200984
985 mutex_lock(&data->update_lock);
986 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200987 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200988 mutex_unlock(&data->update_lock);
989 return count;
990}
991
992static ssize_t
993store_pwm_enable(struct device *dev, struct device_attribute *attr,
994 const char *buf, size_t count)
995{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200996 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200997 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
998 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800999 unsigned long val;
1000 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001001 u16 reg;
1002
Guenter Roeckbce26c52011-02-04 12:54:14 -08001003 err = strict_strtoul(buf, 10, &val);
1004 if (err < 0)
1005 return err;
1006
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001007 if (!val || (val > 4))
Rudolf Marek08c79952006-07-05 18:14:31 +02001008 return -EINVAL;
1009 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001010 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001011 data->pwm_enable[nr] = val;
1012 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1013 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001014 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001015 mutex_unlock(&data->update_lock);
1016 return count;
1017}
1018
1019
1020#define show_tol_temp(reg) \
1021static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1022 char *buf) \
1023{ \
1024 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1025 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1026 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001027 return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001028}
1029
1030show_tol_temp(tolerance)
1031show_tol_temp(target_temp)
1032
1033static ssize_t
1034store_target_temp(struct device *dev, struct device_attribute *attr,
1035 const char *buf, size_t count)
1036{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001037 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001038 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1039 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001040 long val;
1041 int err;
1042
1043 err = strict_strtol(buf, 10, &val);
1044 if (err < 0)
1045 return err;
1046
1047 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
Rudolf Marek08c79952006-07-05 18:14:31 +02001048
1049 mutex_lock(&data->update_lock);
1050 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001051 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001052 mutex_unlock(&data->update_lock);
1053 return count;
1054}
1055
1056static ssize_t
1057store_tolerance(struct device *dev, struct device_attribute *attr,
1058 const char *buf, size_t count)
1059{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001060 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001061 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1062 int nr = sensor_attr->index;
1063 u16 reg;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001064 long val;
1065 int err;
1066
1067 err = strict_strtol(buf, 10, &val);
1068 if (err < 0)
1069 return err;
1070
Rudolf Marek08c79952006-07-05 18:14:31 +02001071 /* Limit the temp to 0C - 15C */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001072 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
Rudolf Marek08c79952006-07-05 18:14:31 +02001073
1074 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001075 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001076 data->tolerance[nr] = val;
1077 if (nr == 1)
1078 reg = (reg & 0x0f) | (val << 4);
1079 else
1080 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001081 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001082 mutex_unlock(&data->update_lock);
1083 return count;
1084}
1085
1086static struct sensor_device_attribute sda_pwm[] = {
1087 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1088 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1089 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1090 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1091};
1092
1093static struct sensor_device_attribute sda_pwm_mode[] = {
1094 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1095 store_pwm_mode, 0),
1096 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1097 store_pwm_mode, 1),
1098 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1099 store_pwm_mode, 2),
1100 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1101 store_pwm_mode, 3),
1102};
1103
1104static struct sensor_device_attribute sda_pwm_enable[] = {
1105 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1106 store_pwm_enable, 0),
1107 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1108 store_pwm_enable, 1),
1109 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1110 store_pwm_enable, 2),
1111 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1112 store_pwm_enable, 3),
1113};
1114
1115static struct sensor_device_attribute sda_target_temp[] = {
1116 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1117 store_target_temp, 0),
1118 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1119 store_target_temp, 1),
1120 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1121 store_target_temp, 2),
1122 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1123 store_target_temp, 3),
1124};
1125
1126static struct sensor_device_attribute sda_tolerance[] = {
1127 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1128 store_tolerance, 0),
1129 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1130 store_tolerance, 1),
1131 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1132 store_tolerance, 2),
1133 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1134 store_tolerance, 3),
1135};
1136
Rudolf Marek08c79952006-07-05 18:14:31 +02001137/* Smart Fan registers */
1138
1139#define fan_functions(reg, REG) \
1140static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1141 char *buf) \
1142{ \
1143 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1144 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1145 int nr = sensor_attr->index; \
1146 return sprintf(buf, "%d\n", data->reg[nr]); \
1147}\
1148static ssize_t \
1149store_##reg(struct device *dev, struct device_attribute *attr, \
1150 const char *buf, size_t count) \
1151{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001152 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001153 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1154 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001155 unsigned long val; \
1156 int err; \
1157 err = strict_strtoul(buf, 10, &val); \
1158 if (err < 0) \
1159 return err; \
1160 val = SENSORS_LIMIT(val, 1, 255); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001161 mutex_lock(&data->update_lock); \
1162 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001163 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001164 mutex_unlock(&data->update_lock); \
1165 return count; \
1166}
1167
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001168fan_functions(fan_start_output, FAN_START_OUTPUT)
1169fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1170fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1171fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001172
1173#define fan_time_functions(reg, REG) \
1174static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1175 char *buf) \
1176{ \
1177 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1178 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1179 int nr = sensor_attr->index; \
1180 return sprintf(buf, "%d\n", \
1181 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1182} \
1183\
1184static ssize_t \
1185store_##reg(struct device *dev, struct device_attribute *attr, \
1186 const char *buf, size_t count) \
1187{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001188 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001189 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1190 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001191 unsigned long val; \
1192 int err; \
1193 err = strict_strtoul(buf, 10, &val); \
1194 if (err < 0) \
1195 return err; \
1196 val = step_time_to_reg(val, data->pwm_mode[nr]); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001197 mutex_lock(&data->update_lock); \
1198 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001199 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001200 mutex_unlock(&data->update_lock); \
1201 return count; \
1202} \
1203
1204fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1205
David Hubbard1ea6dd32007-06-24 11:16:15 +02001206static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1207 char *buf)
1208{
1209 struct w83627ehf_data *data = dev_get_drvdata(dev);
1210
1211 return sprintf(buf, "%s\n", data->name);
1212}
1213static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001214
1215static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1216 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1217 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001218 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1219 store_fan_start_output, 3),
1220 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1221 store_fan_stop_output, 3),
1222 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1223 store_fan_max_output, 3),
1224 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1225 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001226};
1227
1228static struct sensor_device_attribute sda_sf3_arrays[] = {
1229 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1230 store_fan_stop_time, 0),
1231 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1232 store_fan_stop_time, 1),
1233 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1234 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001235 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1236 store_fan_start_output, 0),
1237 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1238 store_fan_start_output, 1),
1239 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1240 store_fan_start_output, 2),
1241 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1242 store_fan_stop_output, 0),
1243 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1244 store_fan_stop_output, 1),
1245 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1246 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001247};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001248
Guenter Roeckda2e0252010-08-14 21:08:55 +02001249
1250/*
1251 * pwm1 and pwm3 don't support max and step settings on all chips.
1252 * Need to check support while generating/removing attribute files.
1253 */
1254static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1255 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1256 store_fan_max_output, 0),
1257 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1258 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001259 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1260 store_fan_max_output, 1),
1261 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1262 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001263 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1264 store_fan_max_output, 2),
1265 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1266 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001267};
1268
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001269static ssize_t
1270show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1271{
1272 struct w83627ehf_data *data = dev_get_drvdata(dev);
1273 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1274}
1275static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1276
Jean Delvare08e7e272005-04-25 22:43:25 +02001277/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001278 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001279 */
1280
David Hubbardc18beb52006-09-24 21:04:38 +02001281static void w83627ehf_device_remove_files(struct device *dev)
1282{
1283 /* some entries in the following arrays may not have been used in
1284 * device_create_file(), but device_remove_file() will ignore them */
1285 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001286 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001287
1288 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1289 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001290 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1291 struct sensor_device_attribute *attr =
1292 &sda_sf3_max_step_arrays[i];
1293 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1294 device_remove_file(dev, &attr->dev_attr);
1295 }
David Hubbardc18beb52006-09-24 21:04:38 +02001296 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1297 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001298 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001299 if ((i == 6) && data->in6_skip)
1300 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001301 device_remove_file(dev, &sda_in_input[i].dev_attr);
1302 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1303 device_remove_file(dev, &sda_in_min[i].dev_attr);
1304 device_remove_file(dev, &sda_in_max[i].dev_attr);
1305 }
1306 for (i = 0; i < 5; i++) {
1307 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1308 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1309 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1310 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1311 }
Gong Jun237c8d22009-03-30 21:46:42 +02001312 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001313 device_remove_file(dev, &sda_pwm[i].dev_attr);
1314 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1315 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1316 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1317 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1318 }
Gong Juna157d062009-03-30 21:46:43 +02001319 for (i = 0; i < 3; i++) {
1320 if ((i == 2) && data->temp3_disable)
1321 continue;
1322 device_remove_file(dev, &sda_temp_input[i].dev_attr);
1323 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1324 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1325 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1326 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1327 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001328
1329 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001330 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001331}
1332
David Hubbard1ea6dd32007-06-24 11:16:15 +02001333/* Get the monitoring functions started */
1334static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001335{
1336 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001337 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001338
1339 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001340 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001341 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001342 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001343 tmp | 0x01);
1344
1345 /* Enable temp2 and temp3 if needed */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001346 for (i = 1; i < 3; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001347 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001348 W83627EHF_REG_TEMP_CONFIG[i]);
Guenter Roeckbce26c52011-02-04 12:54:14 -08001349 if ((i == 2) && data->temp3_disable)
Gong Juna157d062009-03-30 21:46:43 +02001350 continue;
Jean Delvare08e7e272005-04-25 22:43:25 +02001351 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001352 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001353 W83627EHF_REG_TEMP_CONFIG[i],
1354 tmp & 0xfe);
1355 }
Jean Delvared3130f02007-06-24 11:20:13 +02001356
1357 /* Enable VBAT monitoring if needed */
1358 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1359 if (!(tmp & 0x01))
1360 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001361
1362 /* Get thermal sensor types */
1363 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1364 for (i = 0; i < 3; i++) {
1365 if ((tmp & (0x02 << i)))
1366 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1367 else
1368 data->temp_type[i] = 4; /* thermistor */
1369 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001370}
1371
David Hubbard1ea6dd32007-06-24 11:16:15 +02001372static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001373{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001374 struct device *dev = &pdev->dev;
1375 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001376 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001377 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001378 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001379 int i, err = 0;
1380
David Hubbard1ea6dd32007-06-24 11:16:15 +02001381 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1382 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001383 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001384 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1385 (unsigned long)res->start,
1386 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001387 goto exit;
1388 }
1389
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001390 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001391 err = -ENOMEM;
1392 goto exit_release;
1393 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001394
David Hubbard1ea6dd32007-06-24 11:16:15 +02001395 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001396 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001397 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001398 data->name = w83627ehf_device_names[sio_data->kind];
1399 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001400
Gong Jun237c8d22009-03-30 21:46:42 +02001401 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1402 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1403 /* 667HG has 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001404 data->pwm_num = (sio_data->kind == w83667hg
1405 || sio_data->kind == w83667hg_b) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001406
Gong Juna157d062009-03-30 21:46:43 +02001407 /* Check temp3 configuration bit for 667HG */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001408 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Juna157d062009-03-30 21:46:43 +02001409 data->temp3_disable = w83627ehf_read_value(data,
Guenter Roeckbce26c52011-02-04 12:54:14 -08001410 W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
Gong Juna157d062009-03-30 21:46:43 +02001411 data->in6_skip = !data->temp3_disable;
1412 }
1413
Guenter Roeckda2e0252010-08-14 21:08:55 +02001414 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1415 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001416 if (sio_data->kind == w83667hg_b) {
1417 data->REG_FAN_MAX_OUTPUT =
1418 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1419 data->REG_FAN_STEP_OUTPUT =
1420 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1421 } else {
1422 data->REG_FAN_MAX_OUTPUT =
1423 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1424 data->REG_FAN_STEP_OUTPUT =
1425 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1426 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001427
Jean Delvare08e7e272005-04-25 22:43:25 +02001428 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001429 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001430
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001431 data->vrm = vid_which_vrm();
1432 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001433 /* Read VID value */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001434 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d22009-03-30 21:46:42 +02001435 /* W83667HG has different pins for VID input and output, so
1436 we can get the VID input values directly at logical device D
1437 0xe3. */
1438 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1439 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001440 err = device_create_file(dev, &dev_attr_cpu0_vid);
1441 if (err)
1442 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001443 } else {
Gong Jun237c8d22009-03-30 21:46:42 +02001444 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1445 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1446 /* Set VID input sensibility if needed. In theory the
1447 BIOS should have set it, but in practice it's not
1448 always the case. We only do it for the W83627EHF/EHG
1449 because the W83627DHG is more complex in this
1450 respect. */
1451 if (sio_data->kind == w83627ehf) {
1452 en_vrm10 = superio_inb(sio_data->sioreg,
1453 SIO_REG_EN_VRM10);
1454 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1455 dev_warn(dev, "Setting VID input "
1456 "voltage to TTL\n");
1457 superio_outb(sio_data->sioreg,
1458 SIO_REG_EN_VRM10,
1459 en_vrm10 & ~0x08);
1460 } else if (!(en_vrm10 & 0x08)
1461 && data->vrm == 100) {
1462 dev_warn(dev, "Setting VID input "
1463 "voltage to VRM10\n");
1464 superio_outb(sio_data->sioreg,
1465 SIO_REG_EN_VRM10,
1466 en_vrm10 | 0x08);
1467 }
1468 }
1469
1470 data->vid = superio_inb(sio_data->sioreg,
1471 SIO_REG_VID_DATA);
1472 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1473 data->vid &= 0x3f;
1474
1475 err = device_create_file(dev, &dev_attr_cpu0_vid);
1476 if (err)
1477 goto exit_release;
1478 } else {
1479 dev_info(dev, "VID pins in output mode, CPU VID not "
1480 "available\n");
1481 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001482 }
1483
Rudolf Marek08c79952006-07-05 18:14:31 +02001484 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001485 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d22009-03-30 21:46:42 +02001486 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1487 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1488 } else {
1489 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1490 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1491 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001492 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001493
Jean Delvare08e7e272005-04-25 22:43:25 +02001494 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001495 as fan on/off switches, but fan5 control is write only :/
1496 We assume that if the serial interface is disabled, designers
1497 connected fan5 as input unless they are emitting log 1, which
1498 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001499
Jean Delvare08e7e272005-04-25 22:43:25 +02001500 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001501 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001502 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001503 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001504 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001505 data->has_fan |= (1 << 4);
1506
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001507 /* Read fan clock dividers immediately */
1508 w83627ehf_update_fan_div(data);
1509
Jean Delvare08e7e272005-04-25 22:43:25 +02001510 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001511 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001512 if ((err = device_create_file(dev,
1513 &sda_sf3_arrays[i].dev_attr)))
1514 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001515
Guenter Roeckda2e0252010-08-14 21:08:55 +02001516 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1517 struct sensor_device_attribute *attr =
1518 &sda_sf3_max_step_arrays[i];
1519 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
1520 err = device_create_file(dev, &attr->dev_attr);
1521 if (err)
1522 goto exit_remove;
1523 }
1524 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001525 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d22009-03-30 21:46:42 +02001526 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001527 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1528 if ((err = device_create_file(dev,
1529 &sda_sf3_arrays_fan4[i].dev_attr)))
1530 goto exit_remove;
1531 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001532
Gong Juna157d062009-03-30 21:46:43 +02001533 for (i = 0; i < data->in_num; i++) {
1534 if ((i == 6) && data->in6_skip)
1535 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001536 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1537 || (err = device_create_file(dev,
1538 &sda_in_alarm[i].dev_attr))
1539 || (err = device_create_file(dev,
1540 &sda_in_min[i].dev_attr))
1541 || (err = device_create_file(dev,
1542 &sda_in_max[i].dev_attr)))
1543 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001544 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001545
Yuan Mu412fec82006-02-05 23:24:16 +01001546 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001547 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001548 if ((err = device_create_file(dev,
1549 &sda_fan_input[i].dev_attr))
1550 || (err = device_create_file(dev,
1551 &sda_fan_alarm[i].dev_attr))
1552 || (err = device_create_file(dev,
1553 &sda_fan_div[i].dev_attr))
1554 || (err = device_create_file(dev,
1555 &sda_fan_min[i].dev_attr)))
1556 goto exit_remove;
Gong Jun237c8d22009-03-30 21:46:42 +02001557 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001558 ((err = device_create_file(dev,
1559 &sda_pwm[i].dev_attr))
1560 || (err = device_create_file(dev,
1561 &sda_pwm_mode[i].dev_attr))
1562 || (err = device_create_file(dev,
1563 &sda_pwm_enable[i].dev_attr))
1564 || (err = device_create_file(dev,
1565 &sda_target_temp[i].dev_attr))
1566 || (err = device_create_file(dev,
1567 &sda_tolerance[i].dev_attr))))
1568 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001569 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001570 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001571
Gong Juna157d062009-03-30 21:46:43 +02001572 for (i = 0; i < 3; i++) {
1573 if ((i == 2) && data->temp3_disable)
1574 continue;
1575 if ((err = device_create_file(dev,
1576 &sda_temp_input[i].dev_attr))
1577 || (err = device_create_file(dev,
1578 &sda_temp_max[i].dev_attr))
1579 || (err = device_create_file(dev,
1580 &sda_temp_max_hyst[i].dev_attr))
1581 || (err = device_create_file(dev,
1582 &sda_temp_alarm[i].dev_attr))
1583 || (err = device_create_file(dev,
1584 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001585 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001586 }
David Hubbardc18beb52006-09-24 21:04:38 +02001587
David Hubbard1ea6dd32007-06-24 11:16:15 +02001588 err = device_create_file(dev, &dev_attr_name);
1589 if (err)
1590 goto exit_remove;
1591
Tony Jones1beeffe2007-08-20 13:46:20 -07001592 data->hwmon_dev = hwmon_device_register(dev);
1593 if (IS_ERR(data->hwmon_dev)) {
1594 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001595 goto exit_remove;
1596 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001597
1598 return 0;
1599
David Hubbardc18beb52006-09-24 21:04:38 +02001600exit_remove:
1601 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001602 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001603 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001604exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001605 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001606exit:
1607 return err;
1608}
1609
David Hubbard1ea6dd32007-06-24 11:16:15 +02001610static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001611{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001612 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001613
Tony Jones1beeffe2007-08-20 13:46:20 -07001614 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001615 w83627ehf_device_remove_files(&pdev->dev);
1616 release_region(data->addr, IOREGION_LENGTH);
1617 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001618 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001619
1620 return 0;
1621}
1622
David Hubbard1ea6dd32007-06-24 11:16:15 +02001623static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001624 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001625 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001626 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001627 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001628 .probe = w83627ehf_probe,
1629 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001630};
1631
David Hubbard1ea6dd32007-06-24 11:16:15 +02001632/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1633static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1634 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001635{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001636 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1637 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1638 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001639 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d22009-03-30 21:46:42 +02001640 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001641 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001642
Jean Delvare08e7e272005-04-25 22:43:25 +02001643 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001644 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001645
David Hubbard1ea6dd32007-06-24 11:16:15 +02001646 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001647
Jean Delvare67b671b2007-12-06 23:13:42 +01001648 if (force_id)
1649 val = force_id;
1650 else
1651 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1652 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001653 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001654 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001655 sio_data->kind = w83627ehf;
1656 sio_name = sio_name_W83627EHF;
1657 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001658 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001659 sio_data->kind = w83627ehf;
1660 sio_name = sio_name_W83627EHG;
1661 break;
1662 case SIO_W83627DHG_ID:
1663 sio_data->kind = w83627dhg;
1664 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001665 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001666 case SIO_W83627DHG_P_ID:
1667 sio_data->kind = w83627dhg_p;
1668 sio_name = sio_name_W83627DHG_P;
1669 break;
Gong Jun237c8d22009-03-30 21:46:42 +02001670 case SIO_W83667HG_ID:
1671 sio_data->kind = w83667hg;
1672 sio_name = sio_name_W83667HG;
1673 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001674 case SIO_W83667HG_B_ID:
1675 sio_data->kind = w83667hg_b;
1676 sio_name = sio_name_W83667HG_B;
1677 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001678 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001679 if (val != 0xffff)
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001680 pr_debug("unsupported chip ID: 0x%04x\n", val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001681 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001682 return -ENODEV;
1683 }
1684
David Hubbard1ea6dd32007-06-24 11:16:15 +02001685 /* We have a known chip, find the HWM I/O address */
1686 superio_select(sioaddr, W83627EHF_LD_HWM);
1687 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1688 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001689 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001690 if (*addr == 0) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001691 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 +02001692 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001693 return -ENODEV;
1694 }
1695
1696 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001697 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001698 if (!(val & 0x01)) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001699 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001700 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001701 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001702
David Hubbard1ea6dd32007-06-24 11:16:15 +02001703 superio_exit(sioaddr);
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001704 pr_info("Found %s chip at %#x\n", sio_name, *addr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001705 sio_data->sioreg = sioaddr;
1706
Jean Delvare08e7e272005-04-25 22:43:25 +02001707 return 0;
1708}
1709
David Hubbard1ea6dd32007-06-24 11:16:15 +02001710/* when Super-I/O functions move to a separate file, the Super-I/O
1711 * bus will manage the lifetime of the device and this module will only keep
1712 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1713 * must keep track of the device */
1714static struct platform_device *pdev;
1715
Jean Delvare08e7e272005-04-25 22:43:25 +02001716static int __init sensors_w83627ehf_init(void)
1717{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001718 int err;
1719 unsigned short address;
1720 struct resource res;
1721 struct w83627ehf_sio_data sio_data;
1722
1723 /* initialize sio_data->kind and sio_data->sioreg.
1724 *
1725 * when Super-I/O functions move to a separate file, the Super-I/O
1726 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1727 * w83627ehf hardware monitor, and call probe() */
1728 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1729 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001730 return -ENODEV;
1731
David Hubbard1ea6dd32007-06-24 11:16:15 +02001732 err = platform_driver_register(&w83627ehf_driver);
1733 if (err)
1734 goto exit;
1735
1736 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1737 err = -ENOMEM;
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001738 pr_err("Device allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001739 goto exit_unregister;
1740 }
1741
1742 err = platform_device_add_data(pdev, &sio_data,
1743 sizeof(struct w83627ehf_sio_data));
1744 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001745 pr_err("Platform data allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001746 goto exit_device_put;
1747 }
1748
1749 memset(&res, 0, sizeof(res));
1750 res.name = DRVNAME;
1751 res.start = address + IOREGION_OFFSET;
1752 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1753 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001754
1755 err = acpi_check_resource_conflict(&res);
1756 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001757 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001758
David Hubbard1ea6dd32007-06-24 11:16:15 +02001759 err = platform_device_add_resources(pdev, &res, 1);
1760 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001761 pr_err("Device resource addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001762 goto exit_device_put;
1763 }
1764
1765 /* platform_device_add calls probe() */
1766 err = platform_device_add(pdev);
1767 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001768 pr_err("Device addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001769 goto exit_device_put;
1770 }
1771
1772 return 0;
1773
1774exit_device_put:
1775 platform_device_put(pdev);
1776exit_unregister:
1777 platform_driver_unregister(&w83627ehf_driver);
1778exit:
1779 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001780}
1781
1782static void __exit sensors_w83627ehf_exit(void)
1783{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001784 platform_device_unregister(pdev);
1785 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001786}
1787
1788MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1789MODULE_DESCRIPTION("W83627EHF driver");
1790MODULE_LICENSE("GPL");
1791
1792module_init(sensors_w83627ehf_init);
1793module_exit(sensors_w83627ehf_exit);