blob: 1affaf15beda3957792456fb6e5c7c1122606890 [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>
5
6 Shamelessly ripped from the w83627hf driver
7 Copyright (C) 2003 Mark Studebaker
8
9 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
10 in testing and debugging this driver.
11
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020012 This driver also supports the W83627EHG, which is the lead-free
13 version of the W83627EHF.
14
Jean Delvare08e7e272005-04-25 22:43:25 +020015 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28
29
30 Supports the following chips:
31
32 Chip #vin #fan #pwm #temp chip_id man_id
33 w83627ehf - 5 - 3 0x88 0x5ca3
34
35 This is a preliminary version of the driver, only supporting the
36 fan and temperature inputs. The chip does much more than that.
37*/
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>
45#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010046#include <linux/mutex.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020047#include <asm/io.h>
48#include "lm75.h"
49
Jean Delvare2d8672c2005-07-19 23:56:35 +020050/* The actual ISA address is read from Super-I/O configuration space */
51static unsigned short address;
Jean Delvare08e7e272005-04-25 22:43:25 +020052
53/*
54 * Super-I/O constants and functions
55 */
56
57static int REG; /* The register to read/write */
58static int VAL; /* The value to read/write */
59
60#define W83627EHF_LD_HWM 0x0b
61
62#define SIO_REG_LDSEL 0x07 /* Logical device select */
63#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
64#define SIO_REG_ENABLE 0x30 /* Logical device enable */
65#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
66
67#define SIO_W83627EHF_ID 0x8840
68#define SIO_ID_MASK 0xFFC0
69
70static inline void
71superio_outb(int reg, int val)
72{
73 outb(reg, REG);
74 outb(val, VAL);
75}
76
77static inline int
78superio_inb(int reg)
79{
80 outb(reg, REG);
81 return inb(VAL);
82}
83
84static inline void
85superio_select(int ld)
86{
87 outb(SIO_REG_LDSEL, REG);
88 outb(ld, VAL);
89}
90
91static inline void
92superio_enter(void)
93{
94 outb(0x87, REG);
95 outb(0x87, REG);
96}
97
98static inline void
99superio_exit(void)
100{
101 outb(0x02, REG);
102 outb(0x02, VAL);
103}
104
105/*
106 * ISA constants
107 */
108
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200109#define REGION_ALIGNMENT ~7
110#define REGION_OFFSET 5
111#define REGION_LENGTH 2
Jean Delvare08e7e272005-04-25 22:43:25 +0200112#define ADDR_REG_OFFSET 5
113#define DATA_REG_OFFSET 6
114
115#define W83627EHF_REG_BANK 0x4E
116#define W83627EHF_REG_CONFIG 0x40
117#define W83627EHF_REG_CHIP_ID 0x49
118#define W83627EHF_REG_MAN_ID 0x4F
119
120static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
121static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
122
123#define W83627EHF_REG_TEMP1 0x27
124#define W83627EHF_REG_TEMP1_HYST 0x3a
125#define W83627EHF_REG_TEMP1_OVER 0x39
126static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
127static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
128static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
129static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
130
131/* Fan clock dividers are spread over the following five registers */
132#define W83627EHF_REG_FANDIV1 0x47
133#define W83627EHF_REG_FANDIV2 0x4B
134#define W83627EHF_REG_VBAT 0x5D
135#define W83627EHF_REG_DIODE 0x59
136#define W83627EHF_REG_SMI_OVT 0x4C
137
138/*
139 * Conversions
140 */
141
142static inline unsigned int
143fan_from_reg(u8 reg, unsigned int div)
144{
145 if (reg == 0 || reg == 255)
146 return 0;
147 return 1350000U / (reg * div);
148}
149
150static inline unsigned int
151div_from_reg(u8 reg)
152{
153 return 1 << reg;
154}
155
156static inline int
157temp1_from_reg(s8 reg)
158{
159 return reg * 1000;
160}
161
162static inline s8
163temp1_to_reg(int temp)
164{
165 if (temp <= -128000)
166 return -128;
167 if (temp >= 127000)
168 return 127;
169 if (temp < 0)
170 return (temp - 500) / 1000;
171 return (temp + 500) / 1000;
172}
173
174/*
175 * Data structures and manipulation thereof
176 */
177
178struct w83627ehf_data {
179 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400180 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100181 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200182
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100183 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200184 char valid; /* !=0 if following fields are valid */
185 unsigned long last_updated; /* In jiffies */
186
187 /* Register values */
188 u8 fan[5];
189 u8 fan_min[5];
190 u8 fan_div[5];
191 u8 has_fan; /* some fan inputs can be disabled */
192 s8 temp1;
193 s8 temp1_max;
194 s8 temp1_max_hyst;
195 s16 temp[2];
196 s16 temp_max[2];
197 s16 temp_max_hyst[2];
198};
199
200static inline int is_word_sized(u16 reg)
201{
202 return (((reg & 0xff00) == 0x100
203 || (reg & 0xff00) == 0x200)
204 && ((reg & 0x00ff) == 0x50
205 || (reg & 0x00ff) == 0x53
206 || (reg & 0x00ff) == 0x55));
207}
208
209/* We assume that the default bank is 0, thus the following two functions do
210 nothing for registers which live in bank 0. For others, they respectively
211 set the bank register to the correct value (before the register is
212 accessed), and back to 0 (afterwards). */
213static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
214{
215 if (reg & 0xff00) {
216 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
217 outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
218 }
219}
220
221static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
222{
223 if (reg & 0xff00) {
224 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
225 outb_p(0, client->addr + DATA_REG_OFFSET);
226 }
227}
228
229static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
230{
231 struct w83627ehf_data *data = i2c_get_clientdata(client);
232 int res, word_sized = is_word_sized(reg);
233
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100234 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200235
236 w83627ehf_set_bank(client, reg);
237 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
238 res = inb_p(client->addr + DATA_REG_OFFSET);
239 if (word_sized) {
240 outb_p((reg & 0xff) + 1,
241 client->addr + ADDR_REG_OFFSET);
242 res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
243 }
244 w83627ehf_reset_bank(client, reg);
245
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100246 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200247
248 return res;
249}
250
251static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
252{
253 struct w83627ehf_data *data = i2c_get_clientdata(client);
254 int word_sized = is_word_sized(reg);
255
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100256 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200257
258 w83627ehf_set_bank(client, reg);
259 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
260 if (word_sized) {
261 outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
262 outb_p((reg & 0xff) + 1,
263 client->addr + ADDR_REG_OFFSET);
264 }
265 outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
266 w83627ehf_reset_bank(client, reg);
267
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100268 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200269 return 0;
270}
271
272/* This function assumes that the caller holds data->update_lock */
273static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
274{
275 struct w83627ehf_data *data = i2c_get_clientdata(client);
276 u8 reg;
277
278 switch (nr) {
279 case 0:
280 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
281 | ((data->fan_div[0] & 0x03) << 4);
282 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
283 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
284 | ((data->fan_div[0] & 0x04) << 3);
285 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
286 break;
287 case 1:
288 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
289 | ((data->fan_div[1] & 0x03) << 6);
290 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
291 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
292 | ((data->fan_div[1] & 0x04) << 4);
293 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
294 break;
295 case 2:
296 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
297 | ((data->fan_div[2] & 0x03) << 6);
298 w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
299 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
300 | ((data->fan_div[2] & 0x04) << 5);
301 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
302 break;
303 case 3:
304 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
305 | (data->fan_div[3] & 0x03);
306 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
307 reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
308 | ((data->fan_div[3] & 0x04) << 5);
309 w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
310 break;
311 case 4:
312 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
313 | ((data->fan_div[4] & 0x03) << 3)
314 | ((data->fan_div[4] & 0x04) << 5);
315 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
316 break;
317 }
318}
319
320static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
321{
322 struct i2c_client *client = to_i2c_client(dev);
323 struct w83627ehf_data *data = i2c_get_clientdata(client);
324 int i;
325
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100326 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200327
328 if (time_after(jiffies, data->last_updated + HZ)
329 || !data->valid) {
330 /* Fan clock dividers */
331 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
332 data->fan_div[0] = (i >> 4) & 0x03;
333 data->fan_div[1] = (i >> 6) & 0x03;
334 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
335 data->fan_div[2] = (i >> 6) & 0x03;
336 i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
337 data->fan_div[0] |= (i >> 3) & 0x04;
338 data->fan_div[1] |= (i >> 4) & 0x04;
339 data->fan_div[2] |= (i >> 5) & 0x04;
340 if (data->has_fan & ((1 << 3) | (1 << 4))) {
341 i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
342 data->fan_div[3] = i & 0x03;
343 data->fan_div[4] = ((i >> 2) & 0x03)
344 | ((i >> 5) & 0x04);
345 }
346 if (data->has_fan & (1 << 3)) {
347 i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
348 data->fan_div[3] |= (i >> 5) & 0x04;
349 }
350
351 /* Measured fan speeds and limits */
352 for (i = 0; i < 5; i++) {
353 if (!(data->has_fan & (1 << i)))
354 continue;
355
356 data->fan[i] = w83627ehf_read_value(client,
357 W83627EHF_REG_FAN[i]);
358 data->fan_min[i] = w83627ehf_read_value(client,
359 W83627EHF_REG_FAN_MIN[i]);
360
361 /* If we failed to measure the fan speed and clock
362 divider can be increased, let's try that for next
363 time */
364 if (data->fan[i] == 0xff
365 && data->fan_div[i] < 0x07) {
366 dev_dbg(&client->dev, "Increasing fan %d "
367 "clock divider from %u to %u\n",
368 i, div_from_reg(data->fan_div[i]),
369 div_from_reg(data->fan_div[i] + 1));
370 data->fan_div[i]++;
371 w83627ehf_write_fan_div(client, i);
372 /* Preserve min limit if possible */
373 if (data->fan_min[i] >= 2
374 && data->fan_min[i] != 255)
375 w83627ehf_write_value(client,
376 W83627EHF_REG_FAN_MIN[i],
377 (data->fan_min[i] /= 2));
378 }
379 }
380
381 /* Measured temperatures and limits */
382 data->temp1 = w83627ehf_read_value(client,
383 W83627EHF_REG_TEMP1);
384 data->temp1_max = w83627ehf_read_value(client,
385 W83627EHF_REG_TEMP1_OVER);
386 data->temp1_max_hyst = w83627ehf_read_value(client,
387 W83627EHF_REG_TEMP1_HYST);
388 for (i = 0; i < 2; i++) {
389 data->temp[i] = w83627ehf_read_value(client,
390 W83627EHF_REG_TEMP[i]);
391 data->temp_max[i] = w83627ehf_read_value(client,
392 W83627EHF_REG_TEMP_OVER[i]);
393 data->temp_max_hyst[i] = w83627ehf_read_value(client,
394 W83627EHF_REG_TEMP_HYST[i]);
395 }
396
397 data->last_updated = jiffies;
398 data->valid = 1;
399 }
400
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100401 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200402 return data;
403}
404
405/*
406 * Sysfs callback functions
407 */
408
409#define show_fan_reg(reg) \
410static ssize_t \
411show_##reg(struct device *dev, char *buf, int nr) \
412{ \
413 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
414 return sprintf(buf, "%d\n", \
415 fan_from_reg(data->reg[nr], \
416 div_from_reg(data->fan_div[nr]))); \
417}
418show_fan_reg(fan);
419show_fan_reg(fan_min);
420
421static ssize_t
422show_fan_div(struct device *dev, char *buf, int nr)
423{
424 struct w83627ehf_data *data = w83627ehf_update_device(dev);
425 return sprintf(buf, "%u\n",
426 div_from_reg(data->fan_div[nr]));
427}
428
429static ssize_t
430store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
431{
432 struct i2c_client *client = to_i2c_client(dev);
433 struct w83627ehf_data *data = i2c_get_clientdata(client);
434 unsigned int val = simple_strtoul(buf, NULL, 10);
435 unsigned int reg;
436 u8 new_div;
437
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100438 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200439 if (!val) {
440 /* No min limit, alarm disabled */
441 data->fan_min[nr] = 255;
442 new_div = data->fan_div[nr]; /* No change */
443 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
444 } else if ((reg = 1350000U / val) >= 128 * 255) {
445 /* Speed below this value cannot possibly be represented,
446 even with the highest divider (128) */
447 data->fan_min[nr] = 254;
448 new_div = 7; /* 128 == (1 << 7) */
449 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
450 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
451 } else if (!reg) {
452 /* Speed above this value cannot possibly be represented,
453 even with the lowest divider (1) */
454 data->fan_min[nr] = 1;
455 new_div = 0; /* 1 == (1 << 0) */
456 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200457 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200458 } else {
459 /* Automatically pick the best divider, i.e. the one such
460 that the min limit will correspond to a register value
461 in the 96..192 range */
462 new_div = 0;
463 while (reg > 192 && new_div < 7) {
464 reg >>= 1;
465 new_div++;
466 }
467 data->fan_min[nr] = reg;
468 }
469
470 /* Write both the fan clock divider (if it changed) and the new
471 fan min (unconditionally) */
472 if (new_div != data->fan_div[nr]) {
473 if (new_div > data->fan_div[nr])
474 data->fan[nr] >>= (data->fan_div[nr] - new_div);
475 else
476 data->fan[nr] <<= (new_div - data->fan_div[nr]);
477
478 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
479 nr + 1, div_from_reg(data->fan_div[nr]),
480 div_from_reg(new_div));
481 data->fan_div[nr] = new_div;
482 w83627ehf_write_fan_div(client, nr);
483 }
484 w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
485 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100486 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200487
488 return count;
489}
490
491#define sysfs_fan_offset(offset) \
492static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700493show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \
494 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200495{ \
496 return show_fan(dev, buf, offset-1); \
497} \
498static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
499 show_reg_fan_##offset, NULL);
500
501#define sysfs_fan_min_offset(offset) \
502static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700503show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
504 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200505{ \
506 return show_fan_min(dev, buf, offset-1); \
507} \
508static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700509store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
510 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200511{ \
512 return store_fan_min(dev, buf, count, offset-1); \
513} \
514static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
515 show_reg_fan##offset##_min, \
516 store_reg_fan##offset##_min);
517
518#define sysfs_fan_div_offset(offset) \
519static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700520show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \
521 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200522{ \
523 return show_fan_div(dev, buf, offset - 1); \
524} \
525static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
526 show_reg_fan##offset##_div, NULL);
527
528sysfs_fan_offset(1);
529sysfs_fan_min_offset(1);
530sysfs_fan_div_offset(1);
531sysfs_fan_offset(2);
532sysfs_fan_min_offset(2);
533sysfs_fan_div_offset(2);
534sysfs_fan_offset(3);
535sysfs_fan_min_offset(3);
536sysfs_fan_div_offset(3);
537sysfs_fan_offset(4);
538sysfs_fan_min_offset(4);
539sysfs_fan_div_offset(4);
540sysfs_fan_offset(5);
541sysfs_fan_min_offset(5);
542sysfs_fan_div_offset(5);
543
544#define show_temp1_reg(reg) \
545static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700546show_##reg(struct device *dev, struct device_attribute *attr, \
547 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200548{ \
549 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
550 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
551}
552show_temp1_reg(temp1);
553show_temp1_reg(temp1_max);
554show_temp1_reg(temp1_max_hyst);
555
556#define store_temp1_reg(REG, reg) \
557static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700558store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
559 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200560{ \
561 struct i2c_client *client = to_i2c_client(dev); \
562 struct w83627ehf_data *data = i2c_get_clientdata(client); \
563 u32 val = simple_strtoul(buf, NULL, 10); \
564 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100565 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200566 data->temp1_##reg = temp1_to_reg(val); \
567 w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
568 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100569 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200570 return count; \
571}
572store_temp1_reg(OVER, max);
573store_temp1_reg(HYST, max_hyst);
574
575static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
576static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR,
577 show_temp1_max, store_temp1_max);
578static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR,
579 show_temp1_max_hyst, store_temp1_max_hyst);
580
581#define show_temp_reg(reg) \
582static ssize_t \
583show_##reg (struct device *dev, char *buf, int nr) \
584{ \
585 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
586 return sprintf(buf, "%d\n", \
587 LM75_TEMP_FROM_REG(data->reg[nr])); \
588}
589show_temp_reg(temp);
590show_temp_reg(temp_max);
591show_temp_reg(temp_max_hyst);
592
593#define store_temp_reg(REG, reg) \
594static ssize_t \
595store_##reg (struct device *dev, const char *buf, size_t count, int nr) \
596{ \
597 struct i2c_client *client = to_i2c_client(dev); \
598 struct w83627ehf_data *data = i2c_get_clientdata(client); \
599 u32 val = simple_strtoul(buf, NULL, 10); \
600 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100601 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200602 data->reg[nr] = LM75_TEMP_TO_REG(val); \
603 w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
604 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100605 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200606 return count; \
607}
608store_temp_reg(OVER, temp_max);
609store_temp_reg(HYST, temp_max_hyst);
610
611#define sysfs_temp_offset(offset) \
612static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700613show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \
614 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200615{ \
616 return show_temp(dev, buf, offset - 2); \
617} \
618static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
619 show_reg_temp##offset, NULL);
620
621#define sysfs_temp_reg_offset(reg, offset) \
622static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700623show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
624 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200625{ \
626 return show_temp_##reg(dev, buf, offset - 2); \
627} \
628static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700629store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
630 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200631{ \
632 return store_temp_##reg(dev, buf, count, offset - 2); \
633} \
634static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
635 show_reg_temp##offset##_##reg, \
636 store_reg_temp##offset##_##reg);
637
638sysfs_temp_offset(2);
639sysfs_temp_reg_offset(max, 2);
640sysfs_temp_reg_offset(max_hyst, 2);
641sysfs_temp_offset(3);
642sysfs_temp_reg_offset(max, 3);
643sysfs_temp_reg_offset(max_hyst, 3);
644
645/*
646 * Driver and client management
647 */
648
649static struct i2c_driver w83627ehf_driver;
650
651static void w83627ehf_init_client(struct i2c_client *client)
652{
653 int i;
654 u8 tmp;
655
656 /* Start monitoring is needed */
657 tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
658 if (!(tmp & 0x01))
659 w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
660 tmp | 0x01);
661
662 /* Enable temp2 and temp3 if needed */
663 for (i = 0; i < 2; i++) {
664 tmp = w83627ehf_read_value(client,
665 W83627EHF_REG_TEMP_CONFIG[i]);
666 if (tmp & 0x01)
667 w83627ehf_write_value(client,
668 W83627EHF_REG_TEMP_CONFIG[i],
669 tmp & 0xfe);
670 }
671}
672
Jean Delvare2d8672c2005-07-19 23:56:35 +0200673static int w83627ehf_detect(struct i2c_adapter *adapter)
Jean Delvare08e7e272005-04-25 22:43:25 +0200674{
675 struct i2c_client *client;
676 struct w83627ehf_data *data;
677 int i, err = 0;
678
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200679 if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100680 w83627ehf_driver.driver.name)) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200681 err = -EBUSY;
682 goto exit;
683 }
684
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200685 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200686 err = -ENOMEM;
687 goto exit_release;
688 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200689
690 client = &data->client;
691 i2c_set_clientdata(client, data);
692 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100693 mutex_init(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200694 client->adapter = adapter;
695 client->driver = &w83627ehf_driver;
696 client->flags = 0;
697
698 strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
699 data->valid = 0;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100700 mutex_init(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200701
702 /* Tell the i2c layer a new client has arrived */
703 if ((err = i2c_attach_client(client)))
704 goto exit_free;
705
706 /* Initialize the chip */
707 w83627ehf_init_client(client);
708
709 /* A few vars need to be filled upon startup */
710 for (i = 0; i < 5; i++)
711 data->fan_min[i] = w83627ehf_read_value(client,
712 W83627EHF_REG_FAN_MIN[i]);
713
714 /* It looks like fan4 and fan5 pins can be alternatively used
715 as fan on/off switches */
716 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
717 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
718 if (i & (1 << 2))
719 data->has_fan |= (1 << 3);
720 if (i & (1 << 0))
721 data->has_fan |= (1 << 4);
722
723 /* Register sysfs hooks */
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400724 data->class_dev = hwmon_device_register(&client->dev);
725 if (IS_ERR(data->class_dev)) {
726 err = PTR_ERR(data->class_dev);
727 goto exit_detach;
728 }
729
Jean Delvare08e7e272005-04-25 22:43:25 +0200730 device_create_file(&client->dev, &dev_attr_fan1_input);
731 device_create_file(&client->dev, &dev_attr_fan1_min);
732 device_create_file(&client->dev, &dev_attr_fan1_div);
733 device_create_file(&client->dev, &dev_attr_fan2_input);
734 device_create_file(&client->dev, &dev_attr_fan2_min);
735 device_create_file(&client->dev, &dev_attr_fan2_div);
736 device_create_file(&client->dev, &dev_attr_fan3_input);
737 device_create_file(&client->dev, &dev_attr_fan3_min);
738 device_create_file(&client->dev, &dev_attr_fan3_div);
739
740 if (data->has_fan & (1 << 3)) {
741 device_create_file(&client->dev, &dev_attr_fan4_input);
742 device_create_file(&client->dev, &dev_attr_fan4_min);
743 device_create_file(&client->dev, &dev_attr_fan4_div);
744 }
745 if (data->has_fan & (1 << 4)) {
746 device_create_file(&client->dev, &dev_attr_fan5_input);
747 device_create_file(&client->dev, &dev_attr_fan5_min);
748 device_create_file(&client->dev, &dev_attr_fan5_div);
749 }
750
751 device_create_file(&client->dev, &dev_attr_temp1_input);
752 device_create_file(&client->dev, &dev_attr_temp1_max);
753 device_create_file(&client->dev, &dev_attr_temp1_max_hyst);
754 device_create_file(&client->dev, &dev_attr_temp2_input);
755 device_create_file(&client->dev, &dev_attr_temp2_max);
756 device_create_file(&client->dev, &dev_attr_temp2_max_hyst);
757 device_create_file(&client->dev, &dev_attr_temp3_input);
758 device_create_file(&client->dev, &dev_attr_temp3_max);
759 device_create_file(&client->dev, &dev_attr_temp3_max_hyst);
760
761 return 0;
762
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400763exit_detach:
764 i2c_detach_client(client);
Jean Delvare08e7e272005-04-25 22:43:25 +0200765exit_free:
766 kfree(data);
767exit_release:
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200768 release_region(address + REGION_OFFSET, REGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +0200769exit:
770 return err;
771}
772
Jean Delvare08e7e272005-04-25 22:43:25 +0200773static int w83627ehf_detach_client(struct i2c_client *client)
774{
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400775 struct w83627ehf_data *data = i2c_get_clientdata(client);
Jean Delvare08e7e272005-04-25 22:43:25 +0200776 int err;
777
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400778 hwmon_device_unregister(data->class_dev);
779
Jean Delvare7bef5592005-07-27 22:14:49 +0200780 if ((err = i2c_detach_client(client)))
Jean Delvare08e7e272005-04-25 22:43:25 +0200781 return err;
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200782 release_region(client->addr + REGION_OFFSET, REGION_LENGTH);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400783 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200784
785 return 0;
786}
787
788static struct i2c_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100789 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100790 .name = "w83627ehf",
791 },
Jean Delvare2d8672c2005-07-19 23:56:35 +0200792 .attach_adapter = w83627ehf_detect,
Jean Delvare08e7e272005-04-25 22:43:25 +0200793 .detach_client = w83627ehf_detach_client,
794};
795
Jean Delvare2d8672c2005-07-19 23:56:35 +0200796static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200797{
798 u16 val;
799
800 REG = sioaddr;
801 VAL = sioaddr + 1;
802 superio_enter();
803
804 val = (superio_inb(SIO_REG_DEVID) << 8)
805 | superio_inb(SIO_REG_DEVID + 1);
806 if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
807 superio_exit();
808 return -ENODEV;
809 }
810
811 superio_select(W83627EHF_LD_HWM);
812 val = (superio_inb(SIO_REG_ADDR) << 8)
813 | superio_inb(SIO_REG_ADDR + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200814 *addr = val & REGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +0200815 if (*addr == 0) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200816 superio_exit();
817 return -ENODEV;
818 }
819
820 /* Activate logical device if needed */
821 val = superio_inb(SIO_REG_ENABLE);
822 if (!(val & 0x01))
823 superio_outb(SIO_REG_ENABLE, val | 0x01);
824
825 superio_exit();
826 return 0;
827}
828
829static int __init sensors_w83627ehf_init(void)
830{
Jean Delvare2d8672c2005-07-19 23:56:35 +0200831 if (w83627ehf_find(0x2e, &address)
832 && w83627ehf_find(0x4e, &address))
Jean Delvare08e7e272005-04-25 22:43:25 +0200833 return -ENODEV;
834
Jean Delvarefde09502005-07-19 23:51:07 +0200835 return i2c_isa_add_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +0200836}
837
838static void __exit sensors_w83627ehf_exit(void)
839{
Jean Delvarefde09502005-07-19 23:51:07 +0200840 i2c_isa_del_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +0200841}
842
843MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
844MODULE_DESCRIPTION("W83627EHF driver");
845MODULE_LICENSE("GPL");
846
847module_init(sensors_w83627ehf_init);
848module_exit(sensors_w83627ehf_exit);