blob: b60efe8f8b26691a70bc64f5617d362b68e7a2be [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>
Jean Delvare08e7e272005-04-25 22:43:25 +020046#include <asm/io.h>
47#include "lm75.h"
48
Jean Delvare2d8672c2005-07-19 23:56:35 +020049/* The actual ISA address is read from Super-I/O configuration space */
50static unsigned short address;
Jean Delvare08e7e272005-04-25 22:43:25 +020051
52/*
53 * Super-I/O constants and functions
54 */
55
56static int REG; /* The register to read/write */
57static int VAL; /* The value to read/write */
58
59#define W83627EHF_LD_HWM 0x0b
60
61#define SIO_REG_LDSEL 0x07 /* Logical device select */
62#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
63#define SIO_REG_ENABLE 0x30 /* Logical device enable */
64#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
65
66#define SIO_W83627EHF_ID 0x8840
67#define SIO_ID_MASK 0xFFC0
68
69static inline void
70superio_outb(int reg, int val)
71{
72 outb(reg, REG);
73 outb(val, VAL);
74}
75
76static inline int
77superio_inb(int reg)
78{
79 outb(reg, REG);
80 return inb(VAL);
81}
82
83static inline void
84superio_select(int ld)
85{
86 outb(SIO_REG_LDSEL, REG);
87 outb(ld, VAL);
88}
89
90static inline void
91superio_enter(void)
92{
93 outb(0x87, REG);
94 outb(0x87, REG);
95}
96
97static inline void
98superio_exit(void)
99{
100 outb(0x02, REG);
101 outb(0x02, VAL);
102}
103
104/*
105 * ISA constants
106 */
107
108#define REGION_LENGTH 8
109#define ADDR_REG_OFFSET 5
110#define DATA_REG_OFFSET 6
111
112#define W83627EHF_REG_BANK 0x4E
113#define W83627EHF_REG_CONFIG 0x40
114#define W83627EHF_REG_CHIP_ID 0x49
115#define W83627EHF_REG_MAN_ID 0x4F
116
117static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
118static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
119
120#define W83627EHF_REG_TEMP1 0x27
121#define W83627EHF_REG_TEMP1_HYST 0x3a
122#define W83627EHF_REG_TEMP1_OVER 0x39
123static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
124static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
125static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
126static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
127
128/* Fan clock dividers are spread over the following five registers */
129#define W83627EHF_REG_FANDIV1 0x47
130#define W83627EHF_REG_FANDIV2 0x4B
131#define W83627EHF_REG_VBAT 0x5D
132#define W83627EHF_REG_DIODE 0x59
133#define W83627EHF_REG_SMI_OVT 0x4C
134
135/*
136 * Conversions
137 */
138
139static inline unsigned int
140fan_from_reg(u8 reg, unsigned int div)
141{
142 if (reg == 0 || reg == 255)
143 return 0;
144 return 1350000U / (reg * div);
145}
146
147static inline unsigned int
148div_from_reg(u8 reg)
149{
150 return 1 << reg;
151}
152
153static inline int
154temp1_from_reg(s8 reg)
155{
156 return reg * 1000;
157}
158
159static inline s8
160temp1_to_reg(int temp)
161{
162 if (temp <= -128000)
163 return -128;
164 if (temp >= 127000)
165 return 127;
166 if (temp < 0)
167 return (temp - 500) / 1000;
168 return (temp + 500) / 1000;
169}
170
171/*
172 * Data structures and manipulation thereof
173 */
174
175struct w83627ehf_data {
176 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400177 struct class_device *class_dev;
Jean Delvare08e7e272005-04-25 22:43:25 +0200178 struct semaphore lock;
179
180 struct semaphore update_lock;
181 char valid; /* !=0 if following fields are valid */
182 unsigned long last_updated; /* In jiffies */
183
184 /* Register values */
185 u8 fan[5];
186 u8 fan_min[5];
187 u8 fan_div[5];
188 u8 has_fan; /* some fan inputs can be disabled */
189 s8 temp1;
190 s8 temp1_max;
191 s8 temp1_max_hyst;
192 s16 temp[2];
193 s16 temp_max[2];
194 s16 temp_max_hyst[2];
195};
196
197static inline int is_word_sized(u16 reg)
198{
199 return (((reg & 0xff00) == 0x100
200 || (reg & 0xff00) == 0x200)
201 && ((reg & 0x00ff) == 0x50
202 || (reg & 0x00ff) == 0x53
203 || (reg & 0x00ff) == 0x55));
204}
205
206/* We assume that the default bank is 0, thus the following two functions do
207 nothing for registers which live in bank 0. For others, they respectively
208 set the bank register to the correct value (before the register is
209 accessed), and back to 0 (afterwards). */
210static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
211{
212 if (reg & 0xff00) {
213 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
214 outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
215 }
216}
217
218static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
219{
220 if (reg & 0xff00) {
221 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
222 outb_p(0, client->addr + DATA_REG_OFFSET);
223 }
224}
225
226static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
227{
228 struct w83627ehf_data *data = i2c_get_clientdata(client);
229 int res, word_sized = is_word_sized(reg);
230
231 down(&data->lock);
232
233 w83627ehf_set_bank(client, reg);
234 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
235 res = inb_p(client->addr + DATA_REG_OFFSET);
236 if (word_sized) {
237 outb_p((reg & 0xff) + 1,
238 client->addr + ADDR_REG_OFFSET);
239 res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
240 }
241 w83627ehf_reset_bank(client, reg);
242
243 up(&data->lock);
244
245 return res;
246}
247
248static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
249{
250 struct w83627ehf_data *data = i2c_get_clientdata(client);
251 int word_sized = is_word_sized(reg);
252
253 down(&data->lock);
254
255 w83627ehf_set_bank(client, reg);
256 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
257 if (word_sized) {
258 outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
259 outb_p((reg & 0xff) + 1,
260 client->addr + ADDR_REG_OFFSET);
261 }
262 outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
263 w83627ehf_reset_bank(client, reg);
264
265 up(&data->lock);
266 return 0;
267}
268
269/* This function assumes that the caller holds data->update_lock */
270static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
271{
272 struct w83627ehf_data *data = i2c_get_clientdata(client);
273 u8 reg;
274
275 switch (nr) {
276 case 0:
277 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
278 | ((data->fan_div[0] & 0x03) << 4);
279 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
280 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
281 | ((data->fan_div[0] & 0x04) << 3);
282 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
283 break;
284 case 1:
285 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
286 | ((data->fan_div[1] & 0x03) << 6);
287 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
288 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
289 | ((data->fan_div[1] & 0x04) << 4);
290 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
291 break;
292 case 2:
293 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
294 | ((data->fan_div[2] & 0x03) << 6);
295 w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
296 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
297 | ((data->fan_div[2] & 0x04) << 5);
298 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
299 break;
300 case 3:
301 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
302 | (data->fan_div[3] & 0x03);
303 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
304 reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
305 | ((data->fan_div[3] & 0x04) << 5);
306 w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
307 break;
308 case 4:
309 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
310 | ((data->fan_div[4] & 0x03) << 3)
311 | ((data->fan_div[4] & 0x04) << 5);
312 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
313 break;
314 }
315}
316
317static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
318{
319 struct i2c_client *client = to_i2c_client(dev);
320 struct w83627ehf_data *data = i2c_get_clientdata(client);
321 int i;
322
323 down(&data->update_lock);
324
325 if (time_after(jiffies, data->last_updated + HZ)
326 || !data->valid) {
327 /* Fan clock dividers */
328 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
329 data->fan_div[0] = (i >> 4) & 0x03;
330 data->fan_div[1] = (i >> 6) & 0x03;
331 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
332 data->fan_div[2] = (i >> 6) & 0x03;
333 i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
334 data->fan_div[0] |= (i >> 3) & 0x04;
335 data->fan_div[1] |= (i >> 4) & 0x04;
336 data->fan_div[2] |= (i >> 5) & 0x04;
337 if (data->has_fan & ((1 << 3) | (1 << 4))) {
338 i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
339 data->fan_div[3] = i & 0x03;
340 data->fan_div[4] = ((i >> 2) & 0x03)
341 | ((i >> 5) & 0x04);
342 }
343 if (data->has_fan & (1 << 3)) {
344 i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
345 data->fan_div[3] |= (i >> 5) & 0x04;
346 }
347
348 /* Measured fan speeds and limits */
349 for (i = 0; i < 5; i++) {
350 if (!(data->has_fan & (1 << i)))
351 continue;
352
353 data->fan[i] = w83627ehf_read_value(client,
354 W83627EHF_REG_FAN[i]);
355 data->fan_min[i] = w83627ehf_read_value(client,
356 W83627EHF_REG_FAN_MIN[i]);
357
358 /* If we failed to measure the fan speed and clock
359 divider can be increased, let's try that for next
360 time */
361 if (data->fan[i] == 0xff
362 && data->fan_div[i] < 0x07) {
363 dev_dbg(&client->dev, "Increasing fan %d "
364 "clock divider from %u to %u\n",
365 i, div_from_reg(data->fan_div[i]),
366 div_from_reg(data->fan_div[i] + 1));
367 data->fan_div[i]++;
368 w83627ehf_write_fan_div(client, i);
369 /* Preserve min limit if possible */
370 if (data->fan_min[i] >= 2
371 && data->fan_min[i] != 255)
372 w83627ehf_write_value(client,
373 W83627EHF_REG_FAN_MIN[i],
374 (data->fan_min[i] /= 2));
375 }
376 }
377
378 /* Measured temperatures and limits */
379 data->temp1 = w83627ehf_read_value(client,
380 W83627EHF_REG_TEMP1);
381 data->temp1_max = w83627ehf_read_value(client,
382 W83627EHF_REG_TEMP1_OVER);
383 data->temp1_max_hyst = w83627ehf_read_value(client,
384 W83627EHF_REG_TEMP1_HYST);
385 for (i = 0; i < 2; i++) {
386 data->temp[i] = w83627ehf_read_value(client,
387 W83627EHF_REG_TEMP[i]);
388 data->temp_max[i] = w83627ehf_read_value(client,
389 W83627EHF_REG_TEMP_OVER[i]);
390 data->temp_max_hyst[i] = w83627ehf_read_value(client,
391 W83627EHF_REG_TEMP_HYST[i]);
392 }
393
394 data->last_updated = jiffies;
395 data->valid = 1;
396 }
397
398 up(&data->update_lock);
399 return data;
400}
401
402/*
403 * Sysfs callback functions
404 */
405
406#define show_fan_reg(reg) \
407static ssize_t \
408show_##reg(struct device *dev, char *buf, int nr) \
409{ \
410 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
411 return sprintf(buf, "%d\n", \
412 fan_from_reg(data->reg[nr], \
413 div_from_reg(data->fan_div[nr]))); \
414}
415show_fan_reg(fan);
416show_fan_reg(fan_min);
417
418static ssize_t
419show_fan_div(struct device *dev, char *buf, int nr)
420{
421 struct w83627ehf_data *data = w83627ehf_update_device(dev);
422 return sprintf(buf, "%u\n",
423 div_from_reg(data->fan_div[nr]));
424}
425
426static ssize_t
427store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
428{
429 struct i2c_client *client = to_i2c_client(dev);
430 struct w83627ehf_data *data = i2c_get_clientdata(client);
431 unsigned int val = simple_strtoul(buf, NULL, 10);
432 unsigned int reg;
433 u8 new_div;
434
435 down(&data->update_lock);
436 if (!val) {
437 /* No min limit, alarm disabled */
438 data->fan_min[nr] = 255;
439 new_div = data->fan_div[nr]; /* No change */
440 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
441 } else if ((reg = 1350000U / val) >= 128 * 255) {
442 /* Speed below this value cannot possibly be represented,
443 even with the highest divider (128) */
444 data->fan_min[nr] = 254;
445 new_div = 7; /* 128 == (1 << 7) */
446 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
447 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
448 } else if (!reg) {
449 /* Speed above this value cannot possibly be represented,
450 even with the lowest divider (1) */
451 data->fan_min[nr] = 1;
452 new_div = 0; /* 1 == (1 << 0) */
453 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200454 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200455 } else {
456 /* Automatically pick the best divider, i.e. the one such
457 that the min limit will correspond to a register value
458 in the 96..192 range */
459 new_div = 0;
460 while (reg > 192 && new_div < 7) {
461 reg >>= 1;
462 new_div++;
463 }
464 data->fan_min[nr] = reg;
465 }
466
467 /* Write both the fan clock divider (if it changed) and the new
468 fan min (unconditionally) */
469 if (new_div != data->fan_div[nr]) {
470 if (new_div > data->fan_div[nr])
471 data->fan[nr] >>= (data->fan_div[nr] - new_div);
472 else
473 data->fan[nr] <<= (new_div - data->fan_div[nr]);
474
475 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
476 nr + 1, div_from_reg(data->fan_div[nr]),
477 div_from_reg(new_div));
478 data->fan_div[nr] = new_div;
479 w83627ehf_write_fan_div(client, nr);
480 }
481 w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
482 data->fan_min[nr]);
483 up(&data->update_lock);
484
485 return count;
486}
487
488#define sysfs_fan_offset(offset) \
489static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700490show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \
491 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200492{ \
493 return show_fan(dev, buf, offset-1); \
494} \
495static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
496 show_reg_fan_##offset, NULL);
497
498#define sysfs_fan_min_offset(offset) \
499static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700500show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
501 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200502{ \
503 return show_fan_min(dev, buf, offset-1); \
504} \
505static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700506store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
507 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200508{ \
509 return store_fan_min(dev, buf, count, offset-1); \
510} \
511static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
512 show_reg_fan##offset##_min, \
513 store_reg_fan##offset##_min);
514
515#define sysfs_fan_div_offset(offset) \
516static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700517show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \
518 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200519{ \
520 return show_fan_div(dev, buf, offset - 1); \
521} \
522static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
523 show_reg_fan##offset##_div, NULL);
524
525sysfs_fan_offset(1);
526sysfs_fan_min_offset(1);
527sysfs_fan_div_offset(1);
528sysfs_fan_offset(2);
529sysfs_fan_min_offset(2);
530sysfs_fan_div_offset(2);
531sysfs_fan_offset(3);
532sysfs_fan_min_offset(3);
533sysfs_fan_div_offset(3);
534sysfs_fan_offset(4);
535sysfs_fan_min_offset(4);
536sysfs_fan_div_offset(4);
537sysfs_fan_offset(5);
538sysfs_fan_min_offset(5);
539sysfs_fan_div_offset(5);
540
541#define show_temp1_reg(reg) \
542static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700543show_##reg(struct device *dev, struct device_attribute *attr, \
544 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200545{ \
546 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
547 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
548}
549show_temp1_reg(temp1);
550show_temp1_reg(temp1_max);
551show_temp1_reg(temp1_max_hyst);
552
553#define store_temp1_reg(REG, reg) \
554static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700555store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
556 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200557{ \
558 struct i2c_client *client = to_i2c_client(dev); \
559 struct w83627ehf_data *data = i2c_get_clientdata(client); \
560 u32 val = simple_strtoul(buf, NULL, 10); \
561 \
562 down(&data->update_lock); \
563 data->temp1_##reg = temp1_to_reg(val); \
564 w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
565 data->temp1_##reg); \
566 up(&data->update_lock); \
567 return count; \
568}
569store_temp1_reg(OVER, max);
570store_temp1_reg(HYST, max_hyst);
571
572static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
573static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR,
574 show_temp1_max, store_temp1_max);
575static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR,
576 show_temp1_max_hyst, store_temp1_max_hyst);
577
578#define show_temp_reg(reg) \
579static ssize_t \
580show_##reg (struct device *dev, char *buf, int nr) \
581{ \
582 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
583 return sprintf(buf, "%d\n", \
584 LM75_TEMP_FROM_REG(data->reg[nr])); \
585}
586show_temp_reg(temp);
587show_temp_reg(temp_max);
588show_temp_reg(temp_max_hyst);
589
590#define store_temp_reg(REG, reg) \
591static ssize_t \
592store_##reg (struct device *dev, const char *buf, size_t count, int nr) \
593{ \
594 struct i2c_client *client = to_i2c_client(dev); \
595 struct w83627ehf_data *data = i2c_get_clientdata(client); \
596 u32 val = simple_strtoul(buf, NULL, 10); \
597 \
598 down(&data->update_lock); \
599 data->reg[nr] = LM75_TEMP_TO_REG(val); \
600 w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
601 data->reg[nr]); \
602 up(&data->update_lock); \
603 return count; \
604}
605store_temp_reg(OVER, temp_max);
606store_temp_reg(HYST, temp_max_hyst);
607
608#define sysfs_temp_offset(offset) \
609static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700610show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \
611 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200612{ \
613 return show_temp(dev, buf, offset - 2); \
614} \
615static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
616 show_reg_temp##offset, NULL);
617
618#define sysfs_temp_reg_offset(reg, offset) \
619static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700620show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
621 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200622{ \
623 return show_temp_##reg(dev, buf, offset - 2); \
624} \
625static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700626store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
627 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200628{ \
629 return store_temp_##reg(dev, buf, count, offset - 2); \
630} \
631static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
632 show_reg_temp##offset##_##reg, \
633 store_reg_temp##offset##_##reg);
634
635sysfs_temp_offset(2);
636sysfs_temp_reg_offset(max, 2);
637sysfs_temp_reg_offset(max_hyst, 2);
638sysfs_temp_offset(3);
639sysfs_temp_reg_offset(max, 3);
640sysfs_temp_reg_offset(max_hyst, 3);
641
642/*
643 * Driver and client management
644 */
645
646static struct i2c_driver w83627ehf_driver;
647
648static void w83627ehf_init_client(struct i2c_client *client)
649{
650 int i;
651 u8 tmp;
652
653 /* Start monitoring is needed */
654 tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
655 if (!(tmp & 0x01))
656 w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
657 tmp | 0x01);
658
659 /* Enable temp2 and temp3 if needed */
660 for (i = 0; i < 2; i++) {
661 tmp = w83627ehf_read_value(client,
662 W83627EHF_REG_TEMP_CONFIG[i]);
663 if (tmp & 0x01)
664 w83627ehf_write_value(client,
665 W83627EHF_REG_TEMP_CONFIG[i],
666 tmp & 0xfe);
667 }
668}
669
Jean Delvare2d8672c2005-07-19 23:56:35 +0200670static int w83627ehf_detect(struct i2c_adapter *adapter)
Jean Delvare08e7e272005-04-25 22:43:25 +0200671{
672 struct i2c_client *client;
673 struct w83627ehf_data *data;
674 int i, err = 0;
675
Jean Delvare08e7e272005-04-25 22:43:25 +0200676 if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) {
677 err = -EBUSY;
678 goto exit;
679 }
680
681 if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
682 err = -ENOMEM;
683 goto exit_release;
684 }
685 memset(data, 0, sizeof(struct w83627ehf_data));
686
687 client = &data->client;
688 i2c_set_clientdata(client, data);
689 client->addr = address;
690 init_MUTEX(&data->lock);
691 client->adapter = adapter;
692 client->driver = &w83627ehf_driver;
693 client->flags = 0;
694
695 strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
696 data->valid = 0;
697 init_MUTEX(&data->update_lock);
698
699 /* Tell the i2c layer a new client has arrived */
700 if ((err = i2c_attach_client(client)))
701 goto exit_free;
702
703 /* Initialize the chip */
704 w83627ehf_init_client(client);
705
706 /* A few vars need to be filled upon startup */
707 for (i = 0; i < 5; i++)
708 data->fan_min[i] = w83627ehf_read_value(client,
709 W83627EHF_REG_FAN_MIN[i]);
710
711 /* It looks like fan4 and fan5 pins can be alternatively used
712 as fan on/off switches */
713 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
714 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
715 if (i & (1 << 2))
716 data->has_fan |= (1 << 3);
717 if (i & (1 << 0))
718 data->has_fan |= (1 << 4);
719
720 /* Register sysfs hooks */
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400721 data->class_dev = hwmon_device_register(&client->dev);
722 if (IS_ERR(data->class_dev)) {
723 err = PTR_ERR(data->class_dev);
724 goto exit_detach;
725 }
726
Jean Delvare08e7e272005-04-25 22:43:25 +0200727 device_create_file(&client->dev, &dev_attr_fan1_input);
728 device_create_file(&client->dev, &dev_attr_fan1_min);
729 device_create_file(&client->dev, &dev_attr_fan1_div);
730 device_create_file(&client->dev, &dev_attr_fan2_input);
731 device_create_file(&client->dev, &dev_attr_fan2_min);
732 device_create_file(&client->dev, &dev_attr_fan2_div);
733 device_create_file(&client->dev, &dev_attr_fan3_input);
734 device_create_file(&client->dev, &dev_attr_fan3_min);
735 device_create_file(&client->dev, &dev_attr_fan3_div);
736
737 if (data->has_fan & (1 << 3)) {
738 device_create_file(&client->dev, &dev_attr_fan4_input);
739 device_create_file(&client->dev, &dev_attr_fan4_min);
740 device_create_file(&client->dev, &dev_attr_fan4_div);
741 }
742 if (data->has_fan & (1 << 4)) {
743 device_create_file(&client->dev, &dev_attr_fan5_input);
744 device_create_file(&client->dev, &dev_attr_fan5_min);
745 device_create_file(&client->dev, &dev_attr_fan5_div);
746 }
747
748 device_create_file(&client->dev, &dev_attr_temp1_input);
749 device_create_file(&client->dev, &dev_attr_temp1_max);
750 device_create_file(&client->dev, &dev_attr_temp1_max_hyst);
751 device_create_file(&client->dev, &dev_attr_temp2_input);
752 device_create_file(&client->dev, &dev_attr_temp2_max);
753 device_create_file(&client->dev, &dev_attr_temp2_max_hyst);
754 device_create_file(&client->dev, &dev_attr_temp3_input);
755 device_create_file(&client->dev, &dev_attr_temp3_max);
756 device_create_file(&client->dev, &dev_attr_temp3_max_hyst);
757
758 return 0;
759
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400760exit_detach:
761 i2c_detach_client(client);
Jean Delvare08e7e272005-04-25 22:43:25 +0200762exit_free:
763 kfree(data);
764exit_release:
765 release_region(address, REGION_LENGTH);
766exit:
767 return err;
768}
769
Jean Delvare08e7e272005-04-25 22:43:25 +0200770static int w83627ehf_detach_client(struct i2c_client *client)
771{
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400772 struct w83627ehf_data *data = i2c_get_clientdata(client);
Jean Delvare08e7e272005-04-25 22:43:25 +0200773 int err;
774
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400775 hwmon_device_unregister(data->class_dev);
776
Jean Delvare7bef5592005-07-27 22:14:49 +0200777 if ((err = i2c_detach_client(client)))
Jean Delvare08e7e272005-04-25 22:43:25 +0200778 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +0200779 release_region(client->addr, REGION_LENGTH);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400780 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200781
782 return 0;
783}
784
785static struct i2c_driver w83627ehf_driver = {
786 .owner = THIS_MODULE,
787 .name = "w83627ehf",
Jean Delvare2d8672c2005-07-19 23:56:35 +0200788 .attach_adapter = w83627ehf_detect,
Jean Delvare08e7e272005-04-25 22:43:25 +0200789 .detach_client = w83627ehf_detach_client,
790};
791
Jean Delvare2d8672c2005-07-19 23:56:35 +0200792static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200793{
794 u16 val;
795
796 REG = sioaddr;
797 VAL = sioaddr + 1;
798 superio_enter();
799
800 val = (superio_inb(SIO_REG_DEVID) << 8)
801 | superio_inb(SIO_REG_DEVID + 1);
802 if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
803 superio_exit();
804 return -ENODEV;
805 }
806
807 superio_select(W83627EHF_LD_HWM);
808 val = (superio_inb(SIO_REG_ADDR) << 8)
809 | superio_inb(SIO_REG_ADDR + 1);
Jean Delvare2d8672c2005-07-19 23:56:35 +0200810 *addr = val & ~(REGION_LENGTH - 1);
811 if (*addr == 0) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200812 superio_exit();
813 return -ENODEV;
814 }
815
816 /* Activate logical device if needed */
817 val = superio_inb(SIO_REG_ENABLE);
818 if (!(val & 0x01))
819 superio_outb(SIO_REG_ENABLE, val | 0x01);
820
821 superio_exit();
822 return 0;
823}
824
825static int __init sensors_w83627ehf_init(void)
826{
Jean Delvare2d8672c2005-07-19 23:56:35 +0200827 if (w83627ehf_find(0x2e, &address)
828 && w83627ehf_find(0x4e, &address))
Jean Delvare08e7e272005-04-25 22:43:25 +0200829 return -ENODEV;
830
Jean Delvarefde09502005-07-19 23:51:07 +0200831 return i2c_isa_add_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +0200832}
833
834static void __exit sensors_w83627ehf_exit(void)
835{
Jean Delvarefde09502005-07-19 23:51:07 +0200836 i2c_isa_del_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +0200837}
838
839MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
840MODULE_DESCRIPTION("W83627EHF driver");
841MODULE_LICENSE("GPL");
842
843module_init(sensors_w83627ehf_init);
844module_exit(sensors_w83627ehf_exit);