blob: 833faa275ffaed22b8eb5caa57172a965595ca7a [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),
Rudolf Marek08c79952006-07-05 18:14:31 +02006 Rudolf Marek <r.marek@sh.cvut.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
Rudolf Marek08c79952006-07-05 18:14:31 +020035 Chip #vin #fan #pwm #temp chip_id man_id
36 w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020037*/
38
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/slab.h>
42#include <linux/i2c.h>
Jean Delvarefde09502005-07-19 23:51:07 +020043#include <linux/i2c-isa.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040044#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010045#include <linux/hwmon-sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040046#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010047#include <linux/mutex.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020048#include <asm/io.h>
49#include "lm75.h"
50
Jean Delvare2d8672c2005-07-19 23:56:35 +020051/* The actual ISA address is read from Super-I/O configuration space */
52static unsigned short address;
Jean Delvare08e7e272005-04-25 22:43:25 +020053
54/*
55 * Super-I/O constants and functions
56 */
57
58static int REG; /* The register to read/write */
59static int VAL; /* The value to read/write */
60
61#define W83627EHF_LD_HWM 0x0b
62
63#define SIO_REG_LDSEL 0x07 /* Logical device select */
64#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
65#define SIO_REG_ENABLE 0x30 /* Logical device enable */
66#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
67
68#define SIO_W83627EHF_ID 0x8840
69#define SIO_ID_MASK 0xFFC0
70
71static inline void
72superio_outb(int reg, int val)
73{
74 outb(reg, REG);
75 outb(val, VAL);
76}
77
78static inline int
79superio_inb(int reg)
80{
81 outb(reg, REG);
82 return inb(VAL);
83}
84
85static inline void
86superio_select(int ld)
87{
88 outb(SIO_REG_LDSEL, REG);
89 outb(ld, VAL);
90}
91
92static inline void
93superio_enter(void)
94{
95 outb(0x87, REG);
96 outb(0x87, REG);
97}
98
99static inline void
100superio_exit(void)
101{
102 outb(0x02, REG);
103 outb(0x02, VAL);
104}
105
106/*
107 * ISA constants
108 */
109
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200110#define REGION_ALIGNMENT ~7
111#define REGION_OFFSET 5
112#define REGION_LENGTH 2
Jean Delvare08e7e272005-04-25 22:43:25 +0200113#define ADDR_REG_OFFSET 5
114#define DATA_REG_OFFSET 6
115
116#define W83627EHF_REG_BANK 0x4E
117#define W83627EHF_REG_CONFIG 0x40
118#define W83627EHF_REG_CHIP_ID 0x49
119#define W83627EHF_REG_MAN_ID 0x4F
120
121static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
122static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
123
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100124/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
125#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
126 (0x554 + (((nr) - 7) * 2)))
127#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
128 (0x555 + (((nr) - 7) * 2)))
129#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
130 (0x550 + (nr) - 7))
131
Jean Delvare08e7e272005-04-25 22:43:25 +0200132#define W83627EHF_REG_TEMP1 0x27
133#define W83627EHF_REG_TEMP1_HYST 0x3a
134#define W83627EHF_REG_TEMP1_OVER 0x39
135static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
136static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
137static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
138static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
139
140/* Fan clock dividers are spread over the following five registers */
141#define W83627EHF_REG_FANDIV1 0x47
142#define W83627EHF_REG_FANDIV2 0x4B
143#define W83627EHF_REG_VBAT 0x5D
144#define W83627EHF_REG_DIODE 0x59
145#define W83627EHF_REG_SMI_OVT 0x4C
146
Jean Delvarea4589db2006-03-23 16:30:29 +0100147#define W83627EHF_REG_ALARM1 0x459
148#define W83627EHF_REG_ALARM2 0x45A
149#define W83627EHF_REG_ALARM3 0x45B
150
Rudolf Marek08c79952006-07-05 18:14:31 +0200151/* SmartFan registers */
152/* DC or PWM output fan configuration */
153static const u8 W83627EHF_REG_PWM_ENABLE[] = {
154 0x04, /* SYS FAN0 output mode and PWM mode */
155 0x04, /* CPU FAN0 output mode and PWM mode */
156 0x12, /* AUX FAN mode */
157 0x62, /* CPU fan1 mode */
158};
159
160static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
161static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
162
163/* FAN Duty Cycle, be used to control */
164static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
165static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
166static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
167
168
169/* Advanced Fan control, some values are common for all fans */
170static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
171static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
172
Jean Delvare08e7e272005-04-25 22:43:25 +0200173/*
174 * Conversions
175 */
176
Rudolf Marek08c79952006-07-05 18:14:31 +0200177/* 1 is PWM mode, output in ms */
178static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
179{
180 return mode ? 100 * reg : 400 * reg;
181}
182
183static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
184{
185 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
186 (msec + 200) / 400), 1, 255);
187}
188
Jean Delvare08e7e272005-04-25 22:43:25 +0200189static inline unsigned int
190fan_from_reg(u8 reg, unsigned int div)
191{
192 if (reg == 0 || reg == 255)
193 return 0;
194 return 1350000U / (reg * div);
195}
196
197static inline unsigned int
198div_from_reg(u8 reg)
199{
200 return 1 << reg;
201}
202
203static inline int
204temp1_from_reg(s8 reg)
205{
206 return reg * 1000;
207}
208
209static inline s8
Rudolf Marek08c79952006-07-05 18:14:31 +0200210temp1_to_reg(int temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200211{
Rudolf Marek08c79952006-07-05 18:14:31 +0200212 if (temp <= min)
213 return min / 1000;
214 if (temp >= max)
215 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200216 if (temp < 0)
217 return (temp - 500) / 1000;
218 return (temp + 500) / 1000;
219}
220
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100221/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
222
223static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
224
225static inline long in_from_reg(u8 reg, u8 nr)
226{
227 return reg * scale_in[nr];
228}
229
230static inline u8 in_to_reg(u32 val, u8 nr)
231{
232 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
233}
234
Jean Delvare08e7e272005-04-25 22:43:25 +0200235/*
236 * Data structures and manipulation thereof
237 */
238
239struct w83627ehf_data {
240 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400241 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100242 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200243
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100244 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200245 char valid; /* !=0 if following fields are valid */
246 unsigned long last_updated; /* In jiffies */
247
248 /* Register values */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100249 u8 in[10]; /* Register value */
250 u8 in_max[10]; /* Register value */
251 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200252 u8 fan[5];
253 u8 fan_min[5];
254 u8 fan_div[5];
255 u8 has_fan; /* some fan inputs can be disabled */
256 s8 temp1;
257 s8 temp1_max;
258 s8 temp1_max_hyst;
259 s16 temp[2];
260 s16 temp_max[2];
261 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100262 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200263
264 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
265 u8 pwm_enable[4]; /* 1->manual
266 2->thermal cruise (also called SmartFan I) */
267 u8 pwm[4];
268 u8 target_temp[4];
269 u8 tolerance[4];
270
271 u8 fan_min_output[4]; /* minimum fan speed */
272 u8 fan_stop_time[4];
Jean Delvare08e7e272005-04-25 22:43:25 +0200273};
274
275static inline int is_word_sized(u16 reg)
276{
277 return (((reg & 0xff00) == 0x100
278 || (reg & 0xff00) == 0x200)
279 && ((reg & 0x00ff) == 0x50
280 || (reg & 0x00ff) == 0x53
281 || (reg & 0x00ff) == 0x55));
282}
283
284/* We assume that the default bank is 0, thus the following two functions do
285 nothing for registers which live in bank 0. For others, they respectively
286 set the bank register to the correct value (before the register is
287 accessed), and back to 0 (afterwards). */
288static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
289{
290 if (reg & 0xff00) {
291 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
292 outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
293 }
294}
295
296static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
297{
298 if (reg & 0xff00) {
299 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
300 outb_p(0, client->addr + DATA_REG_OFFSET);
301 }
302}
303
304static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
305{
306 struct w83627ehf_data *data = i2c_get_clientdata(client);
307 int res, word_sized = is_word_sized(reg);
308
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100309 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200310
311 w83627ehf_set_bank(client, reg);
312 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
313 res = inb_p(client->addr + DATA_REG_OFFSET);
314 if (word_sized) {
315 outb_p((reg & 0xff) + 1,
316 client->addr + ADDR_REG_OFFSET);
317 res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
318 }
319 w83627ehf_reset_bank(client, reg);
320
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100321 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200322
323 return res;
324}
325
326static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
327{
328 struct w83627ehf_data *data = i2c_get_clientdata(client);
329 int word_sized = is_word_sized(reg);
330
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100331 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200332
333 w83627ehf_set_bank(client, reg);
334 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
335 if (word_sized) {
336 outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
337 outb_p((reg & 0xff) + 1,
338 client->addr + ADDR_REG_OFFSET);
339 }
340 outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
341 w83627ehf_reset_bank(client, reg);
342
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100343 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200344 return 0;
345}
346
347/* This function assumes that the caller holds data->update_lock */
348static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
349{
350 struct w83627ehf_data *data = i2c_get_clientdata(client);
351 u8 reg;
352
353 switch (nr) {
354 case 0:
355 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
356 | ((data->fan_div[0] & 0x03) << 4);
357 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
358 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
359 | ((data->fan_div[0] & 0x04) << 3);
360 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
361 break;
362 case 1:
363 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
364 | ((data->fan_div[1] & 0x03) << 6);
365 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
366 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
367 | ((data->fan_div[1] & 0x04) << 4);
368 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
369 break;
370 case 2:
371 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
372 | ((data->fan_div[2] & 0x03) << 6);
373 w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
374 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
375 | ((data->fan_div[2] & 0x04) << 5);
376 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
377 break;
378 case 3:
379 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
380 | (data->fan_div[3] & 0x03);
381 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
382 reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
383 | ((data->fan_div[3] & 0x04) << 5);
384 w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
385 break;
386 case 4:
387 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
388 | ((data->fan_div[4] & 0x03) << 3)
389 | ((data->fan_div[4] & 0x04) << 5);
390 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
391 break;
392 }
393}
394
395static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
396{
397 struct i2c_client *client = to_i2c_client(dev);
398 struct w83627ehf_data *data = i2c_get_clientdata(client);
Rudolf Marek08c79952006-07-05 18:14:31 +0200399 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200400 int i;
401
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100402 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200403
404 if (time_after(jiffies, data->last_updated + HZ)
405 || !data->valid) {
406 /* Fan clock dividers */
407 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
408 data->fan_div[0] = (i >> 4) & 0x03;
409 data->fan_div[1] = (i >> 6) & 0x03;
410 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
411 data->fan_div[2] = (i >> 6) & 0x03;
412 i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
413 data->fan_div[0] |= (i >> 3) & 0x04;
414 data->fan_div[1] |= (i >> 4) & 0x04;
415 data->fan_div[2] |= (i >> 5) & 0x04;
416 if (data->has_fan & ((1 << 3) | (1 << 4))) {
417 i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
418 data->fan_div[3] = i & 0x03;
419 data->fan_div[4] = ((i >> 2) & 0x03)
420 | ((i >> 5) & 0x04);
421 }
422 if (data->has_fan & (1 << 3)) {
423 i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
424 data->fan_div[3] |= (i >> 5) & 0x04;
425 }
426
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100427 /* Measured voltages and limits */
428 for (i = 0; i < 10; i++) {
429 data->in[i] = w83627ehf_read_value(client,
430 W83627EHF_REG_IN(i));
431 data->in_min[i] = w83627ehf_read_value(client,
432 W83627EHF_REG_IN_MIN(i));
433 data->in_max[i] = w83627ehf_read_value(client,
434 W83627EHF_REG_IN_MAX(i));
435 }
436
Jean Delvare08e7e272005-04-25 22:43:25 +0200437 /* Measured fan speeds and limits */
438 for (i = 0; i < 5; i++) {
439 if (!(data->has_fan & (1 << i)))
440 continue;
441
442 data->fan[i] = w83627ehf_read_value(client,
443 W83627EHF_REG_FAN[i]);
444 data->fan_min[i] = w83627ehf_read_value(client,
445 W83627EHF_REG_FAN_MIN[i]);
446
447 /* If we failed to measure the fan speed and clock
448 divider can be increased, let's try that for next
449 time */
450 if (data->fan[i] == 0xff
451 && data->fan_div[i] < 0x07) {
452 dev_dbg(&client->dev, "Increasing fan %d "
453 "clock divider from %u to %u\n",
454 i, div_from_reg(data->fan_div[i]),
455 div_from_reg(data->fan_div[i] + 1));
456 data->fan_div[i]++;
457 w83627ehf_write_fan_div(client, i);
458 /* Preserve min limit if possible */
459 if (data->fan_min[i] >= 2
460 && data->fan_min[i] != 255)
461 w83627ehf_write_value(client,
462 W83627EHF_REG_FAN_MIN[i],
463 (data->fan_min[i] /= 2));
464 }
465 }
466
Rudolf Marek08c79952006-07-05 18:14:31 +0200467 for (i = 0; i < 4; i++) {
468 /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
469 if (i != 1) {
470 pwmcfg = w83627ehf_read_value(client,
471 W83627EHF_REG_PWM_ENABLE[i]);
472 tolerance = w83627ehf_read_value(client,
473 W83627EHF_REG_TOLERANCE[i]);
474 }
475 data->pwm_mode[i] =
476 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
477 ? 0 : 1;
478 data->pwm_enable[i] =
479 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
480 & 3) + 1;
481 data->pwm[i] = w83627ehf_read_value(client,
482 W83627EHF_REG_PWM[i]);
483 data->fan_min_output[i] = w83627ehf_read_value(client,
484 W83627EHF_REG_FAN_MIN_OUTPUT[i]);
485 data->fan_stop_time[i] = w83627ehf_read_value(client,
486 W83627EHF_REG_FAN_STOP_TIME[i]);
487 data->target_temp[i] =
488 w83627ehf_read_value(client,
489 W83627EHF_REG_TARGET[i]) &
490 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
491 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
492 & 0x0f;
493 }
494
Jean Delvare08e7e272005-04-25 22:43:25 +0200495 /* Measured temperatures and limits */
496 data->temp1 = w83627ehf_read_value(client,
497 W83627EHF_REG_TEMP1);
498 data->temp1_max = w83627ehf_read_value(client,
499 W83627EHF_REG_TEMP1_OVER);
500 data->temp1_max_hyst = w83627ehf_read_value(client,
501 W83627EHF_REG_TEMP1_HYST);
502 for (i = 0; i < 2; i++) {
503 data->temp[i] = w83627ehf_read_value(client,
504 W83627EHF_REG_TEMP[i]);
505 data->temp_max[i] = w83627ehf_read_value(client,
506 W83627EHF_REG_TEMP_OVER[i]);
507 data->temp_max_hyst[i] = w83627ehf_read_value(client,
508 W83627EHF_REG_TEMP_HYST[i]);
509 }
510
Jean Delvarea4589db2006-03-23 16:30:29 +0100511 data->alarms = w83627ehf_read_value(client,
512 W83627EHF_REG_ALARM1) |
513 (w83627ehf_read_value(client,
514 W83627EHF_REG_ALARM2) << 8) |
515 (w83627ehf_read_value(client,
516 W83627EHF_REG_ALARM3) << 16);
517
Jean Delvare08e7e272005-04-25 22:43:25 +0200518 data->last_updated = jiffies;
519 data->valid = 1;
520 }
521
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100522 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200523 return data;
524}
525
526/*
527 * Sysfs callback functions
528 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100529#define show_in_reg(reg) \
530static ssize_t \
531show_##reg(struct device *dev, struct device_attribute *attr, \
532 char *buf) \
533{ \
534 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
535 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
536 int nr = sensor_attr->index; \
537 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
538}
539show_in_reg(in)
540show_in_reg(in_min)
541show_in_reg(in_max)
542
543#define store_in_reg(REG, reg) \
544static ssize_t \
545store_in_##reg (struct device *dev, struct device_attribute *attr, \
546 const char *buf, size_t count) \
547{ \
548 struct i2c_client *client = to_i2c_client(dev); \
549 struct w83627ehf_data *data = i2c_get_clientdata(client); \
550 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
551 int nr = sensor_attr->index; \
552 u32 val = simple_strtoul(buf, NULL, 10); \
553 \
554 mutex_lock(&data->update_lock); \
555 data->in_##reg[nr] = in_to_reg(val, nr); \
556 w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
557 data->in_##reg[nr]); \
558 mutex_unlock(&data->update_lock); \
559 return count; \
560}
561
562store_in_reg(MIN, min)
563store_in_reg(MAX, max)
564
Jean Delvarea4589db2006-03-23 16:30:29 +0100565static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
566{
567 struct w83627ehf_data *data = w83627ehf_update_device(dev);
568 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
569 int nr = sensor_attr->index;
570 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
571}
572
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100573static struct sensor_device_attribute sda_in_input[] = {
574 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
575 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
576 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
577 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
578 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
579 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
580 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
581 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
582 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
583 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
584};
585
Jean Delvarea4589db2006-03-23 16:30:29 +0100586static struct sensor_device_attribute sda_in_alarm[] = {
587 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
588 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
589 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
590 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
591 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
592 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
593 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
594 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
595 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
596 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
597};
598
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100599static struct sensor_device_attribute sda_in_min[] = {
600 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
601 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
602 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
603 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
604 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
605 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
606 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
607 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
608 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
609 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
610};
611
612static struct sensor_device_attribute sda_in_max[] = {
613 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
614 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
615 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
616 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
617 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
618 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
619 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
620 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
621 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
622 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
623};
624
Jean Delvare08e7e272005-04-25 22:43:25 +0200625#define show_fan_reg(reg) \
626static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100627show_##reg(struct device *dev, struct device_attribute *attr, \
628 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200629{ \
630 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100631 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
632 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200633 return sprintf(buf, "%d\n", \
634 fan_from_reg(data->reg[nr], \
635 div_from_reg(data->fan_div[nr]))); \
636}
637show_fan_reg(fan);
638show_fan_reg(fan_min);
639
640static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100641show_fan_div(struct device *dev, struct device_attribute *attr,
642 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200643{
644 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100645 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
646 int nr = sensor_attr->index;
647 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200648}
649
650static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100651store_fan_min(struct device *dev, struct device_attribute *attr,
652 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200653{
654 struct i2c_client *client = to_i2c_client(dev);
655 struct w83627ehf_data *data = i2c_get_clientdata(client);
Yuan Mu412fec82006-02-05 23:24:16 +0100656 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
657 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200658 unsigned int val = simple_strtoul(buf, NULL, 10);
659 unsigned int reg;
660 u8 new_div;
661
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100662 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200663 if (!val) {
664 /* No min limit, alarm disabled */
665 data->fan_min[nr] = 255;
666 new_div = data->fan_div[nr]; /* No change */
667 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
668 } else if ((reg = 1350000U / val) >= 128 * 255) {
669 /* Speed below this value cannot possibly be represented,
670 even with the highest divider (128) */
671 data->fan_min[nr] = 254;
672 new_div = 7; /* 128 == (1 << 7) */
673 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
674 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
675 } else if (!reg) {
676 /* Speed above this value cannot possibly be represented,
677 even with the lowest divider (1) */
678 data->fan_min[nr] = 1;
679 new_div = 0; /* 1 == (1 << 0) */
680 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200681 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200682 } else {
683 /* Automatically pick the best divider, i.e. the one such
684 that the min limit will correspond to a register value
685 in the 96..192 range */
686 new_div = 0;
687 while (reg > 192 && new_div < 7) {
688 reg >>= 1;
689 new_div++;
690 }
691 data->fan_min[nr] = reg;
692 }
693
694 /* Write both the fan clock divider (if it changed) and the new
695 fan min (unconditionally) */
696 if (new_div != data->fan_div[nr]) {
697 if (new_div > data->fan_div[nr])
698 data->fan[nr] >>= (data->fan_div[nr] - new_div);
699 else
700 data->fan[nr] <<= (new_div - data->fan_div[nr]);
701
702 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
703 nr + 1, div_from_reg(data->fan_div[nr]),
704 div_from_reg(new_div));
705 data->fan_div[nr] = new_div;
706 w83627ehf_write_fan_div(client, nr);
707 }
708 w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
709 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100710 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200711
712 return count;
713}
714
Yuan Mu412fec82006-02-05 23:24:16 +0100715static struct sensor_device_attribute sda_fan_input[] = {
716 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
717 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
718 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
719 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
720 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
721};
Jean Delvare08e7e272005-04-25 22:43:25 +0200722
Jean Delvarea4589db2006-03-23 16:30:29 +0100723static struct sensor_device_attribute sda_fan_alarm[] = {
724 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
725 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
726 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
727 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
728 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
729};
730
Yuan Mu412fec82006-02-05 23:24:16 +0100731static struct sensor_device_attribute sda_fan_min[] = {
732 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
733 store_fan_min, 0),
734 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
735 store_fan_min, 1),
736 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
737 store_fan_min, 2),
738 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
739 store_fan_min, 3),
740 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
741 store_fan_min, 4),
742};
Jean Delvare08e7e272005-04-25 22:43:25 +0200743
Yuan Mu412fec82006-02-05 23:24:16 +0100744static struct sensor_device_attribute sda_fan_div[] = {
745 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
746 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
747 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
748 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
749 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
750};
Jean Delvare08e7e272005-04-25 22:43:25 +0200751
Jean Delvare08e7e272005-04-25 22:43:25 +0200752#define show_temp1_reg(reg) \
753static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700754show_##reg(struct device *dev, struct device_attribute *attr, \
755 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200756{ \
757 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
758 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
759}
760show_temp1_reg(temp1);
761show_temp1_reg(temp1_max);
762show_temp1_reg(temp1_max_hyst);
763
764#define store_temp1_reg(REG, reg) \
765static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700766store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
767 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200768{ \
769 struct i2c_client *client = to_i2c_client(dev); \
770 struct w83627ehf_data *data = i2c_get_clientdata(client); \
771 u32 val = simple_strtoul(buf, NULL, 10); \
772 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100773 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200774 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200775 w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
776 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100777 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200778 return count; \
779}
780store_temp1_reg(OVER, max);
781store_temp1_reg(HYST, max_hyst);
782
Jean Delvare08e7e272005-04-25 22:43:25 +0200783#define show_temp_reg(reg) \
784static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100785show_##reg(struct device *dev, struct device_attribute *attr, \
786 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200787{ \
788 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100789 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
790 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200791 return sprintf(buf, "%d\n", \
792 LM75_TEMP_FROM_REG(data->reg[nr])); \
793}
794show_temp_reg(temp);
795show_temp_reg(temp_max);
796show_temp_reg(temp_max_hyst);
797
798#define store_temp_reg(REG, reg) \
799static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100800store_##reg(struct device *dev, struct device_attribute *attr, \
801 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200802{ \
803 struct i2c_client *client = to_i2c_client(dev); \
804 struct w83627ehf_data *data = i2c_get_clientdata(client); \
Yuan Mu412fec82006-02-05 23:24:16 +0100805 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
806 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200807 u32 val = simple_strtoul(buf, NULL, 10); \
808 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100809 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200810 data->reg[nr] = LM75_TEMP_TO_REG(val); \
811 w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
812 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100813 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200814 return count; \
815}
816store_temp_reg(OVER, temp_max);
817store_temp_reg(HYST, temp_max_hyst);
818
Yuan Mu412fec82006-02-05 23:24:16 +0100819static struct sensor_device_attribute sda_temp[] = {
820 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
821 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
822 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
823 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
824 store_temp1_max, 0),
825 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
826 store_temp_max, 0),
827 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
828 store_temp_max, 1),
829 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
830 store_temp1_max_hyst, 0),
831 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
832 store_temp_max_hyst, 0),
833 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
834 store_temp_max_hyst, 1),
Jean Delvarea4589db2006-03-23 16:30:29 +0100835 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
836 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
837 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Yuan Mu412fec82006-02-05 23:24:16 +0100838};
Jean Delvare08e7e272005-04-25 22:43:25 +0200839
Rudolf Marek08c79952006-07-05 18:14:31 +0200840#define show_pwm_reg(reg) \
841static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
842 char *buf) \
843{ \
844 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
845 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
846 int nr = sensor_attr->index; \
847 return sprintf(buf, "%d\n", data->reg[nr]); \
848}
849
850show_pwm_reg(pwm_mode)
851show_pwm_reg(pwm_enable)
852show_pwm_reg(pwm)
853
854static ssize_t
855store_pwm_mode(struct device *dev, struct device_attribute *attr,
856 const char *buf, size_t count)
857{
858 struct i2c_client *client = to_i2c_client(dev);
859 struct w83627ehf_data *data = i2c_get_clientdata(client);
860 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
861 int nr = sensor_attr->index;
862 u32 val = simple_strtoul(buf, NULL, 10);
863 u16 reg;
864
865 if (val > 1)
866 return -EINVAL;
867 mutex_lock(&data->update_lock);
868 reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
869 data->pwm_mode[nr] = val;
870 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
871 if (!val)
872 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
873 w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
874 mutex_unlock(&data->update_lock);
875 return count;
876}
877
878static ssize_t
879store_pwm(struct device *dev, struct device_attribute *attr,
880 const char *buf, size_t count)
881{
882 struct i2c_client *client = to_i2c_client(dev);
883 struct w83627ehf_data *data = i2c_get_clientdata(client);
884 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
885 int nr = sensor_attr->index;
886 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
887
888 mutex_lock(&data->update_lock);
889 data->pwm[nr] = val;
890 w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
891 mutex_unlock(&data->update_lock);
892 return count;
893}
894
895static ssize_t
896store_pwm_enable(struct device *dev, struct device_attribute *attr,
897 const char *buf, size_t count)
898{
899 struct i2c_client *client = to_i2c_client(dev);
900 struct w83627ehf_data *data = i2c_get_clientdata(client);
901 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
902 int nr = sensor_attr->index;
903 u32 val = simple_strtoul(buf, NULL, 10);
904 u16 reg;
905
906 if (!val || (val > 2)) /* only modes 1 and 2 are supported */
907 return -EINVAL;
908 mutex_lock(&data->update_lock);
909 reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
910 data->pwm_enable[nr] = val;
911 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
912 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
913 w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
914 mutex_unlock(&data->update_lock);
915 return count;
916}
917
918
919#define show_tol_temp(reg) \
920static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
921 char *buf) \
922{ \
923 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
924 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
925 int nr = sensor_attr->index; \
926 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
927}
928
929show_tol_temp(tolerance)
930show_tol_temp(target_temp)
931
932static ssize_t
933store_target_temp(struct device *dev, struct device_attribute *attr,
934 const char *buf, size_t count)
935{
936 struct i2c_client *client = to_i2c_client(dev);
937 struct w83627ehf_data *data = i2c_get_clientdata(client);
938 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
939 int nr = sensor_attr->index;
940 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
941
942 mutex_lock(&data->update_lock);
943 data->target_temp[nr] = val;
944 w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
945 mutex_unlock(&data->update_lock);
946 return count;
947}
948
949static ssize_t
950store_tolerance(struct device *dev, struct device_attribute *attr,
951 const char *buf, size_t count)
952{
953 struct i2c_client *client = to_i2c_client(dev);
954 struct w83627ehf_data *data = i2c_get_clientdata(client);
955 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
956 int nr = sensor_attr->index;
957 u16 reg;
958 /* Limit the temp to 0C - 15C */
959 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
960
961 mutex_lock(&data->update_lock);
962 reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
963 data->tolerance[nr] = val;
964 if (nr == 1)
965 reg = (reg & 0x0f) | (val << 4);
966 else
967 reg = (reg & 0xf0) | val;
968 w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
969 mutex_unlock(&data->update_lock);
970 return count;
971}
972
973static struct sensor_device_attribute sda_pwm[] = {
974 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
975 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
976 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
977 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
978};
979
980static struct sensor_device_attribute sda_pwm_mode[] = {
981 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
982 store_pwm_mode, 0),
983 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
984 store_pwm_mode, 1),
985 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
986 store_pwm_mode, 2),
987 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
988 store_pwm_mode, 3),
989};
990
991static struct sensor_device_attribute sda_pwm_enable[] = {
992 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
993 store_pwm_enable, 0),
994 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
995 store_pwm_enable, 1),
996 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
997 store_pwm_enable, 2),
998 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
999 store_pwm_enable, 3),
1000};
1001
1002static struct sensor_device_attribute sda_target_temp[] = {
1003 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1004 store_target_temp, 0),
1005 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1006 store_target_temp, 1),
1007 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1008 store_target_temp, 2),
1009 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1010 store_target_temp, 3),
1011};
1012
1013static struct sensor_device_attribute sda_tolerance[] = {
1014 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1015 store_tolerance, 0),
1016 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1017 store_tolerance, 1),
1018 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1019 store_tolerance, 2),
1020 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1021 store_tolerance, 3),
1022};
1023
Rudolf Marek08c79952006-07-05 18:14:31 +02001024/* Smart Fan registers */
1025
1026#define fan_functions(reg, REG) \
1027static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1028 char *buf) \
1029{ \
1030 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1031 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1032 int nr = sensor_attr->index; \
1033 return sprintf(buf, "%d\n", data->reg[nr]); \
1034}\
1035static ssize_t \
1036store_##reg(struct device *dev, struct device_attribute *attr, \
1037 const char *buf, size_t count) \
1038{\
1039 struct i2c_client *client = to_i2c_client(dev); \
1040 struct w83627ehf_data *data = i2c_get_clientdata(client); \
1041 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1042 int nr = sensor_attr->index; \
1043 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1044 mutex_lock(&data->update_lock); \
1045 data->reg[nr] = val; \
1046 w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
1047 mutex_unlock(&data->update_lock); \
1048 return count; \
1049}
1050
1051fan_functions(fan_min_output, FAN_MIN_OUTPUT)
1052
1053#define fan_time_functions(reg, REG) \
1054static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1055 char *buf) \
1056{ \
1057 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1058 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1059 int nr = sensor_attr->index; \
1060 return sprintf(buf, "%d\n", \
1061 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1062} \
1063\
1064static ssize_t \
1065store_##reg(struct device *dev, struct device_attribute *attr, \
1066 const char *buf, size_t count) \
1067{ \
1068 struct i2c_client *client = to_i2c_client(dev); \
1069 struct w83627ehf_data *data = i2c_get_clientdata(client); \
1070 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1071 int nr = sensor_attr->index; \
1072 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1073 data->pwm_mode[nr]); \
1074 mutex_lock(&data->update_lock); \
1075 data->reg[nr] = val; \
1076 w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
1077 mutex_unlock(&data->update_lock); \
1078 return count; \
1079} \
1080
1081fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1082
1083
1084static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1085 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1086 store_fan_stop_time, 3),
1087 SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1088 store_fan_min_output, 3),
1089};
1090
1091static struct sensor_device_attribute sda_sf3_arrays[] = {
1092 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1093 store_fan_stop_time, 0),
1094 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1095 store_fan_stop_time, 1),
1096 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1097 store_fan_stop_time, 2),
1098 SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1099 store_fan_min_output, 0),
1100 SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1101 store_fan_min_output, 1),
1102 SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1103 store_fan_min_output, 2),
1104};
1105
Jean Delvare08e7e272005-04-25 22:43:25 +02001106/*
1107 * Driver and client management
1108 */
1109
David Hubbardc18beb52006-09-24 21:04:38 +02001110static void w83627ehf_device_remove_files(struct device *dev)
1111{
1112 /* some entries in the following arrays may not have been used in
1113 * device_create_file(), but device_remove_file() will ignore them */
1114 int i;
1115
1116 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1117 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
1118 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1119 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
1120 for (i = 0; i < 10; i++) {
1121 device_remove_file(dev, &sda_in_input[i].dev_attr);
1122 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1123 device_remove_file(dev, &sda_in_min[i].dev_attr);
1124 device_remove_file(dev, &sda_in_max[i].dev_attr);
1125 }
1126 for (i = 0; i < 5; i++) {
1127 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1128 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1129 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1130 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1131 }
1132 for (i = 0; i < 4; i++) {
1133 device_remove_file(dev, &sda_pwm[i].dev_attr);
1134 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1135 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1136 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1137 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1138 }
1139 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
1140 device_remove_file(dev, &sda_temp[i].dev_attr);
1141}
1142
Jean Delvare08e7e272005-04-25 22:43:25 +02001143static struct i2c_driver w83627ehf_driver;
1144
1145static void w83627ehf_init_client(struct i2c_client *client)
1146{
1147 int i;
1148 u8 tmp;
1149
1150 /* Start monitoring is needed */
1151 tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
1152 if (!(tmp & 0x01))
1153 w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
1154 tmp | 0x01);
1155
1156 /* Enable temp2 and temp3 if needed */
1157 for (i = 0; i < 2; i++) {
1158 tmp = w83627ehf_read_value(client,
1159 W83627EHF_REG_TEMP_CONFIG[i]);
1160 if (tmp & 0x01)
1161 w83627ehf_write_value(client,
1162 W83627EHF_REG_TEMP_CONFIG[i],
1163 tmp & 0xfe);
1164 }
1165}
1166
Jean Delvare2d8672c2005-07-19 23:56:35 +02001167static int w83627ehf_detect(struct i2c_adapter *adapter)
Jean Delvare08e7e272005-04-25 22:43:25 +02001168{
1169 struct i2c_client *client;
1170 struct w83627ehf_data *data;
Yuan Mu412fec82006-02-05 23:24:16 +01001171 struct device *dev;
Rudolf Marek08c79952006-07-05 18:14:31 +02001172 u8 fan4pin, fan5pin;
Jean Delvare08e7e272005-04-25 22:43:25 +02001173 int i, err = 0;
1174
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001175 if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001176 w83627ehf_driver.driver.name)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001177 err = -EBUSY;
1178 goto exit;
1179 }
1180
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001181 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001182 err = -ENOMEM;
1183 goto exit_release;
1184 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001185
1186 client = &data->client;
1187 i2c_set_clientdata(client, data);
1188 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001189 mutex_init(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +02001190 client->adapter = adapter;
1191 client->driver = &w83627ehf_driver;
1192 client->flags = 0;
Yuan Mu412fec82006-02-05 23:24:16 +01001193 dev = &client->dev;
Jean Delvare08e7e272005-04-25 22:43:25 +02001194
1195 strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
1196 data->valid = 0;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001197 mutex_init(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +02001198
1199 /* Tell the i2c layer a new client has arrived */
1200 if ((err = i2c_attach_client(client)))
1201 goto exit_free;
1202
1203 /* Initialize the chip */
1204 w83627ehf_init_client(client);
1205
1206 /* A few vars need to be filled upon startup */
1207 for (i = 0; i < 5; i++)
1208 data->fan_min[i] = w83627ehf_read_value(client,
1209 W83627EHF_REG_FAN_MIN[i]);
1210
Rudolf Marek08c79952006-07-05 18:14:31 +02001211 /* fan4 and fan5 share some pins with the GPIO and serial flash */
1212
1213 superio_enter();
1214 fan5pin = superio_inb(0x24) & 0x2;
1215 fan4pin = superio_inb(0x29) & 0x6;
1216 superio_exit();
1217
Jean Delvare08e7e272005-04-25 22:43:25 +02001218 /* It looks like fan4 and fan5 pins can be alternatively used
1219 as fan on/off switches */
Rudolf Marek08c79952006-07-05 18:14:31 +02001220
Jean Delvare08e7e272005-04-25 22:43:25 +02001221 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
1222 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
Rudolf Marek08c79952006-07-05 18:14:31 +02001223 if ((i & (1 << 2)) && (!fan4pin))
Jean Delvare08e7e272005-04-25 22:43:25 +02001224 data->has_fan |= (1 << 3);
Rudolf Marek08c79952006-07-05 18:14:31 +02001225 if ((i & (1 << 0)) && (!fan5pin))
Jean Delvare08e7e272005-04-25 22:43:25 +02001226 data->has_fan |= (1 << 4);
1227
1228 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001229 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001230 if ((err = device_create_file(dev,
1231 &sda_sf3_arrays[i].dev_attr)))
1232 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001233
1234 /* if fan4 is enabled create the sf3 files for it */
1235 if (data->has_fan & (1 << 3))
David Hubbardc18beb52006-09-24 21:04:38 +02001236 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1237 if ((err = device_create_file(dev,
1238 &sda_sf3_arrays_fan4[i].dev_attr)))
1239 goto exit_remove;
1240 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001241
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001242 for (i = 0; i < 10; i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001243 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1244 || (err = device_create_file(dev,
1245 &sda_in_alarm[i].dev_attr))
1246 || (err = device_create_file(dev,
1247 &sda_in_min[i].dev_attr))
1248 || (err = device_create_file(dev,
1249 &sda_in_max[i].dev_attr)))
1250 goto exit_remove;
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001251
Yuan Mu412fec82006-02-05 23:24:16 +01001252 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001253 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001254 if ((err = device_create_file(dev,
1255 &sda_fan_input[i].dev_attr))
1256 || (err = device_create_file(dev,
1257 &sda_fan_alarm[i].dev_attr))
1258 || (err = device_create_file(dev,
1259 &sda_fan_div[i].dev_attr))
1260 || (err = device_create_file(dev,
1261 &sda_fan_min[i].dev_attr)))
1262 goto exit_remove;
1263 if (i < 4 && /* w83627ehf only has 4 pwm */
1264 ((err = device_create_file(dev,
1265 &sda_pwm[i].dev_attr))
1266 || (err = device_create_file(dev,
1267 &sda_pwm_mode[i].dev_attr))
1268 || (err = device_create_file(dev,
1269 &sda_pwm_enable[i].dev_attr))
1270 || (err = device_create_file(dev,
1271 &sda_target_temp[i].dev_attr))
1272 || (err = device_create_file(dev,
1273 &sda_tolerance[i].dev_attr))))
1274 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001275 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001276 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001277
Yuan Mu412fec82006-02-05 23:24:16 +01001278 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001279 if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
1280 goto exit_remove;
1281
1282 data->class_dev = hwmon_device_register(dev);
1283 if (IS_ERR(data->class_dev)) {
1284 err = PTR_ERR(data->class_dev);
1285 goto exit_remove;
1286 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001287
1288 return 0;
1289
David Hubbardc18beb52006-09-24 21:04:38 +02001290exit_remove:
1291 w83627ehf_device_remove_files(dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001292 i2c_detach_client(client);
Jean Delvare08e7e272005-04-25 22:43:25 +02001293exit_free:
1294 kfree(data);
1295exit_release:
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001296 release_region(address + REGION_OFFSET, REGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001297exit:
1298 return err;
1299}
1300
Jean Delvare08e7e272005-04-25 22:43:25 +02001301static int w83627ehf_detach_client(struct i2c_client *client)
1302{
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001303 struct w83627ehf_data *data = i2c_get_clientdata(client);
Jean Delvare08e7e272005-04-25 22:43:25 +02001304 int err;
1305
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001306 hwmon_device_unregister(data->class_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001307 w83627ehf_device_remove_files(&client->dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001308
Jean Delvare7bef5592005-07-27 22:14:49 +02001309 if ((err = i2c_detach_client(client)))
Jean Delvare08e7e272005-04-25 22:43:25 +02001310 return err;
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001311 release_region(client->addr + REGION_OFFSET, REGION_LENGTH);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001312 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001313
1314 return 0;
1315}
1316
1317static struct i2c_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001318 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001319 .owner = THIS_MODULE,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001320 .name = "w83627ehf",
1321 },
Jean Delvare2d8672c2005-07-19 23:56:35 +02001322 .attach_adapter = w83627ehf_detect,
Jean Delvare08e7e272005-04-25 22:43:25 +02001323 .detach_client = w83627ehf_detach_client,
1324};
1325
Jean Delvare2d8672c2005-07-19 23:56:35 +02001326static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
Jean Delvare08e7e272005-04-25 22:43:25 +02001327{
1328 u16 val;
1329
1330 REG = sioaddr;
1331 VAL = sioaddr + 1;
1332 superio_enter();
1333
1334 val = (superio_inb(SIO_REG_DEVID) << 8)
1335 | superio_inb(SIO_REG_DEVID + 1);
1336 if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
1337 superio_exit();
1338 return -ENODEV;
1339 }
1340
1341 superio_select(W83627EHF_LD_HWM);
1342 val = (superio_inb(SIO_REG_ADDR) << 8)
1343 | superio_inb(SIO_REG_ADDR + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001344 *addr = val & REGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001345 if (*addr == 0) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001346 superio_exit();
1347 return -ENODEV;
1348 }
1349
1350 /* Activate logical device if needed */
1351 val = superio_inb(SIO_REG_ENABLE);
1352 if (!(val & 0x01))
1353 superio_outb(SIO_REG_ENABLE, val | 0x01);
1354
1355 superio_exit();
1356 return 0;
1357}
1358
1359static int __init sensors_w83627ehf_init(void)
1360{
Jean Delvare2d8672c2005-07-19 23:56:35 +02001361 if (w83627ehf_find(0x2e, &address)
1362 && w83627ehf_find(0x4e, &address))
Jean Delvare08e7e272005-04-25 22:43:25 +02001363 return -ENODEV;
1364
Jean Delvarefde09502005-07-19 23:51:07 +02001365 return i2c_isa_add_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001366}
1367
1368static void __exit sensors_w83627ehf_exit(void)
1369{
Jean Delvarefde09502005-07-19 23:51:07 +02001370 i2c_isa_del_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001371}
1372
1373MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1374MODULE_DESCRIPTION("W83627EHF driver");
1375MODULE_LICENSE("GPL");
1376
1377module_init(sensors_w83627ehf_init);
1378module_exit(sensors_w83627ehf_exit);