blob: 95a4b5d9eaf29820cdba79472de2f97ea482f269 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 sis5595.c - Part of lm_sensors, Linux kernel modules
3 for hardware monitoring
4
5 Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
6 Kyösti Mälkki <kmalkki@cc.hut.fi>, and
7 Mark D. Studebaker <mdsxyz123@yahoo.com>
8 Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
9 the help of Jean Delvare <khali@linux-fr.org>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26/*
27 SiS southbridge has a LM78-like chip integrated on the same IC.
28 This driver is a customized copy of lm78.c
29
30 Supports following revisions:
31 Version PCI ID PCI Revision
32 1 1039/0008 AF or less
33 2 1039/0008 B0 or greater
34
35 Note: these chips contain a 0008 device which is incompatible with the
36 5595. We recognize these by the presence of the listed
37 "blacklist" PCI ID and refuse to load.
38
39 NOT SUPPORTED PCI ID BLACKLIST PCI ID
40 540 0008 0540
41 550 0008 0550
42 5513 0008 5511
43 5581 0008 5597
44 5582 0008 5597
45 5597 0008 5597
46 5598 0008 5597/5598
47 630 0008 0630
48 645 0008 0645
49 730 0008 0730
50 735 0008 0735
51*/
52
53#include <linux/module.h>
54#include <linux/slab.h>
55#include <linux/ioport.h>
56#include <linux/pci.h>
57#include <linux/i2c.h>
Jean Delvarefde09502005-07-19 23:51:07 +020058#include <linux/i2c-isa.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040059#include <linux/hwmon.h>
60#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/init.h>
Dominik Hacklff324092005-05-16 18:12:18 +020062#include <linux/jiffies.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010063#include <linux/mutex.h>
Jean Delvarea5ebe662006-09-24 21:24:46 +020064#include <linux/sysfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <asm/io.h>
66
67
68/* If force_addr is set to anything different from 0, we forcibly enable
69 the device at the given address. */
70static u16 force_addr;
71module_param(force_addr, ushort, 0);
72MODULE_PARM_DESC(force_addr,
73 "Initialize the base address of the sensors");
74
Jean Delvare2d8672c2005-07-19 23:56:35 +020075/* Device address
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 Note that we can't determine the ISA address until we have initialized
77 our module */
Jean Delvare2d8672c2005-07-19 23:56:35 +020078static unsigned short address;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* Many SIS5595 constants specified below */
81
82/* Length of ISA address segment */
83#define SIS5595_EXTENT 8
84/* PCI Config Registers */
85#define SIS5595_REVISION_REG 0x08
86#define SIS5595_BASE_REG 0x68
87#define SIS5595_PIN_REG 0x7A
88#define SIS5595_ENABLE_REG 0x7B
89
90/* Where are the ISA address/data registers relative to the base address */
91#define SIS5595_ADDR_REG_OFFSET 5
92#define SIS5595_DATA_REG_OFFSET 6
93
94/* The SIS5595 registers */
95#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
96#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
97#define SIS5595_REG_IN(nr) (0x20 + (nr))
98
99#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
100#define SIS5595_REG_FAN(nr) (0x28 + (nr))
101
102/* On the first version of the chip, the temp registers are separate.
103 On the second version,
104 TEMP pin is shared with IN4, configured in PCI register 0x7A.
105 The registers are the same as well.
106 OVER and HYST are really MAX and MIN. */
107
108#define REV2MIN 0xb0
109#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \
110 SIS5595_REG_IN(4) : 0x27
111#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \
112 SIS5595_REG_IN_MAX(4) : 0x39
113#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \
114 SIS5595_REG_IN_MIN(4) : 0x3a
115
116#define SIS5595_REG_CONFIG 0x40
117#define SIS5595_REG_ALARM1 0x41
118#define SIS5595_REG_ALARM2 0x42
119#define SIS5595_REG_FANDIV 0x47
120
121/* Conversions. Limit checking is only done on the TO_REG
122 variants. */
123
124/* IN: mV, (0V to 4.08V)
125 REG: 16mV/bit */
126static inline u8 IN_TO_REG(unsigned long val)
127{
128 unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
129 return (nval + 8) / 16;
130}
131#define IN_FROM_REG(val) ((val) * 16)
132
133static inline u8 FAN_TO_REG(long rpm, int div)
134{
135 if (rpm <= 0)
136 return 255;
137 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
138}
139
140static inline int FAN_FROM_REG(u8 val, int div)
141{
142 return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
143}
144
145/* TEMP: mC (-54.12C to +157.53C)
146 REG: 0.83C/bit + 52.12, two's complement */
147static inline int TEMP_FROM_REG(s8 val)
148{
149 return val * 830 + 52120;
150}
151static inline s8 TEMP_TO_REG(int val)
152{
153 int nval = SENSORS_LIMIT(val, -54120, 157530) ;
154 return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830;
155}
156
157/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
158 REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
159static inline u8 DIV_TO_REG(int val)
160{
161 return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
162}
163#define DIV_FROM_REG(val) (1 << (val))
164
165/* For the SIS5595, we need to keep some data in memory. That
166 data is pointed to by sis5595_list[NR]->data. The structure itself is
167 dynamically allocated, at the time when the new sis5595 client is
168 allocated. */
169struct sis5595_data {
170 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400171 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100172 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100174 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 char valid; /* !=0 if following fields are valid */
176 unsigned long last_updated; /* In jiffies */
177 char maxins; /* == 3 if temp enabled, otherwise == 4 */
178 u8 revision; /* Reg. value */
179
180 u8 in[5]; /* Register value */
181 u8 in_max[5]; /* Register value */
182 u8 in_min[5]; /* Register value */
183 u8 fan[2]; /* Register value */
184 u8 fan_min[2]; /* Register value */
185 s8 temp; /* Register value */
186 s8 temp_over; /* Register value */
187 s8 temp_hyst; /* Register value */
188 u8 fan_div[2]; /* Register encoding, shifted right */
189 u16 alarms; /* Register encoding, combined */
190};
191
192static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
193
Jean Delvare2d8672c2005-07-19 23:56:35 +0200194static int sis5595_detect(struct i2c_adapter *adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195static int sis5595_detach_client(struct i2c_client *client);
196
Darren Jenkinsf6c27fc2006-02-27 23:14:58 +0100197static int sis5595_read_value(struct i2c_client *client, u8 reg);
198static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199static struct sis5595_data *sis5595_update_device(struct device *dev);
200static void sis5595_init_client(struct i2c_client *client);
201
202static struct i2c_driver sis5595_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100203 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200204 .owner = THIS_MODULE,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100205 .name = "sis5595",
206 },
Jean Delvare2d8672c2005-07-19 23:56:35 +0200207 .attach_adapter = sis5595_detect,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 .detach_client = sis5595_detach_client,
209};
210
211/* 4 Voltages */
212static ssize_t show_in(struct device *dev, char *buf, int nr)
213{
214 struct sis5595_data *data = sis5595_update_device(dev);
215 return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
216}
217
218static ssize_t show_in_min(struct device *dev, char *buf, int nr)
219{
220 struct sis5595_data *data = sis5595_update_device(dev);
221 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
222}
223
224static ssize_t show_in_max(struct device *dev, char *buf, int nr)
225{
226 struct sis5595_data *data = sis5595_update_device(dev);
227 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
228}
229
230static ssize_t set_in_min(struct device *dev, const char *buf,
231 size_t count, int nr)
232{
233 struct i2c_client *client = to_i2c_client(dev);
234 struct sis5595_data *data = i2c_get_clientdata(client);
235 unsigned long val = simple_strtoul(buf, NULL, 10);
236
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100237 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 data->in_min[nr] = IN_TO_REG(val);
239 sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100240 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 return count;
242}
243
244static ssize_t set_in_max(struct device *dev, const char *buf,
245 size_t count, int nr)
246{
247 struct i2c_client *client = to_i2c_client(dev);
248 struct sis5595_data *data = i2c_get_clientdata(client);
249 unsigned long val = simple_strtoul(buf, NULL, 10);
250
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100251 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 data->in_max[nr] = IN_TO_REG(val);
253 sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100254 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return count;
256}
257
258#define show_in_offset(offset) \
259static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400260 show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{ \
262 return show_in(dev, buf, offset); \
263} \
264static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
265 show_in##offset, NULL); \
266static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400267 show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{ \
269 return show_in_min(dev, buf, offset); \
270} \
271static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400272 show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{ \
274 return show_in_max(dev, buf, offset); \
275} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400276static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 const char *buf, size_t count) \
278{ \
279 return set_in_min(dev, buf, count, offset); \
280} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400281static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 const char *buf, size_t count) \
283{ \
284 return set_in_max(dev, buf, count, offset); \
285} \
286static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
287 show_in##offset##_min, set_in##offset##_min); \
288static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
289 show_in##offset##_max, set_in##offset##_max);
290
291show_in_offset(0);
292show_in_offset(1);
293show_in_offset(2);
294show_in_offset(3);
295show_in_offset(4);
296
297/* Temperature */
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400298static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 struct sis5595_data *data = sis5595_update_device(dev);
301 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
302}
303
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400304static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 struct sis5595_data *data = sis5595_update_device(dev);
307 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
308}
309
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400310static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
312 struct i2c_client *client = to_i2c_client(dev);
313 struct sis5595_data *data = i2c_get_clientdata(client);
314 long val = simple_strtol(buf, NULL, 10);
315
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100316 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 data->temp_over = TEMP_TO_REG(val);
318 sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100319 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return count;
321}
322
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400323static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 struct sis5595_data *data = sis5595_update_device(dev);
326 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
327}
328
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400329static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
331 struct i2c_client *client = to_i2c_client(dev);
332 struct sis5595_data *data = i2c_get_clientdata(client);
333 long val = simple_strtol(buf, NULL, 10);
334
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100335 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 data->temp_hyst = TEMP_TO_REG(val);
337 sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100338 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return count;
340}
341
342static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
343static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
344 show_temp_over, set_temp_over);
345static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
346 show_temp_hyst, set_temp_hyst);
347
348/* 2 Fans */
349static ssize_t show_fan(struct device *dev, char *buf, int nr)
350{
351 struct sis5595_data *data = sis5595_update_device(dev);
352 return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
353 DIV_FROM_REG(data->fan_div[nr])) );
354}
355
356static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
357{
358 struct sis5595_data *data = sis5595_update_device(dev);
359 return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
360 DIV_FROM_REG(data->fan_div[nr])) );
361}
362
363static ssize_t set_fan_min(struct device *dev, const char *buf,
364 size_t count, int nr)
365{
366 struct i2c_client *client = to_i2c_client(dev);
367 struct sis5595_data *data = i2c_get_clientdata(client);
368 unsigned long val = simple_strtoul(buf, NULL, 10);
369
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100370 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
372 sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100373 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return count;
375}
376
377static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
378{
379 struct sis5595_data *data = sis5595_update_device(dev);
380 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
381}
382
383/* Note: we save and restore the fan minimum here, because its value is
384 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200385 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 because the divisor changed. */
387static ssize_t set_fan_div(struct device *dev, const char *buf,
388 size_t count, int nr)
389{
390 struct i2c_client *client = to_i2c_client(dev);
391 struct sis5595_data *data = i2c_get_clientdata(client);
392 unsigned long min;
393 unsigned long val = simple_strtoul(buf, NULL, 10);
394 int reg;
395
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100396 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 min = FAN_FROM_REG(data->fan_min[nr],
398 DIV_FROM_REG(data->fan_div[nr]));
399 reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
400
401 switch (val) {
402 case 1: data->fan_div[nr] = 0; break;
403 case 2: data->fan_div[nr] = 1; break;
404 case 4: data->fan_div[nr] = 2; break;
405 case 8: data->fan_div[nr] = 3; break;
406 default:
407 dev_err(&client->dev, "fan_div value %ld not "
408 "supported. Choose one of 1, 2, 4 or 8!\n", val);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100409 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return -EINVAL;
411 }
412
413 switch (nr) {
414 case 0:
415 reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
416 break;
417 case 1:
418 reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
419 break;
420 }
421 sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
422 data->fan_min[nr] =
423 FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
424 sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100425 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 return count;
427}
428
429#define show_fan_offset(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400430static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{ \
432 return show_fan(dev, buf, offset - 1); \
433} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400434static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{ \
436 return show_fan_min(dev, buf, offset - 1); \
437} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400438static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{ \
440 return show_fan_div(dev, buf, offset - 1); \
441} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400442static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 const char *buf, size_t count) \
444{ \
445 return set_fan_min(dev, buf, count, offset - 1); \
446} \
447static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
448static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
449 show_fan_##offset##_min, set_fan_##offset##_min);
450
451show_fan_offset(1);
452show_fan_offset(2);
453
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400454static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 size_t count)
456{
457 return set_fan_div(dev, buf, count, 0) ;
458}
459
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400460static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 size_t count)
462{
463 return set_fan_div(dev, buf, count, 1) ;
464}
465static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
466 show_fan_1_div, set_fan_1_div);
467static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
468 show_fan_2_div, set_fan_2_div);
469
470/* Alarms */
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400471static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
473 struct sis5595_data *data = sis5595_update_device(dev);
474 return sprintf(buf, "%d\n", data->alarms);
475}
476static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200477
478static struct attribute *sis5595_attributes[] = {
479 &dev_attr_in0_input.attr,
480 &dev_attr_in0_min.attr,
481 &dev_attr_in0_max.attr,
482 &dev_attr_in1_input.attr,
483 &dev_attr_in1_min.attr,
484 &dev_attr_in1_max.attr,
485 &dev_attr_in2_input.attr,
486 &dev_attr_in2_min.attr,
487 &dev_attr_in2_max.attr,
488 &dev_attr_in3_input.attr,
489 &dev_attr_in3_min.attr,
490 &dev_attr_in3_max.attr,
491
492 &dev_attr_fan1_input.attr,
493 &dev_attr_fan1_min.attr,
494 &dev_attr_fan1_div.attr,
495 &dev_attr_fan2_input.attr,
496 &dev_attr_fan2_min.attr,
497 &dev_attr_fan2_div.attr,
498
499 &dev_attr_alarms.attr,
500 NULL
501};
502
503static const struct attribute_group sis5595_group = {
504 .attrs = sis5595_attributes,
505};
506
507static struct attribute *sis5595_attributes_opt[] = {
508 &dev_attr_in4_input.attr,
509 &dev_attr_in4_min.attr,
510 &dev_attr_in4_max.attr,
511
512 &dev_attr_temp1_input.attr,
513 &dev_attr_temp1_max.attr,
514 &dev_attr_temp1_max_hyst.attr,
515 NULL
516};
517
518static const struct attribute_group sis5595_group_opt = {
519 .attrs = sis5595_attributes_opt,
520};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522/* This is called when the module is loaded */
Jean Delvare2d8672c2005-07-19 23:56:35 +0200523static int sis5595_detect(struct i2c_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 int err = 0;
526 int i;
527 struct i2c_client *new_client;
528 struct sis5595_data *data;
529 char val;
530 u16 a;
531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (force_addr)
533 address = force_addr & ~(SIS5595_EXTENT - 1);
534 /* Reserve the ISA region */
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100535 if (!request_region(address, SIS5595_EXTENT,
536 sis5595_driver.driver.name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 err = -EBUSY;
538 goto exit;
539 }
540 if (force_addr) {
541 dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
542 if (PCIBIOS_SUCCESSFUL !=
543 pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
544 goto exit_release;
545 if (PCIBIOS_SUCCESSFUL !=
546 pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
547 goto exit_release;
548 if ((a & ~(SIS5595_EXTENT - 1)) != address)
549 /* doesn't work for some chips? */
550 goto exit_release;
551 }
552
553 if (PCIBIOS_SUCCESSFUL !=
554 pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
555 goto exit_release;
556 }
557 if ((val & 0x80) == 0) {
558 if (PCIBIOS_SUCCESSFUL !=
559 pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
560 val | 0x80))
561 goto exit_release;
562 if (PCIBIOS_SUCCESSFUL !=
563 pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
564 goto exit_release;
565 if ((val & 0x80) == 0)
566 /* doesn't work for some chips! */
567 goto exit_release;
568 }
569
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200570 if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 err = -ENOMEM;
572 goto exit_release;
573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575 new_client = &data->client;
576 new_client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100577 mutex_init(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 i2c_set_clientdata(new_client, data);
579 new_client->adapter = adapter;
580 new_client->driver = &sis5595_driver;
581 new_client->flags = 0;
582
583 /* Check revision and pin registers to determine whether 4 or 5 voltages */
584 pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
585 /* 4 voltages, 1 temp */
586 data->maxins = 3;
587 if (data->revision >= REV2MIN) {
588 pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
589 if (!(val & 0x80))
590 /* 5 voltages, no temps */
591 data->maxins = 4;
592 }
593
594 /* Fill in the remaining client fields and put it into the global list */
595 strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
596
597 data->valid = 0;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100598 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 /* Tell the I2C layer a new client has arrived */
601 if ((err = i2c_attach_client(new_client)))
602 goto exit_free;
603
604 /* Initialize the SIS5595 chip */
605 sis5595_init_client(new_client);
606
607 /* A few vars need to be filled upon startup */
608 for (i = 0; i < 2; i++) {
609 data->fan_min[i] = sis5595_read_value(new_client,
610 SIS5595_REG_FAN_MIN(i));
611 }
612
613 /* Register sysfs hooks */
Jean Delvarea5ebe662006-09-24 21:24:46 +0200614 if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
615 goto exit_detach;
616 if (data->maxins == 4) {
617 if ((err = device_create_file(&new_client->dev,
618 &dev_attr_in4_input))
619 || (err = device_create_file(&new_client->dev,
620 &dev_attr_in4_min))
621 || (err = device_create_file(&new_client->dev,
622 &dev_attr_in4_max)))
623 goto exit_remove_files;
624 } else {
625 if ((err = device_create_file(&new_client->dev,
626 &dev_attr_temp1_input))
627 || (err = device_create_file(&new_client->dev,
628 &dev_attr_temp1_max))
629 || (err = device_create_file(&new_client->dev,
630 &dev_attr_temp1_max_hyst)))
631 goto exit_remove_files;
632 }
633
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400634 data->class_dev = hwmon_device_register(&new_client->dev);
635 if (IS_ERR(data->class_dev)) {
636 err = PTR_ERR(data->class_dev);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200637 goto exit_remove_files;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400638 }
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return 0;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400641
Jean Delvarea5ebe662006-09-24 21:24:46 +0200642exit_remove_files:
643 sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
644 sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400645exit_detach:
646 i2c_detach_client(new_client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647exit_free:
648 kfree(data);
649exit_release:
650 release_region(address, SIS5595_EXTENT);
651exit:
652 return err;
653}
654
655static int sis5595_detach_client(struct i2c_client *client)
656{
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400657 struct sis5595_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 int err;
659
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400660 hwmon_device_unregister(data->class_dev);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200661 sysfs_remove_group(&client->dev.kobj, &sis5595_group);
662 sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400663
Jean Delvare7bef5592005-07-27 22:14:49 +0200664 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Jean Delvare2d8672c2005-07-19 23:56:35 +0200667 release_region(client->addr, SIS5595_EXTENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400669 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 return 0;
672}
673
674
675/* ISA access must be locked explicitly. */
676static int sis5595_read_value(struct i2c_client *client, u8 reg)
677{
678 int res;
679
680 struct sis5595_data *data = i2c_get_clientdata(client);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100681 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
683 res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100684 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return res;
686}
687
688static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
689{
690 struct sis5595_data *data = i2c_get_clientdata(client);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100691 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
693 outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100694 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return 0;
696}
697
698/* Called when we have found a new SIS5595. */
699static void sis5595_init_client(struct i2c_client *client)
700{
701 u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
702 if (!(config & 0x01))
703 sis5595_write_value(client, SIS5595_REG_CONFIG,
704 (config & 0xf7) | 0x01);
705}
706
707static struct sis5595_data *sis5595_update_device(struct device *dev)
708{
709 struct i2c_client *client = to_i2c_client(dev);
710 struct sis5595_data *data = i2c_get_clientdata(client);
711 int i;
712
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100713 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
716 || !data->valid) {
717
718 for (i = 0; i <= data->maxins; i++) {
719 data->in[i] =
720 sis5595_read_value(client, SIS5595_REG_IN(i));
721 data->in_min[i] =
722 sis5595_read_value(client,
723 SIS5595_REG_IN_MIN(i));
724 data->in_max[i] =
725 sis5595_read_value(client,
726 SIS5595_REG_IN_MAX(i));
727 }
728 for (i = 0; i < 2; i++) {
729 data->fan[i] =
730 sis5595_read_value(client, SIS5595_REG_FAN(i));
731 data->fan_min[i] =
732 sis5595_read_value(client,
733 SIS5595_REG_FAN_MIN(i));
734 }
735 if (data->maxins == 3) {
736 data->temp =
737 sis5595_read_value(client, SIS5595_REG_TEMP);
738 data->temp_over =
739 sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
740 data->temp_hyst =
741 sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
742 }
743 i = sis5595_read_value(client, SIS5595_REG_FANDIV);
744 data->fan_div[0] = (i >> 4) & 0x03;
745 data->fan_div[1] = i >> 6;
746 data->alarms =
747 sis5595_read_value(client, SIS5595_REG_ALARM1) |
748 (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
749 data->last_updated = jiffies;
750 data->valid = 1;
751 }
752
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100753 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
755 return data;
756}
757
758static struct pci_device_id sis5595_pci_ids[] = {
759 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
760 { 0, }
761};
762
763MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
764
765static int blacklist[] __devinitdata = {
766 PCI_DEVICE_ID_SI_540,
767 PCI_DEVICE_ID_SI_550,
768 PCI_DEVICE_ID_SI_630,
769 PCI_DEVICE_ID_SI_645,
770 PCI_DEVICE_ID_SI_730,
771 PCI_DEVICE_ID_SI_735,
772 PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
773 that ID shows up in other chips so we
774 use the 5511 ID for recognition */
775 PCI_DEVICE_ID_SI_5597,
776 PCI_DEVICE_ID_SI_5598,
777 0 };
778
779static int __devinit sis5595_pci_probe(struct pci_dev *dev,
780 const struct pci_device_id *id)
781{
782 u16 val;
783 int *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 for (i = blacklist; *i != 0; i++) {
786 struct pci_dev *dev;
787 dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
788 if (dev) {
789 dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
790 pci_dev_put(dev);
791 return -ENODEV;
792 }
793 }
794
795 if (PCIBIOS_SUCCESSFUL !=
796 pci_read_config_word(dev, SIS5595_BASE_REG, &val))
797 return -ENODEV;
798
Jean Delvare2d8672c2005-07-19 23:56:35 +0200799 address = val & ~(SIS5595_EXTENT - 1);
800 if (address == 0 && force_addr == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
802 return -ENODEV;
803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 s_bridge = pci_dev_get(dev);
Jean Delvarefde09502005-07-19 23:51:07 +0200806 if (i2c_isa_add_driver(&sis5595_driver)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 pci_dev_put(s_bridge);
808 s_bridge = NULL;
809 }
810
811 /* Always return failure here. This is to allow other drivers to bind
812 * to this pci device. We don't really want to have control over the
813 * pci device, we only wanted to read as few register values from it.
814 */
815 return -ENODEV;
816}
817
818static struct pci_driver sis5595_pci_driver = {
819 .name = "sis5595",
820 .id_table = sis5595_pci_ids,
821 .probe = sis5595_pci_probe,
822};
823
824static int __init sm_sis5595_init(void)
825{
826 return pci_register_driver(&sis5595_pci_driver);
827}
828
829static void __exit sm_sis5595_exit(void)
830{
831 pci_unregister_driver(&sis5595_pci_driver);
832 if (s_bridge != NULL) {
Jean Delvarefde09502005-07-19 23:51:07 +0200833 i2c_isa_del_driver(&sis5595_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 pci_dev_put(s_bridge);
835 s_bridge = NULL;
836 }
837}
838
839MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
840MODULE_DESCRIPTION("SiS 5595 Sensor device");
841MODULE_LICENSE("GPL");
842
843module_init(sm_sis5595_init);
844module_exit(sm_sis5595_exit);