blob: 075164dd65a7a6716965538ac56d7b0320e14541 [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>
Jean Delvare08e7e272005-04-25 22:43:25 +02008
9 Shamelessly ripped from the w83627hf driver
10 Copyright (C) 2003 Mark Studebaker
11
12 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
13 in testing and debugging this driver.
14
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020015 This driver also supports the W83627EHG, which is the lead-free
16 version of the W83627EHF.
17
Jean Delvare08e7e272005-04-25 22:43:25 +020018 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
32
33 Supports the following chips:
34
David Hubbard657c93b2007-02-14 21:15:04 +010035 Chip #vin #fan #pwm #temp chip IDs man ID
36 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
37 0x8860 0xa1
38 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020039*/
40
41#include <linux/module.h>
42#include <linux/init.h>
43#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020044#include <linux/jiffies.h>
45#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040046#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010047#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020048#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040049#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010050#include <linux/mutex.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020051#include <asm/io.h>
52#include "lm75.h"
53
David Hubbard1ea6dd32007-06-24 11:16:15 +020054enum kinds { w83627ehf, w83627dhg };
55
56/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
57static const char * w83627ehf_device_names[] = {
58 "w83627ehf",
59 "w83627dhg",
60};
61
Jean Delvare67b671b2007-12-06 23:13:42 +010062static unsigned short force_id;
63module_param(force_id, ushort, 0);
64MODULE_PARM_DESC(force_id, "Override the detected device ID");
65
David Hubbard1ea6dd32007-06-24 11:16:15 +020066#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020067
68/*
69 * Super-I/O constants and functions
70 */
71
Jean Delvare08e7e272005-04-25 22:43:25 +020072#define W83627EHF_LD_HWM 0x0b
73
74#define SIO_REG_LDSEL 0x07 /* Logical device select */
75#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020076#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020077#define SIO_REG_ENABLE 0x30 /* Logical device enable */
78#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020079#define SIO_REG_VID_CTRL 0xF0 /* VID control */
80#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020081
David Hubbard657c93b2007-02-14 21:15:04 +010082#define SIO_W83627EHF_ID 0x8850
83#define SIO_W83627EHG_ID 0x8860
84#define SIO_W83627DHG_ID 0xa020
85#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +020086
87static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +020088superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +020089{
David Hubbard1ea6dd32007-06-24 11:16:15 +020090 outb(reg, ioreg);
91 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +020092}
93
94static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +020095superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +020096{
David Hubbard1ea6dd32007-06-24 11:16:15 +020097 outb(reg, ioreg);
98 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +020099}
100
101static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200103{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200104 outb(SIO_REG_LDSEL, ioreg);
105 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200106}
107
108static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200110{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200111 outb(0x87, ioreg);
112 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200113}
114
115static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200117{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200118 outb(0x02, ioreg);
119 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200120}
121
122/*
123 * ISA constants
124 */
125
Jean Delvare1a641fc2007-04-23 14:41:16 -0700126#define IOREGION_ALIGNMENT ~7
127#define IOREGION_OFFSET 5
128#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200129#define ADDR_REG_OFFSET 0
130#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200131
132#define W83627EHF_REG_BANK 0x4E
133#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100134
135/* Not currently used:
136 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
137 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
138 * REG_MAN_ID is at port 0x4f
139 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200140
141static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
142static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
143
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100144/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
145#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
146 (0x554 + (((nr) - 7) * 2)))
147#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
148 (0x555 + (((nr) - 7) * 2)))
149#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
150 (0x550 + (nr) - 7))
151
Jean Delvare08e7e272005-04-25 22:43:25 +0200152#define W83627EHF_REG_TEMP1 0x27
153#define W83627EHF_REG_TEMP1_HYST 0x3a
154#define W83627EHF_REG_TEMP1_OVER 0x39
155static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
156static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
157static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
158static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
159
160/* Fan clock dividers are spread over the following five registers */
161#define W83627EHF_REG_FANDIV1 0x47
162#define W83627EHF_REG_FANDIV2 0x4B
163#define W83627EHF_REG_VBAT 0x5D
164#define W83627EHF_REG_DIODE 0x59
165#define W83627EHF_REG_SMI_OVT 0x4C
166
Jean Delvarea4589db2006-03-23 16:30:29 +0100167#define W83627EHF_REG_ALARM1 0x459
168#define W83627EHF_REG_ALARM2 0x45A
169#define W83627EHF_REG_ALARM3 0x45B
170
Rudolf Marek08c79952006-07-05 18:14:31 +0200171/* SmartFan registers */
172/* DC or PWM output fan configuration */
173static const u8 W83627EHF_REG_PWM_ENABLE[] = {
174 0x04, /* SYS FAN0 output mode and PWM mode */
175 0x04, /* CPU FAN0 output mode and PWM mode */
176 0x12, /* AUX FAN mode */
177 0x62, /* CPU fan1 mode */
178};
179
180static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
181static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
182
183/* FAN Duty Cycle, be used to control */
184static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
185static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
186static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
187
188
189/* Advanced Fan control, some values are common for all fans */
190static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
191static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
192
Jean Delvare08e7e272005-04-25 22:43:25 +0200193/*
194 * Conversions
195 */
196
Rudolf Marek08c79952006-07-05 18:14:31 +0200197/* 1 is PWM mode, output in ms */
198static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
199{
200 return mode ? 100 * reg : 400 * reg;
201}
202
203static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
204{
205 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
206 (msec + 200) / 400), 1, 255);
207}
208
Jean Delvare08e7e272005-04-25 22:43:25 +0200209static inline unsigned int
210fan_from_reg(u8 reg, unsigned int div)
211{
212 if (reg == 0 || reg == 255)
213 return 0;
214 return 1350000U / (reg * div);
215}
216
217static inline unsigned int
218div_from_reg(u8 reg)
219{
220 return 1 << reg;
221}
222
223static inline int
224temp1_from_reg(s8 reg)
225{
226 return reg * 1000;
227}
228
229static inline s8
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200230temp1_to_reg(long temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200231{
Rudolf Marek08c79952006-07-05 18:14:31 +0200232 if (temp <= min)
233 return min / 1000;
234 if (temp >= max)
235 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200236 if (temp < 0)
237 return (temp - 500) / 1000;
238 return (temp + 500) / 1000;
239}
240
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100241/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
242
243static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
244
245static inline long in_from_reg(u8 reg, u8 nr)
246{
247 return reg * scale_in[nr];
248}
249
250static inline u8 in_to_reg(u32 val, u8 nr)
251{
252 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
253}
254
Jean Delvare08e7e272005-04-25 22:43:25 +0200255/*
256 * Data structures and manipulation thereof
257 */
258
259struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200260 int addr; /* IO base of hw monitor block */
261 const char *name;
262
Tony Jones1beeffe2007-08-20 13:46:20 -0700263 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100264 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200265
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100266 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200267 char valid; /* !=0 if following fields are valid */
268 unsigned long last_updated; /* In jiffies */
269
270 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200271 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100272 u8 in[10]; /* Register value */
273 u8 in_max[10]; /* Register value */
274 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200275 u8 fan[5];
276 u8 fan_min[5];
277 u8 fan_div[5];
278 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200279 u8 temp_type[3];
Jean Delvare08e7e272005-04-25 22:43:25 +0200280 s8 temp1;
281 s8 temp1_max;
282 s8 temp1_max_hyst;
283 s16 temp[2];
284 s16 temp_max[2];
285 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100286 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200287
288 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
289 u8 pwm_enable[4]; /* 1->manual
290 2->thermal cruise (also called SmartFan I) */
291 u8 pwm[4];
292 u8 target_temp[4];
293 u8 tolerance[4];
294
295 u8 fan_min_output[4]; /* minimum fan speed */
296 u8 fan_stop_time[4];
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200297
298 u8 vid;
299 u8 vrm;
Jean Delvare08e7e272005-04-25 22:43:25 +0200300};
301
David Hubbard1ea6dd32007-06-24 11:16:15 +0200302struct w83627ehf_sio_data {
303 int sioreg;
304 enum kinds kind;
305};
306
Jean Delvare08e7e272005-04-25 22:43:25 +0200307static inline int is_word_sized(u16 reg)
308{
309 return (((reg & 0xff00) == 0x100
310 || (reg & 0xff00) == 0x200)
311 && ((reg & 0x00ff) == 0x50
312 || (reg & 0x00ff) == 0x53
313 || (reg & 0x00ff) == 0x55));
314}
315
Jean Delvare09568952007-08-11 13:57:05 +0200316/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200317static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200318{
Jean Delvare09568952007-08-11 13:57:05 +0200319 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200320 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
321 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200322 }
323}
324
Jean Delvare09568952007-08-11 13:57:05 +0200325/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200326static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200327{
328 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200329 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
330 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200331 }
332}
333
David Hubbard1ea6dd32007-06-24 11:16:15 +0200334static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200335{
Jean Delvare08e7e272005-04-25 22:43:25 +0200336 int res, word_sized = is_word_sized(reg);
337
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100338 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200339
David Hubbard1ea6dd32007-06-24 11:16:15 +0200340 w83627ehf_set_bank(data, reg);
341 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
342 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200343 if (word_sized) {
344 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200345 data->addr + ADDR_REG_OFFSET);
346 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200347 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200348 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200349
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100350 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200351
352 return res;
353}
354
David Hubbard1ea6dd32007-06-24 11:16:15 +0200355static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200356{
Jean Delvare08e7e272005-04-25 22:43:25 +0200357 int word_sized = is_word_sized(reg);
358
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100359 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200360
David Hubbard1ea6dd32007-06-24 11:16:15 +0200361 w83627ehf_set_bank(data, reg);
362 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200363 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200364 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200365 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200366 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200367 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200368 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
369 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200370
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100371 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200372 return 0;
373}
374
375/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200376static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200377{
Jean Delvare08e7e272005-04-25 22:43:25 +0200378 u8 reg;
379
380 switch (nr) {
381 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200382 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200383 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200384 /* fan5 input control bit is write only, compute the value */
385 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200386 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
387 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200388 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200389 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200390 break;
391 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200392 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200393 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200394 /* fan5 input control bit is write only, compute the value */
395 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200396 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
397 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200398 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200399 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200400 break;
401 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200402 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200403 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200404 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
405 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200406 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200407 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200408 break;
409 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200410 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200411 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200412 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
413 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200414 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200415 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200416 break;
417 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200418 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700419 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200420 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200421 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200422 break;
423 }
424}
425
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400426static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
427{
428 int i;
429
430 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
431 data->fan_div[0] = (i >> 4) & 0x03;
432 data->fan_div[1] = (i >> 6) & 0x03;
433 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
434 data->fan_div[2] = (i >> 6) & 0x03;
435 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
436 data->fan_div[0] |= (i >> 3) & 0x04;
437 data->fan_div[1] |= (i >> 4) & 0x04;
438 data->fan_div[2] |= (i >> 5) & 0x04;
439 if (data->has_fan & ((1 << 3) | (1 << 4))) {
440 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
441 data->fan_div[3] = i & 0x03;
442 data->fan_div[4] = ((i >> 2) & 0x03)
443 | ((i >> 5) & 0x04);
444 }
445 if (data->has_fan & (1 << 3)) {
446 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
447 data->fan_div[3] |= (i >> 5) & 0x04;
448 }
449}
450
Jean Delvare08e7e272005-04-25 22:43:25 +0200451static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
452{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200453 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200454 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200455 int i;
456
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100457 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200458
Jean Delvare6b3e4642007-06-24 11:19:01 +0200459 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200460 || !data->valid) {
461 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400462 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200463
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100464 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200465 for (i = 0; i < data->in_num; i++) {
466 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100467 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200468 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100469 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200470 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100471 W83627EHF_REG_IN_MAX(i));
472 }
473
Jean Delvare08e7e272005-04-25 22:43:25 +0200474 /* Measured fan speeds and limits */
475 for (i = 0; i < 5; i++) {
476 if (!(data->has_fan & (1 << i)))
477 continue;
478
David Hubbard1ea6dd32007-06-24 11:16:15 +0200479 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200480 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200481 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200482 W83627EHF_REG_FAN_MIN[i]);
483
484 /* If we failed to measure the fan speed and clock
485 divider can be increased, let's try that for next
486 time */
487 if (data->fan[i] == 0xff
488 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200489 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200490 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700491 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200492 div_from_reg(data->fan_div[i] + 1));
493 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200494 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200495 /* Preserve min limit if possible */
496 if (data->fan_min[i] >= 2
497 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200498 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200499 W83627EHF_REG_FAN_MIN[i],
500 (data->fan_min[i] /= 2));
501 }
502 }
503
Rudolf Marek08c79952006-07-05 18:14:31 +0200504 for (i = 0; i < 4; i++) {
505 /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
506 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200507 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200508 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200509 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200510 W83627EHF_REG_TOLERANCE[i]);
511 }
512 data->pwm_mode[i] =
513 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
514 ? 0 : 1;
515 data->pwm_enable[i] =
516 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
517 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200518 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200519 W83627EHF_REG_PWM[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200520 data->fan_min_output[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200521 W83627EHF_REG_FAN_MIN_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200522 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200523 W83627EHF_REG_FAN_STOP_TIME[i]);
524 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200525 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200526 W83627EHF_REG_TARGET[i]) &
527 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
528 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
529 & 0x0f;
530 }
531
Jean Delvare08e7e272005-04-25 22:43:25 +0200532 /* Measured temperatures and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200533 data->temp1 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200534 W83627EHF_REG_TEMP1);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200535 data->temp1_max = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200536 W83627EHF_REG_TEMP1_OVER);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200537 data->temp1_max_hyst = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200538 W83627EHF_REG_TEMP1_HYST);
539 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200540 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200541 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200542 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200543 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200544 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200545 W83627EHF_REG_TEMP_HYST[i]);
546 }
547
David Hubbard1ea6dd32007-06-24 11:16:15 +0200548 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100549 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200550 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100551 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200552 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100553 W83627EHF_REG_ALARM3) << 16);
554
Jean Delvare08e7e272005-04-25 22:43:25 +0200555 data->last_updated = jiffies;
556 data->valid = 1;
557 }
558
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100559 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200560 return data;
561}
562
563/*
564 * Sysfs callback functions
565 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100566#define show_in_reg(reg) \
567static ssize_t \
568show_##reg(struct device *dev, struct device_attribute *attr, \
569 char *buf) \
570{ \
571 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
572 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
573 int nr = sensor_attr->index; \
574 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
575}
576show_in_reg(in)
577show_in_reg(in_min)
578show_in_reg(in_max)
579
580#define store_in_reg(REG, reg) \
581static ssize_t \
582store_in_##reg (struct device *dev, struct device_attribute *attr, \
583 const char *buf, size_t count) \
584{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200585 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100586 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
587 int nr = sensor_attr->index; \
588 u32 val = simple_strtoul(buf, NULL, 10); \
589 \
590 mutex_lock(&data->update_lock); \
591 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200592 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100593 data->in_##reg[nr]); \
594 mutex_unlock(&data->update_lock); \
595 return count; \
596}
597
598store_in_reg(MIN, min)
599store_in_reg(MAX, max)
600
Jean Delvarea4589db2006-03-23 16:30:29 +0100601static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
602{
603 struct w83627ehf_data *data = w83627ehf_update_device(dev);
604 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
605 int nr = sensor_attr->index;
606 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
607}
608
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100609static struct sensor_device_attribute sda_in_input[] = {
610 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
611 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
612 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
613 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
614 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
615 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
616 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
617 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
618 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
619 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
620};
621
Jean Delvarea4589db2006-03-23 16:30:29 +0100622static struct sensor_device_attribute sda_in_alarm[] = {
623 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
624 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
625 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
626 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
627 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
628 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
629 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
630 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
631 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
632 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
633};
634
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100635static struct sensor_device_attribute sda_in_min[] = {
636 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
637 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
638 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
639 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
640 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
641 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
642 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
643 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
644 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
645 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
646};
647
648static struct sensor_device_attribute sda_in_max[] = {
649 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
650 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
651 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
652 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
653 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
654 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
655 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
656 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
657 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
658 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
659};
660
Jean Delvare08e7e272005-04-25 22:43:25 +0200661#define show_fan_reg(reg) \
662static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100663show_##reg(struct device *dev, struct device_attribute *attr, \
664 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200665{ \
666 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100667 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
668 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200669 return sprintf(buf, "%d\n", \
670 fan_from_reg(data->reg[nr], \
671 div_from_reg(data->fan_div[nr]))); \
672}
673show_fan_reg(fan);
674show_fan_reg(fan_min);
675
676static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100677show_fan_div(struct device *dev, struct device_attribute *attr,
678 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200679{
680 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100681 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
682 int nr = sensor_attr->index;
683 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200684}
685
686static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100687store_fan_min(struct device *dev, struct device_attribute *attr,
688 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200689{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200690 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100691 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
692 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200693 unsigned int val = simple_strtoul(buf, NULL, 10);
694 unsigned int reg;
695 u8 new_div;
696
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100697 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200698 if (!val) {
699 /* No min limit, alarm disabled */
700 data->fan_min[nr] = 255;
701 new_div = data->fan_div[nr]; /* No change */
702 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
703 } else if ((reg = 1350000U / val) >= 128 * 255) {
704 /* Speed below this value cannot possibly be represented,
705 even with the highest divider (128) */
706 data->fan_min[nr] = 254;
707 new_div = 7; /* 128 == (1 << 7) */
708 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
709 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
710 } else if (!reg) {
711 /* Speed above this value cannot possibly be represented,
712 even with the lowest divider (1) */
713 data->fan_min[nr] = 1;
714 new_div = 0; /* 1 == (1 << 0) */
715 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200716 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200717 } else {
718 /* Automatically pick the best divider, i.e. the one such
719 that the min limit will correspond to a register value
720 in the 96..192 range */
721 new_div = 0;
722 while (reg > 192 && new_div < 7) {
723 reg >>= 1;
724 new_div++;
725 }
726 data->fan_min[nr] = reg;
727 }
728
729 /* Write both the fan clock divider (if it changed) and the new
730 fan min (unconditionally) */
731 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200732 /* Preserve the fan speed reading */
733 if (data->fan[nr] != 0xff) {
734 if (new_div > data->fan_div[nr])
735 data->fan[nr] >>= new_div - data->fan_div[nr];
736 else if (data->fan[nr] & 0x80)
737 data->fan[nr] = 0xff;
738 else
739 data->fan[nr] <<= data->fan_div[nr] - new_div;
740 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200741
742 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
743 nr + 1, div_from_reg(data->fan_div[nr]),
744 div_from_reg(new_div));
745 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200746 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200747 /* Give the chip time to sample a new speed value */
748 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200749 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200750 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200751 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100752 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200753
754 return count;
755}
756
Yuan Mu412fec82006-02-05 23:24:16 +0100757static struct sensor_device_attribute sda_fan_input[] = {
758 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
759 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
760 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
761 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
762 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
763};
Jean Delvare08e7e272005-04-25 22:43:25 +0200764
Jean Delvarea4589db2006-03-23 16:30:29 +0100765static struct sensor_device_attribute sda_fan_alarm[] = {
766 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
767 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
768 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
769 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
770 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
771};
772
Yuan Mu412fec82006-02-05 23:24:16 +0100773static struct sensor_device_attribute sda_fan_min[] = {
774 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
775 store_fan_min, 0),
776 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
777 store_fan_min, 1),
778 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
779 store_fan_min, 2),
780 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
781 store_fan_min, 3),
782 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
783 store_fan_min, 4),
784};
Jean Delvare08e7e272005-04-25 22:43:25 +0200785
Yuan Mu412fec82006-02-05 23:24:16 +0100786static struct sensor_device_attribute sda_fan_div[] = {
787 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
788 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
789 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
790 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
791 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
792};
Jean Delvare08e7e272005-04-25 22:43:25 +0200793
Jean Delvare08e7e272005-04-25 22:43:25 +0200794#define show_temp1_reg(reg) \
795static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700796show_##reg(struct device *dev, struct device_attribute *attr, \
797 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200798{ \
799 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
800 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
801}
802show_temp1_reg(temp1);
803show_temp1_reg(temp1_max);
804show_temp1_reg(temp1_max_hyst);
805
806#define store_temp1_reg(REG, reg) \
807static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700808store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
809 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200810{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200811 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200812 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200813 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100814 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200815 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200816 w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
Jean Delvare08e7e272005-04-25 22:43:25 +0200817 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100818 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200819 return count; \
820}
821store_temp1_reg(OVER, max);
822store_temp1_reg(HYST, max_hyst);
823
Jean Delvare08e7e272005-04-25 22:43:25 +0200824#define show_temp_reg(reg) \
825static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100826show_##reg(struct device *dev, struct device_attribute *attr, \
827 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200828{ \
829 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100830 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
831 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200832 return sprintf(buf, "%d\n", \
833 LM75_TEMP_FROM_REG(data->reg[nr])); \
834}
835show_temp_reg(temp);
836show_temp_reg(temp_max);
837show_temp_reg(temp_max_hyst);
838
839#define store_temp_reg(REG, reg) \
840static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100841store_##reg(struct device *dev, struct device_attribute *attr, \
842 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200843{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200844 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100845 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
846 int nr = sensor_attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200847 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200848 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100849 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200850 data->reg[nr] = LM75_TEMP_TO_REG(val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200851 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200852 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100853 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200854 return count; \
855}
856store_temp_reg(OVER, temp_max);
857store_temp_reg(HYST, temp_max_hyst);
858
Jean Delvareda667362007-06-24 11:21:02 +0200859static ssize_t
860show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
861{
862 struct w83627ehf_data *data = w83627ehf_update_device(dev);
863 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
864 int nr = sensor_attr->index;
865 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
866}
867
Yuan Mu412fec82006-02-05 23:24:16 +0100868static struct sensor_device_attribute sda_temp[] = {
869 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
870 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
871 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
872 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
873 store_temp1_max, 0),
874 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
875 store_temp_max, 0),
876 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
877 store_temp_max, 1),
878 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
879 store_temp1_max_hyst, 0),
880 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
881 store_temp_max_hyst, 0),
882 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
883 store_temp_max_hyst, 1),
Jean Delvarea4589db2006-03-23 16:30:29 +0100884 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
885 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
886 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Jean Delvareda667362007-06-24 11:21:02 +0200887 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
888 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
889 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100890};
Jean Delvare08e7e272005-04-25 22:43:25 +0200891
Rudolf Marek08c79952006-07-05 18:14:31 +0200892#define show_pwm_reg(reg) \
893static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
894 char *buf) \
895{ \
896 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
897 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
898 int nr = sensor_attr->index; \
899 return sprintf(buf, "%d\n", data->reg[nr]); \
900}
901
902show_pwm_reg(pwm_mode)
903show_pwm_reg(pwm_enable)
904show_pwm_reg(pwm)
905
906static ssize_t
907store_pwm_mode(struct device *dev, struct device_attribute *attr,
908 const char *buf, size_t count)
909{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200910 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200911 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
912 int nr = sensor_attr->index;
913 u32 val = simple_strtoul(buf, NULL, 10);
914 u16 reg;
915
916 if (val > 1)
917 return -EINVAL;
918 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200919 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200920 data->pwm_mode[nr] = val;
921 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
922 if (!val)
923 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200924 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200925 mutex_unlock(&data->update_lock);
926 return count;
927}
928
929static ssize_t
930store_pwm(struct device *dev, struct device_attribute *attr,
931 const char *buf, size_t count)
932{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200933 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200934 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
935 int nr = sensor_attr->index;
936 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
937
938 mutex_lock(&data->update_lock);
939 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200940 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200941 mutex_unlock(&data->update_lock);
942 return count;
943}
944
945static ssize_t
946store_pwm_enable(struct device *dev, struct device_attribute *attr,
947 const char *buf, size_t count)
948{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200949 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200950 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
951 int nr = sensor_attr->index;
952 u32 val = simple_strtoul(buf, NULL, 10);
953 u16 reg;
954
955 if (!val || (val > 2)) /* only modes 1 and 2 are supported */
956 return -EINVAL;
957 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200958 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200959 data->pwm_enable[nr] = val;
960 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
961 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200962 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200963 mutex_unlock(&data->update_lock);
964 return count;
965}
966
967
968#define show_tol_temp(reg) \
969static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
970 char *buf) \
971{ \
972 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
973 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
974 int nr = sensor_attr->index; \
975 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
976}
977
978show_tol_temp(tolerance)
979show_tol_temp(target_temp)
980
981static ssize_t
982store_target_temp(struct device *dev, struct device_attribute *attr,
983 const char *buf, size_t count)
984{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200985 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200986 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
987 int nr = sensor_attr->index;
988 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
989
990 mutex_lock(&data->update_lock);
991 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200992 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200993 mutex_unlock(&data->update_lock);
994 return count;
995}
996
997static ssize_t
998store_tolerance(struct device *dev, struct device_attribute *attr,
999 const char *buf, size_t count)
1000{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001001 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001002 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1003 int nr = sensor_attr->index;
1004 u16 reg;
1005 /* Limit the temp to 0C - 15C */
1006 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
1007
1008 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001009 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001010 data->tolerance[nr] = val;
1011 if (nr == 1)
1012 reg = (reg & 0x0f) | (val << 4);
1013 else
1014 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001015 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001016 mutex_unlock(&data->update_lock);
1017 return count;
1018}
1019
1020static struct sensor_device_attribute sda_pwm[] = {
1021 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1022 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1023 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1024 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1025};
1026
1027static struct sensor_device_attribute sda_pwm_mode[] = {
1028 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1029 store_pwm_mode, 0),
1030 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1031 store_pwm_mode, 1),
1032 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1033 store_pwm_mode, 2),
1034 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1035 store_pwm_mode, 3),
1036};
1037
1038static struct sensor_device_attribute sda_pwm_enable[] = {
1039 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1040 store_pwm_enable, 0),
1041 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1042 store_pwm_enable, 1),
1043 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1044 store_pwm_enable, 2),
1045 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1046 store_pwm_enable, 3),
1047};
1048
1049static struct sensor_device_attribute sda_target_temp[] = {
1050 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1051 store_target_temp, 0),
1052 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1053 store_target_temp, 1),
1054 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1055 store_target_temp, 2),
1056 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1057 store_target_temp, 3),
1058};
1059
1060static struct sensor_device_attribute sda_tolerance[] = {
1061 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1062 store_tolerance, 0),
1063 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1064 store_tolerance, 1),
1065 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1066 store_tolerance, 2),
1067 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1068 store_tolerance, 3),
1069};
1070
Rudolf Marek08c79952006-07-05 18:14:31 +02001071/* Smart Fan registers */
1072
1073#define fan_functions(reg, REG) \
1074static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1075 char *buf) \
1076{ \
1077 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1078 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1079 int nr = sensor_attr->index; \
1080 return sprintf(buf, "%d\n", data->reg[nr]); \
1081}\
1082static ssize_t \
1083store_##reg(struct device *dev, struct device_attribute *attr, \
1084 const char *buf, size_t count) \
1085{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001086 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001087 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1088 int nr = sensor_attr->index; \
1089 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1090 mutex_lock(&data->update_lock); \
1091 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001092 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001093 mutex_unlock(&data->update_lock); \
1094 return count; \
1095}
1096
1097fan_functions(fan_min_output, FAN_MIN_OUTPUT)
1098
1099#define fan_time_functions(reg, REG) \
1100static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1101 char *buf) \
1102{ \
1103 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1104 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1105 int nr = sensor_attr->index; \
1106 return sprintf(buf, "%d\n", \
1107 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1108} \
1109\
1110static ssize_t \
1111store_##reg(struct device *dev, struct device_attribute *attr, \
1112 const char *buf, size_t count) \
1113{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001114 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001115 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1116 int nr = sensor_attr->index; \
1117 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1118 data->pwm_mode[nr]); \
1119 mutex_lock(&data->update_lock); \
1120 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001121 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001122 mutex_unlock(&data->update_lock); \
1123 return count; \
1124} \
1125
1126fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1127
David Hubbard1ea6dd32007-06-24 11:16:15 +02001128static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1129 char *buf)
1130{
1131 struct w83627ehf_data *data = dev_get_drvdata(dev);
1132
1133 return sprintf(buf, "%s\n", data->name);
1134}
1135static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001136
1137static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1138 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1139 store_fan_stop_time, 3),
1140 SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1141 store_fan_min_output, 3),
1142};
1143
1144static struct sensor_device_attribute sda_sf3_arrays[] = {
1145 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1146 store_fan_stop_time, 0),
1147 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1148 store_fan_stop_time, 1),
1149 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1150 store_fan_stop_time, 2),
1151 SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1152 store_fan_min_output, 0),
1153 SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1154 store_fan_min_output, 1),
1155 SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1156 store_fan_min_output, 2),
1157};
1158
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001159static ssize_t
1160show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1161{
1162 struct w83627ehf_data *data = dev_get_drvdata(dev);
1163 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1164}
1165static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1166
Jean Delvare08e7e272005-04-25 22:43:25 +02001167/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001168 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001169 */
1170
David Hubbardc18beb52006-09-24 21:04:38 +02001171static void w83627ehf_device_remove_files(struct device *dev)
1172{
1173 /* some entries in the following arrays may not have been used in
1174 * device_create_file(), but device_remove_file() will ignore them */
1175 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001176 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001177
1178 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1179 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
1180 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1181 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001182 for (i = 0; i < data->in_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001183 device_remove_file(dev, &sda_in_input[i].dev_attr);
1184 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1185 device_remove_file(dev, &sda_in_min[i].dev_attr);
1186 device_remove_file(dev, &sda_in_max[i].dev_attr);
1187 }
1188 for (i = 0; i < 5; i++) {
1189 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1190 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1191 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1192 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1193 }
1194 for (i = 0; i < 4; i++) {
1195 device_remove_file(dev, &sda_pwm[i].dev_attr);
1196 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1197 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1198 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1199 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1200 }
1201 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
1202 device_remove_file(dev, &sda_temp[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001203
1204 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001205 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001206}
1207
David Hubbard1ea6dd32007-06-24 11:16:15 +02001208/* Get the monitoring functions started */
1209static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001210{
1211 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001212 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001213
1214 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001215 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001216 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001217 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001218 tmp | 0x01);
1219
1220 /* Enable temp2 and temp3 if needed */
1221 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001222 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001223 W83627EHF_REG_TEMP_CONFIG[i]);
1224 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001225 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001226 W83627EHF_REG_TEMP_CONFIG[i],
1227 tmp & 0xfe);
1228 }
Jean Delvared3130f02007-06-24 11:20:13 +02001229
1230 /* Enable VBAT monitoring if needed */
1231 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1232 if (!(tmp & 0x01))
1233 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001234
1235 /* Get thermal sensor types */
1236 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1237 for (i = 0; i < 3; i++) {
1238 if ((tmp & (0x02 << i)))
1239 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1240 else
1241 data->temp_type[i] = 4; /* thermistor */
1242 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001243}
1244
David Hubbard1ea6dd32007-06-24 11:16:15 +02001245static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001246{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001247 struct device *dev = &pdev->dev;
1248 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001249 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001250 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001251 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001252 int i, err = 0;
1253
David Hubbard1ea6dd32007-06-24 11:16:15 +02001254 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1255 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001256 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001257 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1258 (unsigned long)res->start,
1259 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001260 goto exit;
1261 }
1262
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001263 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001264 err = -ENOMEM;
1265 goto exit_release;
1266 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001267
David Hubbard1ea6dd32007-06-24 11:16:15 +02001268 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001269 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001270 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001271 data->name = w83627ehf_device_names[sio_data->kind];
1272 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001273
David Hubbard1ea6dd32007-06-24 11:16:15 +02001274 /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
1275 data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001276
1277 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001278 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001279
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001280 data->vrm = vid_which_vrm();
1281 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001282 /* Read VID value */
1283 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
Jean Delvare58e6e782008-01-03 07:33:31 -05001284 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1285 /* Set VID input sensibility if needed. In theory the BIOS
1286 should have set it, but in practice it's not always the
1287 case. We only do it for the W83627EHF/EHG because the
1288 W83627DHG is more complex in this respect. */
1289 if (sio_data->kind == w83627ehf) {
1290 en_vrm10 = superio_inb(sio_data->sioreg,
1291 SIO_REG_EN_VRM10);
1292 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1293 dev_warn(dev, "Setting VID input voltage to "
1294 "TTL\n");
1295 superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
1296 en_vrm10 & ~0x08);
1297 } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
1298 dev_warn(dev, "Setting VID input voltage to "
1299 "VRM10\n");
1300 superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
1301 en_vrm10 | 0x08);
1302 }
1303 }
1304
Jean Delvarecbe311f2008-01-03 21:22:44 +01001305 data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
1306 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1307 data->vid &= 0x3f;
1308
1309 err = device_create_file(dev, &dev_attr_cpu0_vid);
1310 if (err)
1311 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001312 } else {
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001313 dev_info(dev, "VID pins in output mode, CPU VID not "
1314 "available\n");
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001315 }
1316
Rudolf Marek08c79952006-07-05 18:14:31 +02001317 /* fan4 and fan5 share some pins with the GPIO and serial flash */
1318
David Hubbard1ea6dd32007-06-24 11:16:15 +02001319 fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
1320 fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
1321 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001322
Jean Delvare08e7e272005-04-25 22:43:25 +02001323 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001324 as fan on/off switches, but fan5 control is write only :/
1325 We assume that if the serial interface is disabled, designers
1326 connected fan5 as input unless they are emitting log 1, which
1327 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001328
Jean Delvare08e7e272005-04-25 22:43:25 +02001329 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001330 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Rudolf Marek08c79952006-07-05 18:14:31 +02001331 if ((i & (1 << 2)) && (!fan4pin))
Jean Delvare08e7e272005-04-25 22:43:25 +02001332 data->has_fan |= (1 << 3);
Rudolf Marek14992c72006-10-08 22:02:09 +02001333 if (!(i & (1 << 1)) && (!fan5pin))
Jean Delvare08e7e272005-04-25 22:43:25 +02001334 data->has_fan |= (1 << 4);
1335
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001336 /* Read fan clock dividers immediately */
1337 w83627ehf_update_fan_div(data);
1338
Jean Delvare08e7e272005-04-25 22:43:25 +02001339 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001340 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001341 if ((err = device_create_file(dev,
1342 &sda_sf3_arrays[i].dev_attr)))
1343 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001344
1345 /* if fan4 is enabled create the sf3 files for it */
1346 if (data->has_fan & (1 << 3))
David Hubbardc18beb52006-09-24 21:04:38 +02001347 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1348 if ((err = device_create_file(dev,
1349 &sda_sf3_arrays_fan4[i].dev_attr)))
1350 goto exit_remove;
1351 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001352
David Hubbard1ea6dd32007-06-24 11:16:15 +02001353 for (i = 0; i < data->in_num; i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001354 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1355 || (err = device_create_file(dev,
1356 &sda_in_alarm[i].dev_attr))
1357 || (err = device_create_file(dev,
1358 &sda_in_min[i].dev_attr))
1359 || (err = device_create_file(dev,
1360 &sda_in_max[i].dev_attr)))
1361 goto exit_remove;
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001362
Yuan Mu412fec82006-02-05 23:24:16 +01001363 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001364 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001365 if ((err = device_create_file(dev,
1366 &sda_fan_input[i].dev_attr))
1367 || (err = device_create_file(dev,
1368 &sda_fan_alarm[i].dev_attr))
1369 || (err = device_create_file(dev,
1370 &sda_fan_div[i].dev_attr))
1371 || (err = device_create_file(dev,
1372 &sda_fan_min[i].dev_attr)))
1373 goto exit_remove;
1374 if (i < 4 && /* w83627ehf only has 4 pwm */
1375 ((err = device_create_file(dev,
1376 &sda_pwm[i].dev_attr))
1377 || (err = device_create_file(dev,
1378 &sda_pwm_mode[i].dev_attr))
1379 || (err = device_create_file(dev,
1380 &sda_pwm_enable[i].dev_attr))
1381 || (err = device_create_file(dev,
1382 &sda_target_temp[i].dev_attr))
1383 || (err = device_create_file(dev,
1384 &sda_tolerance[i].dev_attr))))
1385 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001386 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001387 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001388
Yuan Mu412fec82006-02-05 23:24:16 +01001389 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001390 if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
1391 goto exit_remove;
1392
David Hubbard1ea6dd32007-06-24 11:16:15 +02001393 err = device_create_file(dev, &dev_attr_name);
1394 if (err)
1395 goto exit_remove;
1396
Tony Jones1beeffe2007-08-20 13:46:20 -07001397 data->hwmon_dev = hwmon_device_register(dev);
1398 if (IS_ERR(data->hwmon_dev)) {
1399 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001400 goto exit_remove;
1401 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001402
1403 return 0;
1404
David Hubbardc18beb52006-09-24 21:04:38 +02001405exit_remove:
1406 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001407 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001408 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001409exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001410 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001411exit:
1412 return err;
1413}
1414
David Hubbard1ea6dd32007-06-24 11:16:15 +02001415static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001416{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001417 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001418
Tony Jones1beeffe2007-08-20 13:46:20 -07001419 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001420 w83627ehf_device_remove_files(&pdev->dev);
1421 release_region(data->addr, IOREGION_LENGTH);
1422 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001423 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001424
1425 return 0;
1426}
1427
David Hubbard1ea6dd32007-06-24 11:16:15 +02001428static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001429 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001430 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001431 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001432 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001433 .probe = w83627ehf_probe,
1434 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001435};
1436
David Hubbard1ea6dd32007-06-24 11:16:15 +02001437/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1438static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1439 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001440{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001441 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1442 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1443 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
1444
Jean Delvare08e7e272005-04-25 22:43:25 +02001445 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001446 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001447
David Hubbard1ea6dd32007-06-24 11:16:15 +02001448 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001449
Jean Delvare67b671b2007-12-06 23:13:42 +01001450 if (force_id)
1451 val = force_id;
1452 else
1453 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1454 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001455 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001456 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001457 sio_data->kind = w83627ehf;
1458 sio_name = sio_name_W83627EHF;
1459 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001460 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001461 sio_data->kind = w83627ehf;
1462 sio_name = sio_name_W83627EHG;
1463 break;
1464 case SIO_W83627DHG_ID:
1465 sio_data->kind = w83627dhg;
1466 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001467 break;
1468 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001469 if (val != 0xffff)
1470 pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
1471 val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001472 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001473 return -ENODEV;
1474 }
1475
David Hubbard1ea6dd32007-06-24 11:16:15 +02001476 /* We have a known chip, find the HWM I/O address */
1477 superio_select(sioaddr, W83627EHF_LD_HWM);
1478 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1479 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001480 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001481 if (*addr == 0) {
David Hubbard475ef852007-06-24 11:17:09 +02001482 printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
1483 "device with a base I/O port 0.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001484 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001485 return -ENODEV;
1486 }
1487
1488 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001489 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001490 if (!(val & 0x01)) {
1491 printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
1492 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001493 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001494 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001495
David Hubbard1ea6dd32007-06-24 11:16:15 +02001496 superio_exit(sioaddr);
1497 pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
1498 sio_data->sioreg = sioaddr;
1499
Jean Delvare08e7e272005-04-25 22:43:25 +02001500 return 0;
1501}
1502
David Hubbard1ea6dd32007-06-24 11:16:15 +02001503/* when Super-I/O functions move to a separate file, the Super-I/O
1504 * bus will manage the lifetime of the device and this module will only keep
1505 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1506 * must keep track of the device */
1507static struct platform_device *pdev;
1508
Jean Delvare08e7e272005-04-25 22:43:25 +02001509static int __init sensors_w83627ehf_init(void)
1510{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001511 int err;
1512 unsigned short address;
1513 struct resource res;
1514 struct w83627ehf_sio_data sio_data;
1515
1516 /* initialize sio_data->kind and sio_data->sioreg.
1517 *
1518 * when Super-I/O functions move to a separate file, the Super-I/O
1519 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1520 * w83627ehf hardware monitor, and call probe() */
1521 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1522 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001523 return -ENODEV;
1524
David Hubbard1ea6dd32007-06-24 11:16:15 +02001525 err = platform_driver_register(&w83627ehf_driver);
1526 if (err)
1527 goto exit;
1528
1529 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1530 err = -ENOMEM;
1531 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1532 goto exit_unregister;
1533 }
1534
1535 err = platform_device_add_data(pdev, &sio_data,
1536 sizeof(struct w83627ehf_sio_data));
1537 if (err) {
1538 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1539 goto exit_device_put;
1540 }
1541
1542 memset(&res, 0, sizeof(res));
1543 res.name = DRVNAME;
1544 res.start = address + IOREGION_OFFSET;
1545 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1546 res.flags = IORESOURCE_IO;
1547 err = platform_device_add_resources(pdev, &res, 1);
1548 if (err) {
1549 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1550 "(%d)\n", err);
1551 goto exit_device_put;
1552 }
1553
1554 /* platform_device_add calls probe() */
1555 err = platform_device_add(pdev);
1556 if (err) {
1557 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1558 err);
1559 goto exit_device_put;
1560 }
1561
1562 return 0;
1563
1564exit_device_put:
1565 platform_device_put(pdev);
1566exit_unregister:
1567 platform_driver_unregister(&w83627ehf_driver);
1568exit:
1569 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001570}
1571
1572static void __exit sensors_w83627ehf_exit(void)
1573{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001574 platform_device_unregister(pdev);
1575 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001576}
1577
1578MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1579MODULE_DESCRIPTION("W83627EHF driver");
1580MODULE_LICENSE("GPL");
1581
1582module_init(sensors_w83627ehf_init);
1583module_exit(sensors_w83627ehf_exit);