blob: 3783af4195bd9452e758ac84e874fe132e4d1767 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <asm/io.h>
65
66
67/* If force_addr is set to anything different from 0, we forcibly enable
68 the device at the given address. */
69static u16 force_addr;
70module_param(force_addr, ushort, 0);
71MODULE_PARM_DESC(force_addr,
72 "Initialize the base address of the sensors");
73
Jean Delvare2d8672c2005-07-19 23:56:35 +020074/* Device address
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 Note that we can't determine the ISA address until we have initialized
76 our module */
Jean Delvare2d8672c2005-07-19 23:56:35 +020077static unsigned short address;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* Many SIS5595 constants specified below */
80
81/* Length of ISA address segment */
82#define SIS5595_EXTENT 8
83/* PCI Config Registers */
84#define SIS5595_REVISION_REG 0x08
85#define SIS5595_BASE_REG 0x68
86#define SIS5595_PIN_REG 0x7A
87#define SIS5595_ENABLE_REG 0x7B
88
89/* Where are the ISA address/data registers relative to the base address */
90#define SIS5595_ADDR_REG_OFFSET 5
91#define SIS5595_DATA_REG_OFFSET 6
92
93/* The SIS5595 registers */
94#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
95#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
96#define SIS5595_REG_IN(nr) (0x20 + (nr))
97
98#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
99#define SIS5595_REG_FAN(nr) (0x28 + (nr))
100
101/* On the first version of the chip, the temp registers are separate.
102 On the second version,
103 TEMP pin is shared with IN4, configured in PCI register 0x7A.
104 The registers are the same as well.
105 OVER and HYST are really MAX and MIN. */
106
107#define REV2MIN 0xb0
108#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \
109 SIS5595_REG_IN(4) : 0x27
110#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \
111 SIS5595_REG_IN_MAX(4) : 0x39
112#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \
113 SIS5595_REG_IN_MIN(4) : 0x3a
114
115#define SIS5595_REG_CONFIG 0x40
116#define SIS5595_REG_ALARM1 0x41
117#define SIS5595_REG_ALARM2 0x42
118#define SIS5595_REG_FANDIV 0x47
119
120/* Conversions. Limit checking is only done on the TO_REG
121 variants. */
122
123/* IN: mV, (0V to 4.08V)
124 REG: 16mV/bit */
125static inline u8 IN_TO_REG(unsigned long val)
126{
127 unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
128 return (nval + 8) / 16;
129}
130#define IN_FROM_REG(val) ((val) * 16)
131
132static inline u8 FAN_TO_REG(long rpm, int div)
133{
134 if (rpm <= 0)
135 return 255;
136 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
137}
138
139static inline int FAN_FROM_REG(u8 val, int div)
140{
141 return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
142}
143
144/* TEMP: mC (-54.12C to +157.53C)
145 REG: 0.83C/bit + 52.12, two's complement */
146static inline int TEMP_FROM_REG(s8 val)
147{
148 return val * 830 + 52120;
149}
150static inline s8 TEMP_TO_REG(int val)
151{
152 int nval = SENSORS_LIMIT(val, -54120, 157530) ;
153 return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830;
154}
155
156/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
157 REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
158static inline u8 DIV_TO_REG(int val)
159{
160 return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
161}
162#define DIV_FROM_REG(val) (1 << (val))
163
164/* For the SIS5595, we need to keep some data in memory. That
165 data is pointed to by sis5595_list[NR]->data. The structure itself is
166 dynamically allocated, at the time when the new sis5595 client is
167 allocated. */
168struct sis5595_data {
169 struct i2c_client client;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400170 struct class_device *class_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100171 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100173 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 char valid; /* !=0 if following fields are valid */
175 unsigned long last_updated; /* In jiffies */
176 char maxins; /* == 3 if temp enabled, otherwise == 4 */
177 u8 revision; /* Reg. value */
178
179 u8 in[5]; /* Register value */
180 u8 in_max[5]; /* Register value */
181 u8 in_min[5]; /* Register value */
182 u8 fan[2]; /* Register value */
183 u8 fan_min[2]; /* Register value */
184 s8 temp; /* Register value */
185 s8 temp_over; /* Register value */
186 s8 temp_hyst; /* Register value */
187 u8 fan_div[2]; /* Register encoding, shifted right */
188 u16 alarms; /* Register encoding, combined */
189};
190
191static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
192
Jean Delvare2d8672c2005-07-19 23:56:35 +0200193static int sis5595_detect(struct i2c_adapter *adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194static int sis5595_detach_client(struct i2c_client *client);
195
Darren Jenkinsf6c27fc2006-02-27 23:14:58 +0100196static int sis5595_read_value(struct i2c_client *client, u8 reg);
197static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static struct sis5595_data *sis5595_update_device(struct device *dev);
199static void sis5595_init_client(struct i2c_client *client);
200
201static struct i2c_driver sis5595_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100202 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200203 .owner = THIS_MODULE,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100204 .name = "sis5595",
205 },
Jean Delvare2d8672c2005-07-19 23:56:35 +0200206 .attach_adapter = sis5595_detect,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 .detach_client = sis5595_detach_client,
208};
209
210/* 4 Voltages */
211static ssize_t show_in(struct device *dev, char *buf, int nr)
212{
213 struct sis5595_data *data = sis5595_update_device(dev);
214 return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
215}
216
217static ssize_t show_in_min(struct device *dev, char *buf, int nr)
218{
219 struct sis5595_data *data = sis5595_update_device(dev);
220 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
221}
222
223static ssize_t show_in_max(struct device *dev, char *buf, int nr)
224{
225 struct sis5595_data *data = sis5595_update_device(dev);
226 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
227}
228
229static ssize_t set_in_min(struct device *dev, const char *buf,
230 size_t count, int nr)
231{
232 struct i2c_client *client = to_i2c_client(dev);
233 struct sis5595_data *data = i2c_get_clientdata(client);
234 unsigned long val = simple_strtoul(buf, NULL, 10);
235
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100236 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 data->in_min[nr] = IN_TO_REG(val);
238 sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100239 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 return count;
241}
242
243static ssize_t set_in_max(struct device *dev, const char *buf,
244 size_t count, int nr)
245{
246 struct i2c_client *client = to_i2c_client(dev);
247 struct sis5595_data *data = i2c_get_clientdata(client);
248 unsigned long val = simple_strtoul(buf, NULL, 10);
249
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100250 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 data->in_max[nr] = IN_TO_REG(val);
252 sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100253 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 return count;
255}
256
257#define show_in_offset(offset) \
258static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400259 show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{ \
261 return show_in(dev, buf, offset); \
262} \
263static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
264 show_in##offset, NULL); \
265static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400266 show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{ \
268 return show_in_min(dev, buf, offset); \
269} \
270static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400271 show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{ \
273 return show_in_max(dev, buf, offset); \
274} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400275static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 const char *buf, size_t count) \
277{ \
278 return set_in_min(dev, buf, count, offset); \
279} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400280static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 const char *buf, size_t count) \
282{ \
283 return set_in_max(dev, buf, count, offset); \
284} \
285static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
286 show_in##offset##_min, set_in##offset##_min); \
287static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
288 show_in##offset##_max, set_in##offset##_max);
289
290show_in_offset(0);
291show_in_offset(1);
292show_in_offset(2);
293show_in_offset(3);
294show_in_offset(4);
295
296/* Temperature */
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400297static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 struct sis5595_data *data = sis5595_update_device(dev);
300 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
301}
302
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400303static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
305 struct sis5595_data *data = sis5595_update_device(dev);
306 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
307}
308
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400309static 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 -0700310{
311 struct i2c_client *client = to_i2c_client(dev);
312 struct sis5595_data *data = i2c_get_clientdata(client);
313 long val = simple_strtol(buf, NULL, 10);
314
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100315 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 data->temp_over = TEMP_TO_REG(val);
317 sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100318 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 return count;
320}
321
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400322static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
324 struct sis5595_data *data = sis5595_update_device(dev);
325 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
326}
327
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400328static 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 -0700329{
330 struct i2c_client *client = to_i2c_client(dev);
331 struct sis5595_data *data = i2c_get_clientdata(client);
332 long val = simple_strtol(buf, NULL, 10);
333
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100334 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 data->temp_hyst = TEMP_TO_REG(val);
336 sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100337 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return count;
339}
340
341static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
342static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
343 show_temp_over, set_temp_over);
344static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
345 show_temp_hyst, set_temp_hyst);
346
347/* 2 Fans */
348static ssize_t show_fan(struct device *dev, char *buf, int nr)
349{
350 struct sis5595_data *data = sis5595_update_device(dev);
351 return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
352 DIV_FROM_REG(data->fan_div[nr])) );
353}
354
355static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
356{
357 struct sis5595_data *data = sis5595_update_device(dev);
358 return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
359 DIV_FROM_REG(data->fan_div[nr])) );
360}
361
362static ssize_t set_fan_min(struct device *dev, const char *buf,
363 size_t count, int nr)
364{
365 struct i2c_client *client = to_i2c_client(dev);
366 struct sis5595_data *data = i2c_get_clientdata(client);
367 unsigned long val = simple_strtoul(buf, NULL, 10);
368
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100369 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
371 sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100372 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return count;
374}
375
376static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
377{
378 struct sis5595_data *data = sis5595_update_device(dev);
379 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
380}
381
382/* Note: we save and restore the fan minimum here, because its value is
383 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200384 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 because the divisor changed. */
386static ssize_t set_fan_div(struct device *dev, const char *buf,
387 size_t count, int nr)
388{
389 struct i2c_client *client = to_i2c_client(dev);
390 struct sis5595_data *data = i2c_get_clientdata(client);
391 unsigned long min;
392 unsigned long val = simple_strtoul(buf, NULL, 10);
393 int reg;
394
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100395 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 min = FAN_FROM_REG(data->fan_min[nr],
397 DIV_FROM_REG(data->fan_div[nr]));
398 reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
399
400 switch (val) {
401 case 1: data->fan_div[nr] = 0; break;
402 case 2: data->fan_div[nr] = 1; break;
403 case 4: data->fan_div[nr] = 2; break;
404 case 8: data->fan_div[nr] = 3; break;
405 default:
406 dev_err(&client->dev, "fan_div value %ld not "
407 "supported. Choose one of 1, 2, 4 or 8!\n", val);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100408 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 return -EINVAL;
410 }
411
412 switch (nr) {
413 case 0:
414 reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
415 break;
416 case 1:
417 reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
418 break;
419 }
420 sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
421 data->fan_min[nr] =
422 FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
423 sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100424 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return count;
426}
427
428#define show_fan_offset(offset) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400429static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{ \
431 return show_fan(dev, buf, offset - 1); \
432} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400433static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{ \
435 return show_fan_min(dev, buf, offset - 1); \
436} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400437static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{ \
439 return show_fan_div(dev, buf, offset - 1); \
440} \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400441static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 const char *buf, size_t count) \
443{ \
444 return set_fan_min(dev, buf, count, offset - 1); \
445} \
446static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
447static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
448 show_fan_##offset##_min, set_fan_##offset##_min);
449
450show_fan_offset(1);
451show_fan_offset(2);
452
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400453static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 size_t count)
455{
456 return set_fan_div(dev, buf, count, 0) ;
457}
458
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400459static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 size_t count)
461{
462 return set_fan_div(dev, buf, count, 1) ;
463}
464static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
465 show_fan_1_div, set_fan_1_div);
466static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
467 show_fan_2_div, set_fan_2_div);
468
469/* Alarms */
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400470static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 struct sis5595_data *data = sis5595_update_device(dev);
473 return sprintf(buf, "%d\n", data->alarms);
474}
475static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
476
477/* This is called when the module is loaded */
Jean Delvare2d8672c2005-07-19 23:56:35 +0200478static int sis5595_detect(struct i2c_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
480 int err = 0;
481 int i;
482 struct i2c_client *new_client;
483 struct sis5595_data *data;
484 char val;
485 u16 a;
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (force_addr)
488 address = force_addr & ~(SIS5595_EXTENT - 1);
489 /* Reserve the ISA region */
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100490 if (!request_region(address, SIS5595_EXTENT,
491 sis5595_driver.driver.name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 err = -EBUSY;
493 goto exit;
494 }
495 if (force_addr) {
496 dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
497 if (PCIBIOS_SUCCESSFUL !=
498 pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
499 goto exit_release;
500 if (PCIBIOS_SUCCESSFUL !=
501 pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
502 goto exit_release;
503 if ((a & ~(SIS5595_EXTENT - 1)) != address)
504 /* doesn't work for some chips? */
505 goto exit_release;
506 }
507
508 if (PCIBIOS_SUCCESSFUL !=
509 pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
510 goto exit_release;
511 }
512 if ((val & 0x80) == 0) {
513 if (PCIBIOS_SUCCESSFUL !=
514 pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
515 val | 0x80))
516 goto exit_release;
517 if (PCIBIOS_SUCCESSFUL !=
518 pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
519 goto exit_release;
520 if ((val & 0x80) == 0)
521 /* doesn't work for some chips! */
522 goto exit_release;
523 }
524
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200525 if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 err = -ENOMEM;
527 goto exit_release;
528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 new_client = &data->client;
531 new_client->addr = address;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100532 mutex_init(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 i2c_set_clientdata(new_client, data);
534 new_client->adapter = adapter;
535 new_client->driver = &sis5595_driver;
536 new_client->flags = 0;
537
538 /* Check revision and pin registers to determine whether 4 or 5 voltages */
539 pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
540 /* 4 voltages, 1 temp */
541 data->maxins = 3;
542 if (data->revision >= REV2MIN) {
543 pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
544 if (!(val & 0x80))
545 /* 5 voltages, no temps */
546 data->maxins = 4;
547 }
548
549 /* Fill in the remaining client fields and put it into the global list */
550 strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
551
552 data->valid = 0;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100553 mutex_init(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 /* Tell the I2C layer a new client has arrived */
556 if ((err = i2c_attach_client(new_client)))
557 goto exit_free;
558
559 /* Initialize the SIS5595 chip */
560 sis5595_init_client(new_client);
561
562 /* A few vars need to be filled upon startup */
563 for (i = 0; i < 2; i++) {
564 data->fan_min[i] = sis5595_read_value(new_client,
565 SIS5595_REG_FAN_MIN(i));
566 }
567
568 /* Register sysfs hooks */
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400569 data->class_dev = hwmon_device_register(&new_client->dev);
570 if (IS_ERR(data->class_dev)) {
571 err = PTR_ERR(data->class_dev);
572 goto exit_detach;
573 }
574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 device_create_file(&new_client->dev, &dev_attr_in0_input);
576 device_create_file(&new_client->dev, &dev_attr_in0_min);
577 device_create_file(&new_client->dev, &dev_attr_in0_max);
578 device_create_file(&new_client->dev, &dev_attr_in1_input);
579 device_create_file(&new_client->dev, &dev_attr_in1_min);
580 device_create_file(&new_client->dev, &dev_attr_in1_max);
581 device_create_file(&new_client->dev, &dev_attr_in2_input);
582 device_create_file(&new_client->dev, &dev_attr_in2_min);
583 device_create_file(&new_client->dev, &dev_attr_in2_max);
584 device_create_file(&new_client->dev, &dev_attr_in3_input);
585 device_create_file(&new_client->dev, &dev_attr_in3_min);
586 device_create_file(&new_client->dev, &dev_attr_in3_max);
587 if (data->maxins == 4) {
588 device_create_file(&new_client->dev, &dev_attr_in4_input);
589 device_create_file(&new_client->dev, &dev_attr_in4_min);
590 device_create_file(&new_client->dev, &dev_attr_in4_max);
591 }
592 device_create_file(&new_client->dev, &dev_attr_fan1_input);
593 device_create_file(&new_client->dev, &dev_attr_fan1_min);
594 device_create_file(&new_client->dev, &dev_attr_fan1_div);
595 device_create_file(&new_client->dev, &dev_attr_fan2_input);
596 device_create_file(&new_client->dev, &dev_attr_fan2_min);
597 device_create_file(&new_client->dev, &dev_attr_fan2_div);
598 device_create_file(&new_client->dev, &dev_attr_alarms);
599 if (data->maxins == 3) {
600 device_create_file(&new_client->dev, &dev_attr_temp1_input);
601 device_create_file(&new_client->dev, &dev_attr_temp1_max);
602 device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
603 }
604 return 0;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400605
606exit_detach:
607 i2c_detach_client(new_client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608exit_free:
609 kfree(data);
610exit_release:
611 release_region(address, SIS5595_EXTENT);
612exit:
613 return err;
614}
615
616static int sis5595_detach_client(struct i2c_client *client)
617{
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400618 struct sis5595_data *data = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 int err;
620
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400621 hwmon_device_unregister(data->class_dev);
622
Jean Delvare7bef5592005-07-27 22:14:49 +0200623 if ((err = i2c_detach_client(client)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Jean Delvare2d8672c2005-07-19 23:56:35 +0200626 release_region(client->addr, SIS5595_EXTENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400628 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 return 0;
631}
632
633
634/* ISA access must be locked explicitly. */
635static int sis5595_read_value(struct i2c_client *client, u8 reg)
636{
637 int res;
638
639 struct sis5595_data *data = i2c_get_clientdata(client);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100640 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
642 res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100643 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return res;
645}
646
647static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
648{
649 struct sis5595_data *data = i2c_get_clientdata(client);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100650 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
652 outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100653 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return 0;
655}
656
657/* Called when we have found a new SIS5595. */
658static void sis5595_init_client(struct i2c_client *client)
659{
660 u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
661 if (!(config & 0x01))
662 sis5595_write_value(client, SIS5595_REG_CONFIG,
663 (config & 0xf7) | 0x01);
664}
665
666static struct sis5595_data *sis5595_update_device(struct device *dev)
667{
668 struct i2c_client *client = to_i2c_client(dev);
669 struct sis5595_data *data = i2c_get_clientdata(client);
670 int i;
671
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100672 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
675 || !data->valid) {
676
677 for (i = 0; i <= data->maxins; i++) {
678 data->in[i] =
679 sis5595_read_value(client, SIS5595_REG_IN(i));
680 data->in_min[i] =
681 sis5595_read_value(client,
682 SIS5595_REG_IN_MIN(i));
683 data->in_max[i] =
684 sis5595_read_value(client,
685 SIS5595_REG_IN_MAX(i));
686 }
687 for (i = 0; i < 2; i++) {
688 data->fan[i] =
689 sis5595_read_value(client, SIS5595_REG_FAN(i));
690 data->fan_min[i] =
691 sis5595_read_value(client,
692 SIS5595_REG_FAN_MIN(i));
693 }
694 if (data->maxins == 3) {
695 data->temp =
696 sis5595_read_value(client, SIS5595_REG_TEMP);
697 data->temp_over =
698 sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
699 data->temp_hyst =
700 sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
701 }
702 i = sis5595_read_value(client, SIS5595_REG_FANDIV);
703 data->fan_div[0] = (i >> 4) & 0x03;
704 data->fan_div[1] = i >> 6;
705 data->alarms =
706 sis5595_read_value(client, SIS5595_REG_ALARM1) |
707 (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
708 data->last_updated = jiffies;
709 data->valid = 1;
710 }
711
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100712 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
714 return data;
715}
716
717static struct pci_device_id sis5595_pci_ids[] = {
718 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
719 { 0, }
720};
721
722MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
723
724static int blacklist[] __devinitdata = {
725 PCI_DEVICE_ID_SI_540,
726 PCI_DEVICE_ID_SI_550,
727 PCI_DEVICE_ID_SI_630,
728 PCI_DEVICE_ID_SI_645,
729 PCI_DEVICE_ID_SI_730,
730 PCI_DEVICE_ID_SI_735,
731 PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
732 that ID shows up in other chips so we
733 use the 5511 ID for recognition */
734 PCI_DEVICE_ID_SI_5597,
735 PCI_DEVICE_ID_SI_5598,
736 0 };
737
738static int __devinit sis5595_pci_probe(struct pci_dev *dev,
739 const struct pci_device_id *id)
740{
741 u16 val;
742 int *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 for (i = blacklist; *i != 0; i++) {
745 struct pci_dev *dev;
746 dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
747 if (dev) {
748 dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
749 pci_dev_put(dev);
750 return -ENODEV;
751 }
752 }
753
754 if (PCIBIOS_SUCCESSFUL !=
755 pci_read_config_word(dev, SIS5595_BASE_REG, &val))
756 return -ENODEV;
757
Jean Delvare2d8672c2005-07-19 23:56:35 +0200758 address = val & ~(SIS5595_EXTENT - 1);
759 if (address == 0 && force_addr == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
761 return -ENODEV;
762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 s_bridge = pci_dev_get(dev);
Jean Delvarefde09502005-07-19 23:51:07 +0200765 if (i2c_isa_add_driver(&sis5595_driver)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 pci_dev_put(s_bridge);
767 s_bridge = NULL;
768 }
769
770 /* Always return failure here. This is to allow other drivers to bind
771 * to this pci device. We don't really want to have control over the
772 * pci device, we only wanted to read as few register values from it.
773 */
774 return -ENODEV;
775}
776
777static struct pci_driver sis5595_pci_driver = {
778 .name = "sis5595",
779 .id_table = sis5595_pci_ids,
780 .probe = sis5595_pci_probe,
781};
782
783static int __init sm_sis5595_init(void)
784{
785 return pci_register_driver(&sis5595_pci_driver);
786}
787
788static void __exit sm_sis5595_exit(void)
789{
790 pci_unregister_driver(&sis5595_pci_driver);
791 if (s_bridge != NULL) {
Jean Delvarefde09502005-07-19 23:51:07 +0200792 i2c_isa_del_driver(&sis5595_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 pci_dev_put(s_bridge);
794 s_bridge = NULL;
795 }
796}
797
798MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
799MODULE_DESCRIPTION("SiS 5595 Sensor device");
800MODULE_LICENSE("GPL");
801
802module_init(sm_sis5595_init);
803module_exit(sm_sis5595_exit);