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