blob: b6bd5685fd389dd634ab6318935d4aee94fd362a [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>
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
124#define W83627EHF_REG_TEMP1 0x27
125#define W83627EHF_REG_TEMP1_HYST 0x3a
126#define W83627EHF_REG_TEMP1_OVER 0x39
127static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
128static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
129static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
130static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
131
132/* Fan clock dividers are spread over the following five registers */
133#define W83627EHF_REG_FANDIV1 0x47
134#define W83627EHF_REG_FANDIV2 0x4B
135#define W83627EHF_REG_VBAT 0x5D
136#define W83627EHF_REG_DIODE 0x59
137#define W83627EHF_REG_SMI_OVT 0x4C
138
139/*
140 * Conversions
141 */
142
143static inline unsigned int
144fan_from_reg(u8 reg, unsigned int div)
145{
146 if (reg == 0 || reg == 255)
147 return 0;
148 return 1350000U / (reg * div);
149}
150
151static inline unsigned int
152div_from_reg(u8 reg)
153{
154 return 1 << reg;
155}
156
157static inline int
158temp1_from_reg(s8 reg)
159{
160 return reg * 1000;
161}
162
163static inline s8
164temp1_to_reg(int temp)
165{
166 if (temp <= -128000)
167 return -128;
168 if (temp >= 127000)
169 return 127;
170 if (temp < 0)
171 return (temp - 500) / 1000;
172 return (temp + 500) / 1000;
173}
174
175/*
176 * Data structures and manipulation thereof
177 */
178
179struct w83627ehf_data {
180 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400181 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100182 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200183
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100184 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200185 char valid; /* !=0 if following fields are valid */
186 unsigned long last_updated; /* In jiffies */
187
188 /* Register values */
189 u8 fan[5];
190 u8 fan_min[5];
191 u8 fan_div[5];
192 u8 has_fan; /* some fan inputs can be disabled */
193 s8 temp1;
194 s8 temp1_max;
195 s8 temp1_max_hyst;
196 s16 temp[2];
197 s16 temp_max[2];
198 s16 temp_max_hyst[2];
199};
200
201static inline int is_word_sized(u16 reg)
202{
203 return (((reg & 0xff00) == 0x100
204 || (reg & 0xff00) == 0x200)
205 && ((reg & 0x00ff) == 0x50
206 || (reg & 0x00ff) == 0x53
207 || (reg & 0x00ff) == 0x55));
208}
209
210/* We assume that the default bank is 0, thus the following two functions do
211 nothing for registers which live in bank 0. For others, they respectively
212 set the bank register to the correct value (before the register is
213 accessed), and back to 0 (afterwards). */
214static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
215{
216 if (reg & 0xff00) {
217 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
218 outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
219 }
220}
221
222static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
223{
224 if (reg & 0xff00) {
225 outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
226 outb_p(0, client->addr + DATA_REG_OFFSET);
227 }
228}
229
230static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
231{
232 struct w83627ehf_data *data = i2c_get_clientdata(client);
233 int res, word_sized = is_word_sized(reg);
234
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100235 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200236
237 w83627ehf_set_bank(client, reg);
238 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
239 res = inb_p(client->addr + DATA_REG_OFFSET);
240 if (word_sized) {
241 outb_p((reg & 0xff) + 1,
242 client->addr + ADDR_REG_OFFSET);
243 res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
244 }
245 w83627ehf_reset_bank(client, reg);
246
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100247 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200248
249 return res;
250}
251
252static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
253{
254 struct w83627ehf_data *data = i2c_get_clientdata(client);
255 int word_sized = is_word_sized(reg);
256
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100257 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200258
259 w83627ehf_set_bank(client, reg);
260 outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
261 if (word_sized) {
262 outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
263 outb_p((reg & 0xff) + 1,
264 client->addr + ADDR_REG_OFFSET);
265 }
266 outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
267 w83627ehf_reset_bank(client, reg);
268
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100269 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200270 return 0;
271}
272
273/* This function assumes that the caller holds data->update_lock */
274static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
275{
276 struct w83627ehf_data *data = i2c_get_clientdata(client);
277 u8 reg;
278
279 switch (nr) {
280 case 0:
281 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
282 | ((data->fan_div[0] & 0x03) << 4);
283 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
284 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
285 | ((data->fan_div[0] & 0x04) << 3);
286 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
287 break;
288 case 1:
289 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
290 | ((data->fan_div[1] & 0x03) << 6);
291 w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
292 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
293 | ((data->fan_div[1] & 0x04) << 4);
294 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
295 break;
296 case 2:
297 reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
298 | ((data->fan_div[2] & 0x03) << 6);
299 w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
300 reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
301 | ((data->fan_div[2] & 0x04) << 5);
302 w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
303 break;
304 case 3:
305 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
306 | (data->fan_div[3] & 0x03);
307 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
308 reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
309 | ((data->fan_div[3] & 0x04) << 5);
310 w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
311 break;
312 case 4:
313 reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
314 | ((data->fan_div[4] & 0x03) << 3)
315 | ((data->fan_div[4] & 0x04) << 5);
316 w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
317 break;
318 }
319}
320
321static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
322{
323 struct i2c_client *client = to_i2c_client(dev);
324 struct w83627ehf_data *data = i2c_get_clientdata(client);
325 int i;
326
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100327 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200328
329 if (time_after(jiffies, data->last_updated + HZ)
330 || !data->valid) {
331 /* Fan clock dividers */
332 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
333 data->fan_div[0] = (i >> 4) & 0x03;
334 data->fan_div[1] = (i >> 6) & 0x03;
335 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
336 data->fan_div[2] = (i >> 6) & 0x03;
337 i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
338 data->fan_div[0] |= (i >> 3) & 0x04;
339 data->fan_div[1] |= (i >> 4) & 0x04;
340 data->fan_div[2] |= (i >> 5) & 0x04;
341 if (data->has_fan & ((1 << 3) | (1 << 4))) {
342 i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
343 data->fan_div[3] = i & 0x03;
344 data->fan_div[4] = ((i >> 2) & 0x03)
345 | ((i >> 5) & 0x04);
346 }
347 if (data->has_fan & (1 << 3)) {
348 i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
349 data->fan_div[3] |= (i >> 5) & 0x04;
350 }
351
352 /* Measured fan speeds and limits */
353 for (i = 0; i < 5; i++) {
354 if (!(data->has_fan & (1 << i)))
355 continue;
356
357 data->fan[i] = w83627ehf_read_value(client,
358 W83627EHF_REG_FAN[i]);
359 data->fan_min[i] = w83627ehf_read_value(client,
360 W83627EHF_REG_FAN_MIN[i]);
361
362 /* If we failed to measure the fan speed and clock
363 divider can be increased, let's try that for next
364 time */
365 if (data->fan[i] == 0xff
366 && data->fan_div[i] < 0x07) {
367 dev_dbg(&client->dev, "Increasing fan %d "
368 "clock divider from %u to %u\n",
369 i, div_from_reg(data->fan_div[i]),
370 div_from_reg(data->fan_div[i] + 1));
371 data->fan_div[i]++;
372 w83627ehf_write_fan_div(client, i);
373 /* Preserve min limit if possible */
374 if (data->fan_min[i] >= 2
375 && data->fan_min[i] != 255)
376 w83627ehf_write_value(client,
377 W83627EHF_REG_FAN_MIN[i],
378 (data->fan_min[i] /= 2));
379 }
380 }
381
382 /* Measured temperatures and limits */
383 data->temp1 = w83627ehf_read_value(client,
384 W83627EHF_REG_TEMP1);
385 data->temp1_max = w83627ehf_read_value(client,
386 W83627EHF_REG_TEMP1_OVER);
387 data->temp1_max_hyst = w83627ehf_read_value(client,
388 W83627EHF_REG_TEMP1_HYST);
389 for (i = 0; i < 2; i++) {
390 data->temp[i] = w83627ehf_read_value(client,
391 W83627EHF_REG_TEMP[i]);
392 data->temp_max[i] = w83627ehf_read_value(client,
393 W83627EHF_REG_TEMP_OVER[i]);
394 data->temp_max_hyst[i] = w83627ehf_read_value(client,
395 W83627EHF_REG_TEMP_HYST[i]);
396 }
397
398 data->last_updated = jiffies;
399 data->valid = 1;
400 }
401
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100402 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200403 return data;
404}
405
406/*
407 * Sysfs callback functions
408 */
409
410#define show_fan_reg(reg) \
411static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100412show_##reg(struct device *dev, struct device_attribute *attr, \
413 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200414{ \
415 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100416 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
417 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200418 return sprintf(buf, "%d\n", \
419 fan_from_reg(data->reg[nr], \
420 div_from_reg(data->fan_div[nr]))); \
421}
422show_fan_reg(fan);
423show_fan_reg(fan_min);
424
425static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100426show_fan_div(struct device *dev, struct device_attribute *attr,
427 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200428{
429 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100430 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
431 int nr = sensor_attr->index;
432 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200433}
434
435static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100436store_fan_min(struct device *dev, struct device_attribute *attr,
437 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200438{
439 struct i2c_client *client = to_i2c_client(dev);
440 struct w83627ehf_data *data = i2c_get_clientdata(client);
Yuan Mu412fec82006-02-05 23:24:16 +0100441 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
442 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200443 unsigned int val = simple_strtoul(buf, NULL, 10);
444 unsigned int reg;
445 u8 new_div;
446
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100447 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200448 if (!val) {
449 /* No min limit, alarm disabled */
450 data->fan_min[nr] = 255;
451 new_div = data->fan_div[nr]; /* No change */
452 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
453 } else if ((reg = 1350000U / val) >= 128 * 255) {
454 /* Speed below this value cannot possibly be represented,
455 even with the highest divider (128) */
456 data->fan_min[nr] = 254;
457 new_div = 7; /* 128 == (1 << 7) */
458 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
459 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
460 } else if (!reg) {
461 /* Speed above this value cannot possibly be represented,
462 even with the lowest divider (1) */
463 data->fan_min[nr] = 1;
464 new_div = 0; /* 1 == (1 << 0) */
465 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200466 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200467 } else {
468 /* Automatically pick the best divider, i.e. the one such
469 that the min limit will correspond to a register value
470 in the 96..192 range */
471 new_div = 0;
472 while (reg > 192 && new_div < 7) {
473 reg >>= 1;
474 new_div++;
475 }
476 data->fan_min[nr] = reg;
477 }
478
479 /* Write both the fan clock divider (if it changed) and the new
480 fan min (unconditionally) */
481 if (new_div != data->fan_div[nr]) {
482 if (new_div > data->fan_div[nr])
483 data->fan[nr] >>= (data->fan_div[nr] - new_div);
484 else
485 data->fan[nr] <<= (new_div - data->fan_div[nr]);
486
487 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
488 nr + 1, div_from_reg(data->fan_div[nr]),
489 div_from_reg(new_div));
490 data->fan_div[nr] = new_div;
491 w83627ehf_write_fan_div(client, nr);
492 }
493 w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
494 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100495 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200496
497 return count;
498}
499
Yuan Mu412fec82006-02-05 23:24:16 +0100500static struct sensor_device_attribute sda_fan_input[] = {
501 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
502 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
503 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
504 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
505 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
506};
Jean Delvare08e7e272005-04-25 22:43:25 +0200507
Yuan Mu412fec82006-02-05 23:24:16 +0100508static struct sensor_device_attribute sda_fan_min[] = {
509 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
510 store_fan_min, 0),
511 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
512 store_fan_min, 1),
513 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
514 store_fan_min, 2),
515 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
516 store_fan_min, 3),
517 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
518 store_fan_min, 4),
519};
Jean Delvare08e7e272005-04-25 22:43:25 +0200520
Yuan Mu412fec82006-02-05 23:24:16 +0100521static struct sensor_device_attribute sda_fan_div[] = {
522 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
523 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
524 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
525 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
526 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
527};
Jean Delvare08e7e272005-04-25 22:43:25 +0200528
Yuan Mu412fec82006-02-05 23:24:16 +0100529static void device_create_file_fan(struct device *dev, int i)
530{
531 device_create_file(dev, &sda_fan_input[i].dev_attr);
532 device_create_file(dev, &sda_fan_div[i].dev_attr);
533 device_create_file(dev, &sda_fan_min[i].dev_attr);
534}
Jean Delvare08e7e272005-04-25 22:43:25 +0200535
536#define show_temp1_reg(reg) \
537static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700538show_##reg(struct device *dev, struct device_attribute *attr, \
539 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200540{ \
541 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
542 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
543}
544show_temp1_reg(temp1);
545show_temp1_reg(temp1_max);
546show_temp1_reg(temp1_max_hyst);
547
548#define store_temp1_reg(REG, reg) \
549static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700550store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
551 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200552{ \
553 struct i2c_client *client = to_i2c_client(dev); \
554 struct w83627ehf_data *data = i2c_get_clientdata(client); \
555 u32 val = simple_strtoul(buf, NULL, 10); \
556 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100557 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200558 data->temp1_##reg = temp1_to_reg(val); \
559 w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
560 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100561 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200562 return count; \
563}
564store_temp1_reg(OVER, max);
565store_temp1_reg(HYST, max_hyst);
566
Jean Delvare08e7e272005-04-25 22:43:25 +0200567#define show_temp_reg(reg) \
568static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100569show_##reg(struct device *dev, struct device_attribute *attr, \
570 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200571{ \
572 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100573 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
574 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200575 return sprintf(buf, "%d\n", \
576 LM75_TEMP_FROM_REG(data->reg[nr])); \
577}
578show_temp_reg(temp);
579show_temp_reg(temp_max);
580show_temp_reg(temp_max_hyst);
581
582#define store_temp_reg(REG, reg) \
583static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100584store_##reg(struct device *dev, struct device_attribute *attr, \
585 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200586{ \
587 struct i2c_client *client = to_i2c_client(dev); \
588 struct w83627ehf_data *data = i2c_get_clientdata(client); \
Yuan Mu412fec82006-02-05 23:24:16 +0100589 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
590 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200591 u32 val = simple_strtoul(buf, NULL, 10); \
592 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100593 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200594 data->reg[nr] = LM75_TEMP_TO_REG(val); \
595 w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
596 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100597 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200598 return count; \
599}
600store_temp_reg(OVER, temp_max);
601store_temp_reg(HYST, temp_max_hyst);
602
Yuan Mu412fec82006-02-05 23:24:16 +0100603static struct sensor_device_attribute sda_temp[] = {
604 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
605 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
606 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
607 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
608 store_temp1_max, 0),
609 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
610 store_temp_max, 0),
611 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
612 store_temp_max, 1),
613 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
614 store_temp1_max_hyst, 0),
615 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
616 store_temp_max_hyst, 0),
617 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
618 store_temp_max_hyst, 1),
619};
Jean Delvare08e7e272005-04-25 22:43:25 +0200620
621/*
622 * Driver and client management
623 */
624
625static struct i2c_driver w83627ehf_driver;
626
627static void w83627ehf_init_client(struct i2c_client *client)
628{
629 int i;
630 u8 tmp;
631
632 /* Start monitoring is needed */
633 tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
634 if (!(tmp & 0x01))
635 w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
636 tmp | 0x01);
637
638 /* Enable temp2 and temp3 if needed */
639 for (i = 0; i < 2; i++) {
640 tmp = w83627ehf_read_value(client,
641 W83627EHF_REG_TEMP_CONFIG[i]);
642 if (tmp & 0x01)
643 w83627ehf_write_value(client,
644 W83627EHF_REG_TEMP_CONFIG[i],
645 tmp & 0xfe);
646 }
647}
648
Jean Delvare2d8672c2005-07-19 23:56:35 +0200649static int w83627ehf_detect(struct i2c_adapter *adapter)
Jean Delvare08e7e272005-04-25 22:43:25 +0200650{
651 struct i2c_client *client;
652 struct w83627ehf_data *data;
Yuan Mu412fec82006-02-05 23:24:16 +0100653 struct device *dev;
Jean Delvare08e7e272005-04-25 22:43:25 +0200654 int i, err = 0;
655
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200656 if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100657 w83627ehf_driver.driver.name)) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200658 err = -EBUSY;
659 goto exit;
660 }
661
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200662 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200663 err = -ENOMEM;
664 goto exit_release;
665 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200666
667 client = &data->client;
668 i2c_set_clientdata(client, data);
669 client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100670 mutex_init(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200671 client->adapter = adapter;
672 client->driver = &w83627ehf_driver;
673 client->flags = 0;
Yuan Mu412fec82006-02-05 23:24:16 +0100674 dev = &client->dev;
Jean Delvare08e7e272005-04-25 22:43:25 +0200675
676 strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
677 data->valid = 0;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100678 mutex_init(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200679
680 /* Tell the i2c layer a new client has arrived */
681 if ((err = i2c_attach_client(client)))
682 goto exit_free;
683
684 /* Initialize the chip */
685 w83627ehf_init_client(client);
686
687 /* A few vars need to be filled upon startup */
688 for (i = 0; i < 5; i++)
689 data->fan_min[i] = w83627ehf_read_value(client,
690 W83627EHF_REG_FAN_MIN[i]);
691
692 /* It looks like fan4 and fan5 pins can be alternatively used
693 as fan on/off switches */
694 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
695 i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
696 if (i & (1 << 2))
697 data->has_fan |= (1 << 3);
698 if (i & (1 << 0))
699 data->has_fan |= (1 << 4);
700
701 /* Register sysfs hooks */
Yuan Mu412fec82006-02-05 23:24:16 +0100702 data->class_dev = hwmon_device_register(dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400703 if (IS_ERR(data->class_dev)) {
704 err = PTR_ERR(data->class_dev);
705 goto exit_detach;
706 }
707
Yuan Mu412fec82006-02-05 23:24:16 +0100708 for (i = 0; i < 5; i++) {
709 if (data->has_fan & (1 << i))
710 device_create_file_fan(dev, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200711 }
Yuan Mu412fec82006-02-05 23:24:16 +0100712 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
713 device_create_file(dev, &sda_temp[i].dev_attr);
Jean Delvare08e7e272005-04-25 22:43:25 +0200714
715 return 0;
716
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400717exit_detach:
718 i2c_detach_client(client);
Jean Delvare08e7e272005-04-25 22:43:25 +0200719exit_free:
720 kfree(data);
721exit_release:
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200722 release_region(address + REGION_OFFSET, REGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +0200723exit:
724 return err;
725}
726
Jean Delvare08e7e272005-04-25 22:43:25 +0200727static int w83627ehf_detach_client(struct i2c_client *client)
728{
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400729 struct w83627ehf_data *data = i2c_get_clientdata(client);
Jean Delvare08e7e272005-04-25 22:43:25 +0200730 int err;
731
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400732 hwmon_device_unregister(data->class_dev);
733
Jean Delvare7bef5592005-07-27 22:14:49 +0200734 if ((err = i2c_detach_client(client)))
Jean Delvare08e7e272005-04-25 22:43:25 +0200735 return err;
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200736 release_region(client->addr + REGION_OFFSET, REGION_LENGTH);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400737 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200738
739 return 0;
740}
741
742static struct i2c_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100743 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100744 .name = "w83627ehf",
745 },
Jean Delvare2d8672c2005-07-19 23:56:35 +0200746 .attach_adapter = w83627ehf_detect,
Jean Delvare08e7e272005-04-25 22:43:25 +0200747 .detach_client = w83627ehf_detach_client,
748};
749
Jean Delvare2d8672c2005-07-19 23:56:35 +0200750static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200751{
752 u16 val;
753
754 REG = sioaddr;
755 VAL = sioaddr + 1;
756 superio_enter();
757
758 val = (superio_inb(SIO_REG_DEVID) << 8)
759 | superio_inb(SIO_REG_DEVID + 1);
760 if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
761 superio_exit();
762 return -ENODEV;
763 }
764
765 superio_select(W83627EHF_LD_HWM);
766 val = (superio_inb(SIO_REG_ADDR) << 8)
767 | superio_inb(SIO_REG_ADDR + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200768 *addr = val & REGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +0200769 if (*addr == 0) {
Jean Delvare08e7e272005-04-25 22:43:25 +0200770 superio_exit();
771 return -ENODEV;
772 }
773
774 /* Activate logical device if needed */
775 val = superio_inb(SIO_REG_ENABLE);
776 if (!(val & 0x01))
777 superio_outb(SIO_REG_ENABLE, val | 0x01);
778
779 superio_exit();
780 return 0;
781}
782
783static int __init sensors_w83627ehf_init(void)
784{
Jean Delvare2d8672c2005-07-19 23:56:35 +0200785 if (w83627ehf_find(0x2e, &address)
786 && w83627ehf_find(0x4e, &address))
Jean Delvare08e7e272005-04-25 22:43:25 +0200787 return -ENODEV;
788
Jean Delvarefde09502005-07-19 23:51:07 +0200789 return i2c_isa_add_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +0200790}
791
792static void __exit sensors_w83627ehf_exit(void)
793{
Jean Delvarefde09502005-07-19 23:51:07 +0200794 i2c_isa_del_driver(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +0200795}
796
797MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
798MODULE_DESCRIPTION("W83627EHF driver");
799MODULE_LICENSE("GPL");
800
801module_init(sensors_w83627ehf_init);
802module_exit(sensors_w83627ehf_exit);