blob: 33242456e2d230ac564fc741d80efa3aa126b1e8 [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>,
Jan Engelhardt96de0e22007-10-19 23:21:04 +02006 Kyösti Mälkki <kmalkki@cc.hut.fi>, and
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 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
Joe Perches4b2515d2010-10-20 06:51:47 +000053#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <linux/module.h>
56#include <linux/slab.h>
57#include <linux/ioport.h>
58#include <linux/pci.h>
Jean Delvare17e7dc42007-06-09 10:11:16 -040059#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040060#include <linux/hwmon.h>
Jean Delvare1f5f48d2007-06-09 10:11:16 -040061#include <linux/hwmon-sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040062#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#include <linux/init.h>
Dominik Hacklff324092005-05-16 18:12:18 +020064#include <linux/jiffies.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010065#include <linux/mutex.h>
Jean Delvarea5ebe662006-09-24 21:24:46 +020066#include <linux/sysfs.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010067#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020068#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70
71/* If force_addr is set to anything different from 0, we forcibly enable
72 the device at the given address. */
73static u16 force_addr;
74module_param(force_addr, ushort, 0);
75MODULE_PARM_DESC(force_addr,
76 "Initialize the base address of the sensors");
77
Jean Delvare17e7dc42007-06-09 10:11:16 -040078static struct platform_device *pdev;
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#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
Jean Delvareed6bafb2007-02-14 21:15:03 +0100164/* For each registered chip, we need to keep some data in memory.
165 The structure is dynamically allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166struct sis5595_data {
Jean Delvare17e7dc42007-06-09 10:11:16 -0400167 unsigned short addr;
168 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700169 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100170 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100172 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 char valid; /* !=0 if following fields are valid */
174 unsigned long last_updated; /* In jiffies */
175 char maxins; /* == 3 if temp enabled, otherwise == 4 */
176 u8 revision; /* Reg. value */
177
178 u8 in[5]; /* Register value */
179 u8 in_max[5]; /* Register value */
180 u8 in_min[5]; /* Register value */
181 u8 fan[2]; /* Register value */
182 u8 fan_min[2]; /* Register value */
183 s8 temp; /* Register value */
184 s8 temp_over; /* Register value */
185 s8 temp_hyst; /* Register value */
186 u8 fan_div[2]; /* Register encoding, shifted right */
187 u16 alarms; /* Register encoding, combined */
188};
189
190static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
191
Jean Delvare17e7dc42007-06-09 10:11:16 -0400192static int sis5595_probe(struct platform_device *pdev);
Jean Delvared0546122007-07-22 12:09:48 +0200193static int __devexit sis5595_remove(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Jean Delvare17e7dc42007-06-09 10:11:16 -0400195static int sis5595_read_value(struct sis5595_data *data, u8 reg);
196static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static struct sis5595_data *sis5595_update_device(struct device *dev);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400198static void sis5595_init_device(struct sis5595_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Jean Delvare17e7dc42007-06-09 10:11:16 -0400200static struct platform_driver sis5595_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100201 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200202 .owner = THIS_MODULE,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100203 .name = "sis5595",
204 },
Jean Delvare17e7dc42007-06-09 10:11:16 -0400205 .probe = sis5595_probe,
206 .remove = __devexit_p(sis5595_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207};
208
209/* 4 Voltages */
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400210static ssize_t show_in(struct device *dev, struct device_attribute *da,
211 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
213 struct sis5595_data *data = sis5595_update_device(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400214 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
215 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
217}
218
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400219static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
220 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
222 struct sis5595_data *data = sis5595_update_device(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400223 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
224 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
226}
227
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400228static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
229 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
231 struct sis5595_data *data = sis5595_update_device(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400232 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
233 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
235}
236
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400237static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
238 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400240 struct sis5595_data *data = dev_get_drvdata(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400241 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
242 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 unsigned long val = simple_strtoul(buf, NULL, 10);
244
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100245 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 data->in_min[nr] = IN_TO_REG(val);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400247 sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100248 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 return count;
250}
251
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400252static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
253 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400255 struct sis5595_data *data = dev_get_drvdata(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400256 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
257 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 unsigned long val = simple_strtoul(buf, NULL, 10);
259
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100260 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 data->in_max[nr] = IN_TO_REG(val);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400262 sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100263 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return count;
265}
266
267#define show_in_offset(offset) \
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400268static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
269 show_in, NULL, offset); \
270static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
271 show_in_min, set_in_min, offset); \
272static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
273 show_in_max, set_in_max, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275show_in_offset(0);
276show_in_offset(1);
277show_in_offset(2);
278show_in_offset(3);
279show_in_offset(4);
280
281/* Temperature */
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400282static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
284 struct sis5595_data *data = sis5595_update_device(dev);
285 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
286}
287
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400288static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 struct sis5595_data *data = sis5595_update_device(dev);
291 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
292}
293
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400294static 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 -0700295{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400296 struct sis5595_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 long val = simple_strtol(buf, NULL, 10);
298
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100299 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 data->temp_over = TEMP_TO_REG(val);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400301 sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100302 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 return count;
304}
305
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400306static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
308 struct sis5595_data *data = sis5595_update_device(dev);
309 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
310}
311
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400312static 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 -0700313{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400314 struct sis5595_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 long val = simple_strtol(buf, NULL, 10);
316
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100317 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 data->temp_hyst = TEMP_TO_REG(val);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400319 sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100320 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 return count;
322}
323
324static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
325static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
326 show_temp_over, set_temp_over);
327static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
328 show_temp_hyst, set_temp_hyst);
329
330/* 2 Fans */
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400331static ssize_t show_fan(struct device *dev, struct device_attribute *da,
332 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 struct sis5595_data *data = sis5595_update_device(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400335 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
336 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
338 DIV_FROM_REG(data->fan_div[nr])) );
339}
340
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400341static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
342 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 struct sis5595_data *data = sis5595_update_device(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400345 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
346 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
348 DIV_FROM_REG(data->fan_div[nr])) );
349}
350
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400351static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
352 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400354 struct sis5595_data *data = dev_get_drvdata(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400355 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
356 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 unsigned long val = simple_strtoul(buf, NULL, 10);
358
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100359 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare17e7dc42007-06-09 10:11:16 -0400361 sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100362 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return count;
364}
365
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400366static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
367 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 struct sis5595_data *data = sis5595_update_device(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400370 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
371 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
373}
374
375/* Note: we save and restore the fan minimum here, because its value is
376 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200377 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 because the divisor changed. */
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400379static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
380 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400382 struct sis5595_data *data = dev_get_drvdata(dev);
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400383 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
384 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 unsigned long min;
386 unsigned long val = simple_strtoul(buf, NULL, 10);
387 int reg;
388
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100389 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 min = FAN_FROM_REG(data->fan_min[nr],
391 DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare17e7dc42007-06-09 10:11:16 -0400392 reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 switch (val) {
395 case 1: data->fan_div[nr] = 0; break;
396 case 2: data->fan_div[nr] = 1; break;
397 case 4: data->fan_div[nr] = 2; break;
398 case 8: data->fan_div[nr] = 3; break;
399 default:
Jean Delvare17e7dc42007-06-09 10:11:16 -0400400 dev_err(dev, "fan_div value %ld not "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 "supported. Choose one of 1, 2, 4 or 8!\n", val);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100402 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return -EINVAL;
404 }
405
406 switch (nr) {
407 case 0:
408 reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
409 break;
410 case 1:
411 reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
412 break;
413 }
Jean Delvare17e7dc42007-06-09 10:11:16 -0400414 sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 data->fan_min[nr] =
416 FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare17e7dc42007-06-09 10:11:16 -0400417 sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100418 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 return count;
420}
421
422#define show_fan_offset(offset) \
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400423static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
424 show_fan, NULL, offset - 1); \
425static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
426 show_fan_min, set_fan_min, offset - 1); \
427static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
428 show_fan_div, set_fan_div, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
430show_fan_offset(1);
431show_fan_offset(2);
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433/* Alarms */
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400434static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 struct sis5595_data *data = sis5595_update_device(dev);
437 return sprintf(buf, "%d\n", data->alarms);
438}
439static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200440
Ivo Manca5c726b32007-10-15 20:50:53 +0200441static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
442 char *buf)
443{
444 struct sis5595_data *data = sis5595_update_device(dev);
445 int nr = to_sensor_dev_attr(da)->index;
446 return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
447}
448static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
449static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
450static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
451static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
452static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
453static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
454static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
455static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
456
Jean Delvare17e7dc42007-06-09 10:11:16 -0400457static ssize_t show_name(struct device *dev, struct device_attribute *attr,
458 char *buf)
459{
460 struct sis5595_data *data = dev_get_drvdata(dev);
461 return sprintf(buf, "%s\n", data->name);
462}
463static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
464
Jean Delvarea5ebe662006-09-24 21:24:46 +0200465static struct attribute *sis5595_attributes[] = {
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400466 &sensor_dev_attr_in0_input.dev_attr.attr,
467 &sensor_dev_attr_in0_min.dev_attr.attr,
468 &sensor_dev_attr_in0_max.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200469 &sensor_dev_attr_in0_alarm.dev_attr.attr,
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400470 &sensor_dev_attr_in1_input.dev_attr.attr,
471 &sensor_dev_attr_in1_min.dev_attr.attr,
472 &sensor_dev_attr_in1_max.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200473 &sensor_dev_attr_in1_alarm.dev_attr.attr,
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400474 &sensor_dev_attr_in2_input.dev_attr.attr,
475 &sensor_dev_attr_in2_min.dev_attr.attr,
476 &sensor_dev_attr_in2_max.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200477 &sensor_dev_attr_in2_alarm.dev_attr.attr,
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400478 &sensor_dev_attr_in3_input.dev_attr.attr,
479 &sensor_dev_attr_in3_min.dev_attr.attr,
480 &sensor_dev_attr_in3_max.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200481 &sensor_dev_attr_in3_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200482
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400483 &sensor_dev_attr_fan1_input.dev_attr.attr,
484 &sensor_dev_attr_fan1_min.dev_attr.attr,
485 &sensor_dev_attr_fan1_div.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200486 &sensor_dev_attr_fan1_alarm.dev_attr.attr,
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400487 &sensor_dev_attr_fan2_input.dev_attr.attr,
488 &sensor_dev_attr_fan2_min.dev_attr.attr,
489 &sensor_dev_attr_fan2_div.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200490 &sensor_dev_attr_fan2_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200491
492 &dev_attr_alarms.attr,
Jean Delvare17e7dc42007-06-09 10:11:16 -0400493 &dev_attr_name.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200494 NULL
495};
496
497static const struct attribute_group sis5595_group = {
498 .attrs = sis5595_attributes,
499};
500
Ivo Manca76e63862007-10-15 13:27:13 +0200501static struct attribute *sis5595_attributes_in4[] = {
Jean Delvare1f5f48d2007-06-09 10:11:16 -0400502 &sensor_dev_attr_in4_input.dev_attr.attr,
503 &sensor_dev_attr_in4_min.dev_attr.attr,
504 &sensor_dev_attr_in4_max.dev_attr.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200505 &sensor_dev_attr_in4_alarm.dev_attr.attr,
Ivo Manca76e63862007-10-15 13:27:13 +0200506 NULL
507};
Jean Delvarea5ebe662006-09-24 21:24:46 +0200508
Ivo Manca76e63862007-10-15 13:27:13 +0200509static const struct attribute_group sis5595_group_in4 = {
510 .attrs = sis5595_attributes_in4,
511};
512
513static struct attribute *sis5595_attributes_temp1[] = {
Jean Delvarea5ebe662006-09-24 21:24:46 +0200514 &dev_attr_temp1_input.attr,
515 &dev_attr_temp1_max.attr,
516 &dev_attr_temp1_max_hyst.attr,
Ivo Manca5c726b32007-10-15 20:50:53 +0200517 &sensor_dev_attr_temp1_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200518 NULL
519};
520
Ivo Manca76e63862007-10-15 13:27:13 +0200521static const struct attribute_group sis5595_group_temp1 = {
522 .attrs = sis5595_attributes_temp1,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200523};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525/* This is called when the module is loaded */
Jean Delvare17e7dc42007-06-09 10:11:16 -0400526static int __devinit sis5595_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 int err = 0;
529 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 struct sis5595_data *data;
Jean Delvare17e7dc42007-06-09 10:11:16 -0400531 struct resource *res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 char val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 /* Reserve the ISA region */
Jean Delvare17e7dc42007-06-09 10:11:16 -0400535 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
536 if (!request_region(res->start, SIS5595_EXTENT,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100537 sis5595_driver.driver.name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 err = -EBUSY;
539 goto exit;
540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Deepak Saxenaba9c2e82005-10-17 23:08:32 +0200542 if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 err = -ENOMEM;
544 goto exit_release;
545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100547 mutex_init(&data->lock);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400548 mutex_init(&data->update_lock);
549 data->addr = res->start;
550 data->name = "sis5595";
551 platform_set_drvdata(pdev, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 /* Check revision and pin registers to determine whether 4 or 5 voltages */
Auke Kok7b6d1f02007-08-27 16:17:01 -0700554 data->revision = s_bridge->revision;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 /* 4 voltages, 1 temp */
556 data->maxins = 3;
557 if (data->revision >= REV2MIN) {
558 pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
559 if (!(val & 0x80))
560 /* 5 voltages, no temps */
561 data->maxins = 4;
562 }
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 /* Initialize the SIS5595 chip */
Jean Delvare17e7dc42007-06-09 10:11:16 -0400565 sis5595_init_device(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 /* A few vars need to be filled upon startup */
568 for (i = 0; i < 2; i++) {
Jean Delvare17e7dc42007-06-09 10:11:16 -0400569 data->fan_min[i] = sis5595_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 SIS5595_REG_FAN_MIN(i));
571 }
572
573 /* Register sysfs hooks */
Jean Delvare17e7dc42007-06-09 10:11:16 -0400574 if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
575 goto exit_free;
Jean Delvarea5ebe662006-09-24 21:24:46 +0200576 if (data->maxins == 4) {
Ivo Manca76e63862007-10-15 13:27:13 +0200577 if ((err = sysfs_create_group(&pdev->dev.kobj,
578 &sis5595_group_in4)))
Jean Delvarea5ebe662006-09-24 21:24:46 +0200579 goto exit_remove_files;
580 } else {
Ivo Manca76e63862007-10-15 13:27:13 +0200581 if ((err = sysfs_create_group(&pdev->dev.kobj,
582 &sis5595_group_temp1)))
Jean Delvarea5ebe662006-09-24 21:24:46 +0200583 goto exit_remove_files;
584 }
585
Tony Jones1beeffe2007-08-20 13:46:20 -0700586 data->hwmon_dev = hwmon_device_register(&pdev->dev);
587 if (IS_ERR(data->hwmon_dev)) {
588 err = PTR_ERR(data->hwmon_dev);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200589 goto exit_remove_files;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400590 }
591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 return 0;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400593
Jean Delvarea5ebe662006-09-24 21:24:46 +0200594exit_remove_files:
Jean Delvare17e7dc42007-06-09 10:11:16 -0400595 sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
Ivo Manca76e63862007-10-15 13:27:13 +0200596 sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
597 sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598exit_free:
599 kfree(data);
600exit_release:
Jean Delvare17e7dc42007-06-09 10:11:16 -0400601 release_region(res->start, SIS5595_EXTENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602exit:
603 return err;
604}
605
Jean Delvare17e7dc42007-06-09 10:11:16 -0400606static int __devexit sis5595_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400608 struct sis5595_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Tony Jones1beeffe2007-08-20 13:46:20 -0700610 hwmon_device_unregister(data->hwmon_dev);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400611 sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
Ivo Manca76e63862007-10-15 13:27:13 +0200612 sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
613 sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400614
Jean Delvare17e7dc42007-06-09 10:11:16 -0400615 release_region(data->addr, SIS5595_EXTENT);
616 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400617 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 return 0;
620}
621
622
623/* ISA access must be locked explicitly. */
Jean Delvare17e7dc42007-06-09 10:11:16 -0400624static int sis5595_read_value(struct sis5595_data *data, u8 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 int res;
627
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100628 mutex_lock(&data->lock);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400629 outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
630 res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100631 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return res;
633}
634
Jean Delvare17e7dc42007-06-09 10:11:16 -0400635static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100637 mutex_lock(&data->lock);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400638 outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
639 outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100640 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
643/* Called when we have found a new SIS5595. */
Jean Delvare17e7dc42007-06-09 10:11:16 -0400644static void __devinit sis5595_init_device(struct sis5595_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400646 u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 if (!(config & 0x01))
Jean Delvare17e7dc42007-06-09 10:11:16 -0400648 sis5595_write_value(data, SIS5595_REG_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 (config & 0xf7) | 0x01);
650}
651
652static struct sis5595_data *sis5595_update_device(struct device *dev)
653{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400654 struct sis5595_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 int i;
656
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100657 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
660 || !data->valid) {
661
662 for (i = 0; i <= data->maxins; i++) {
663 data->in[i] =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400664 sis5595_read_value(data, SIS5595_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 data->in_min[i] =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400666 sis5595_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 SIS5595_REG_IN_MIN(i));
668 data->in_max[i] =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400669 sis5595_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 SIS5595_REG_IN_MAX(i));
671 }
672 for (i = 0; i < 2; i++) {
673 data->fan[i] =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400674 sis5595_read_value(data, SIS5595_REG_FAN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 data->fan_min[i] =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400676 sis5595_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 SIS5595_REG_FAN_MIN(i));
678 }
679 if (data->maxins == 3) {
680 data->temp =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400681 sis5595_read_value(data, SIS5595_REG_TEMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 data->temp_over =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400683 sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 data->temp_hyst =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400685 sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
Jean Delvare17e7dc42007-06-09 10:11:16 -0400687 i = sis5595_read_value(data, SIS5595_REG_FANDIV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 data->fan_div[0] = (i >> 4) & 0x03;
689 data->fan_div[1] = i >> 6;
690 data->alarms =
Jean Delvare17e7dc42007-06-09 10:11:16 -0400691 sis5595_read_value(data, SIS5595_REG_ALARM1) |
692 (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 data->last_updated = jiffies;
694 data->valid = 1;
695 }
696
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100697 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 return data;
700}
701
Frans Meulenbroeks600151b2012-01-05 19:50:17 +0100702static DEFINE_PCI_DEVICE_TABLE(sis5595_pci_ids) = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
704 { 0, }
705};
706
707MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
708
709static int blacklist[] __devinitdata = {
710 PCI_DEVICE_ID_SI_540,
711 PCI_DEVICE_ID_SI_550,
712 PCI_DEVICE_ID_SI_630,
713 PCI_DEVICE_ID_SI_645,
714 PCI_DEVICE_ID_SI_730,
715 PCI_DEVICE_ID_SI_735,
716 PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
717 that ID shows up in other chips so we
718 use the 5511 ID for recognition */
719 PCI_DEVICE_ID_SI_5597,
720 PCI_DEVICE_ID_SI_5598,
721 0 };
722
Jean Delvare17e7dc42007-06-09 10:11:16 -0400723static int __devinit sis5595_device_add(unsigned short address)
724{
725 struct resource res = {
726 .start = address,
727 .end = address + SIS5595_EXTENT - 1,
728 .name = "sis5595",
729 .flags = IORESOURCE_IO,
730 };
731 int err;
732
Jean Delvareb9acb642009-01-07 16:37:35 +0100733 err = acpi_check_resource_conflict(&res);
734 if (err)
735 goto exit;
736
Jean Delvare17e7dc42007-06-09 10:11:16 -0400737 pdev = platform_device_alloc("sis5595", address);
738 if (!pdev) {
739 err = -ENOMEM;
Joe Perches4b2515d2010-10-20 06:51:47 +0000740 pr_err("Device allocation failed\n");
Jean Delvare17e7dc42007-06-09 10:11:16 -0400741 goto exit;
742 }
743
744 err = platform_device_add_resources(pdev, &res, 1);
745 if (err) {
Joe Perches4b2515d2010-10-20 06:51:47 +0000746 pr_err("Device resource addition failed (%d)\n", err);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400747 goto exit_device_put;
748 }
749
750 err = platform_device_add(pdev);
751 if (err) {
Joe Perches4b2515d2010-10-20 06:51:47 +0000752 pr_err("Device addition failed (%d)\n", err);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400753 goto exit_device_put;
754 }
755
756 return 0;
757
758exit_device_put:
759 platform_device_put(pdev);
760exit:
761 return err;
762}
763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764static int __devinit sis5595_pci_probe(struct pci_dev *dev,
765 const struct pci_device_id *id)
766{
Jean Delvare17e7dc42007-06-09 10:11:16 -0400767 u16 address;
768 u8 enable;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 int *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 for (i = blacklist; *i != 0; i++) {
Mark M. Hoffman5460a9d2007-10-14 14:57:35 -0400772 struct pci_dev *d;
773 if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) {
774 dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
775 pci_dev_put(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return -ENODEV;
777 }
778 }
779
Jean Delvare17e7dc42007-06-09 10:11:16 -0400780 force_addr &= ~(SIS5595_EXTENT - 1);
781 if (force_addr) {
782 dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
783 pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
784 }
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (PCIBIOS_SUCCESSFUL !=
Jean Delvare17e7dc42007-06-09 10:11:16 -0400787 pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
788 dev_err(&dev->dev, "Failed to read ISA address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return -ENODEV;
Jean Delvare17e7dc42007-06-09 10:11:16 -0400790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Jean Delvare17e7dc42007-06-09 10:11:16 -0400792 address &= ~(SIS5595_EXTENT - 1);
793 if (!address) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
795 return -ENODEV;
796 }
Jean Delvare17e7dc42007-06-09 10:11:16 -0400797 if (force_addr && address != force_addr) {
798 /* doesn't work for some chips? */
799 dev_err(&dev->dev, "Failed to force ISA address\n");
800 return -ENODEV;
801 }
802
803 if (PCIBIOS_SUCCESSFUL !=
804 pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
805 dev_err(&dev->dev, "Failed to read enable register\n");
806 return -ENODEV;
807 }
808 if (!(enable & 0x80)) {
809 if ((PCIBIOS_SUCCESSFUL !=
810 pci_write_config_byte(dev, SIS5595_ENABLE_REG,
811 enable | 0x80))
812 || (PCIBIOS_SUCCESSFUL !=
813 pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
814 || (!(enable & 0x80))) {
815 /* doesn't work for some chips! */
816 dev_err(&dev->dev, "Failed to enable HWM device\n");
817 return -ENODEV;
818 }
819 }
820
821 if (platform_driver_register(&sis5595_driver)) {
822 dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
823 goto exit;
824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 s_bridge = pci_dev_get(dev);
Jean Delvare17e7dc42007-06-09 10:11:16 -0400827 /* Sets global pdev as a side effect */
828 if (sis5595_device_add(address))
829 goto exit_unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 /* Always return failure here. This is to allow other drivers to bind
832 * to this pci device. We don't really want to have control over the
833 * pci device, we only wanted to read as few register values from it.
834 */
835 return -ENODEV;
Jean Delvare17e7dc42007-06-09 10:11:16 -0400836
837exit_unregister:
838 pci_dev_put(dev);
839 platform_driver_unregister(&sis5595_driver);
840exit:
841 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842}
843
844static struct pci_driver sis5595_pci_driver = {
845 .name = "sis5595",
846 .id_table = sis5595_pci_ids,
847 .probe = sis5595_pci_probe,
848};
849
850static int __init sm_sis5595_init(void)
851{
852 return pci_register_driver(&sis5595_pci_driver);
853}
854
855static void __exit sm_sis5595_exit(void)
856{
857 pci_unregister_driver(&sis5595_pci_driver);
858 if (s_bridge != NULL) {
Jean Delvare17e7dc42007-06-09 10:11:16 -0400859 platform_device_unregister(pdev);
860 platform_driver_unregister(&sis5595_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 pci_dev_put(s_bridge);
862 s_bridge = NULL;
863 }
864}
865
866MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
867MODULE_DESCRIPTION("SiS 5595 Sensor device");
868MODULE_LICENSE("GPL");
869
870module_init(sm_sis5595_init);
871module_exit(sm_sis5595_exit);