Blame view

drivers/hwmon/sis5595.c 25.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
      sis5595.c - Part of lm_sensors, Linux kernel modules
  		for hardware monitoring
  
      Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
96de0e252   Jan Engelhardt   Convert files to ...
6
  			Kyösti Mälkki <kmalkki@cc.hut.fi>, and
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  			Mark D. Studebaker <mdsxyz123@yahoo.com>
      Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
      the help of Jean Delvare <khali@linux-fr.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.
  
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  
  /*
     SiS southbridge has a LM78-like chip integrated on the same IC.
     This driver is a customized copy of lm78.c
     
     Supports following revisions:
  	Version		PCI ID		PCI Revision
  	1		1039/0008	AF or less
  	2		1039/0008	B0 or greater
  
     Note: these chips contain a 0008 device which is incompatible with the
  	 5595. We recognize these by the presence of the listed
  	 "blacklist" PCI ID and refuse to load.
  
     NOT SUPPORTED	PCI ID		BLACKLIST PCI ID	
  	 540		0008		0540
  	 550		0008		0550
  	5513		0008		5511
  	5581		0008		5597
  	5582		0008		5597
  	5597		0008		5597
  	5598		0008		5597/5598
  	 630		0008		0630
  	 645		0008		0645
  	 730		0008		0730
  	 735		0008		0735
  */
4b2515dbb   Joe Perches   hwmon: (sis5595) ...
52
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/ioport.h>
  #include <linux/pci.h>
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
57
  #include <linux/platform_device.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
58
  #include <linux/hwmon.h>
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
59
  #include <linux/hwmon-sysfs.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
60
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  #include <linux/init.h>
ff3240946   Dominik Hackl   [PATCH] I2C: incl...
62
  #include <linux/jiffies.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
63
  #include <linux/mutex.h>
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
64
  #include <linux/sysfs.h>
b9acb64a3   Jean Delvare   hwmon: Check for ...
65
  #include <linux/acpi.h>
6055fae8a   H Hartley Sweeten   hwmon: Include <l...
66
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
  
  
  /* If force_addr is set to anything different from 0, we forcibly enable
     the device at the given address. */
  static u16 force_addr;
  module_param(force_addr, ushort, 0);
  MODULE_PARM_DESC(force_addr,
  		 "Initialize the base address of the sensors");
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
75
  static struct platform_device *pdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
  
  /* Many SIS5595 constants specified below */
  
  /* Length of ISA address segment */
  #define SIS5595_EXTENT 8
  /* PCI Config Registers */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  #define SIS5595_BASE_REG 0x68
  #define SIS5595_PIN_REG 0x7A
  #define SIS5595_ENABLE_REG 0x7B
  
  /* Where are the ISA address/data registers relative to the base address */
  #define SIS5595_ADDR_REG_OFFSET 5
  #define SIS5595_DATA_REG_OFFSET 6
  
  /* The SIS5595 registers */
  #define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
  #define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
  #define SIS5595_REG_IN(nr) (0x20 + (nr))
  
  #define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
  #define SIS5595_REG_FAN(nr) (0x28 + (nr))
  
  /* On the first version of the chip, the temp registers are separate.
     On the second version,
     TEMP pin is shared with IN4, configured in PCI register 0x7A.
     The registers are the same as well.
     OVER and HYST are really MAX and MIN. */
  
  #define REV2MIN	0xb0
  #define SIS5595_REG_TEMP 	(( data->revision) >= REV2MIN) ? \
  					SIS5595_REG_IN(4) : 0x27
  #define SIS5595_REG_TEMP_OVER	(( data->revision) >= REV2MIN) ? \
  					SIS5595_REG_IN_MAX(4) : 0x39
  #define SIS5595_REG_TEMP_HYST	(( data->revision) >= REV2MIN) ? \
  					SIS5595_REG_IN_MIN(4) : 0x3a
  
  #define SIS5595_REG_CONFIG 0x40
  #define SIS5595_REG_ALARM1 0x41
  #define SIS5595_REG_ALARM2 0x42
  #define SIS5595_REG_FANDIV 0x47
  
  /* Conversions. Limit checking is only done on the TO_REG
     variants. */
  
  /* IN: mV, (0V to 4.08V)
     REG: 16mV/bit */
  static inline u8 IN_TO_REG(unsigned long val)
  {
  	unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
  	return (nval + 8) / 16;
  }
  #define IN_FROM_REG(val) ((val) *  16)
  
  static inline u8 FAN_TO_REG(long rpm, int div)
  {
  	if (rpm <= 0)
  		return 255;
  	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
  }
  
  static inline int FAN_FROM_REG(u8 val, int div)
  {
  	return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
  }
  
  /* TEMP: mC (-54.12C to +157.53C)
     REG: 0.83C/bit + 52.12, two's complement  */
  static inline int TEMP_FROM_REG(s8 val)
  {
  	return val * 830 + 52120;
  }
  static inline s8 TEMP_TO_REG(int val)
  {
  	int nval = SENSORS_LIMIT(val, -54120, 157530) ;
  	return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830;
  }
  
  /* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
     REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
  static inline u8 DIV_TO_REG(int val)
  {
  	return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
  }
  #define DIV_FROM_REG(val) (1 << (val))
ed6bafbf6   Jean Delvare   hwmon: Cleanup a ...
160
161
  /* For each registered chip, we need to keep some data in memory.
     The structure is dynamically allocated. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  struct sis5595_data {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
163
164
  	unsigned short addr;
  	const char *name;
1beeffe43   Tony Jones   hwmon: Convert fr...
165
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
166
  	struct mutex lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
168
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  	char valid;		/* !=0 if following fields are valid */
  	unsigned long last_updated;	/* In jiffies */
  	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
  	u8 revision;		/* Reg. value */
  
  	u8 in[5];		/* Register value */
  	u8 in_max[5];		/* Register value */
  	u8 in_min[5];		/* Register value */
  	u8 fan[2];		/* Register value */
  	u8 fan_min[2];		/* Register value */
  	s8 temp;		/* Register value */
  	s8 temp_over;		/* Register value */
  	s8 temp_hyst;		/* Register value */
  	u8 fan_div[2];		/* Register encoding, shifted right */
  	u16 alarms;		/* Register encoding, combined */
  };
  
  static struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
187
  static int sis5595_probe(struct platform_device *pdev);
d05461289   Jean Delvare   hwmon: Add missin...
188
  static int __devexit sis5595_remove(struct platform_device *pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189

17e7dc437   Jean Delvare   hwmon/sis5595: Co...
190
191
  static int sis5595_read_value(struct sis5595_data *data, u8 reg);
  static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  static struct sis5595_data *sis5595_update_device(struct device *dev);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
193
  static void sis5595_init_device(struct sis5595_data *data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

17e7dc437   Jean Delvare   hwmon/sis5595: Co...
195
  static struct platform_driver sis5595_driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
196
  	.driver = {
872188420   Jean Delvare   i2c-isa: Restore ...
197
  		.owner	= THIS_MODULE,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
198
199
  		.name	= "sis5595",
  	},
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
200
201
  	.probe		= sis5595_probe,
  	.remove		= __devexit_p(sis5595_remove),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
  };
  
  /* 4 Voltages */
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
205
206
  static ssize_t show_in(struct device *dev, struct device_attribute *da,
  		       char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
209
210
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->in[nr]));
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
214
215
  static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
218
219
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->in_min[nr]));
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
223
224
  static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
227
228
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->in_max[nr]));
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
232
233
  static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
  			  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
235
  	struct sis5595_data *data = dev_get_drvdata(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
236
237
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  	unsigned long val = simple_strtoul(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
239
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  	data->in_min[nr] = IN_TO_REG(val);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
241
  	sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
242
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  	return count;
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
245
246
  static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
  			  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
248
  	struct sis5595_data *data = dev_get_drvdata(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
249
250
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  	unsigned long val = simple_strtoul(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
252
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  	data->in_max[nr] = IN_TO_REG(val);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
254
  	sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
255
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
  	return count;
  }
  
  #define show_in_offset(offset)					\
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
260
261
262
263
264
265
  static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
  		show_in, NULL, offset);				\
  static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
  		show_in_min, set_in_min, offset);		\
  static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
  		show_in_max, set_in_max, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
272
273
  
  show_in_offset(0);
  show_in_offset(1);
  show_in_offset(2);
  show_in_offset(3);
  show_in_offset(4);
  
  /* Temperature */
a5099cfc2   Yani Ioannou   [PATCH] Driver Co...
274
  static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp));
  }
a5099cfc2   Yani Ioannou   [PATCH] Driver Co...
280
  static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_over));
  }
a5099cfc2   Yani Ioannou   [PATCH] Driver Co...
286
  static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
288
  	struct sis5595_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  	long val = simple_strtol(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
290
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	data->temp_over = TEMP_TO_REG(val);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
292
  	sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
293
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  	return count;
  }
a5099cfc2   Yani Ioannou   [PATCH] Driver Co...
296
  static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_hyst));
  }
a5099cfc2   Yani Ioannou   [PATCH] Driver Co...
302
  static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
304
  	struct sis5595_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  	long val = simple_strtol(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
306
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  	data->temp_hyst = TEMP_TO_REG(val);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
308
  	sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
309
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
316
317
318
319
  	return count;
  }
  
  static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
  static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
  		show_temp_over, set_temp_over);
  static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
  		show_temp_hyst, set_temp_hyst);
  
  /* 2 Fans */
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
320
321
  static ssize_t show_fan(struct device *dev, struct device_attribute *da,
  			char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
324
325
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan[nr],
  		DIV_FROM_REG(data->fan_div[nr])) );
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
330
331
  static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
  			    char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
334
335
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
  	return sprintf(buf,"%d
  ", FAN_FROM_REG(data->fan_min[nr],
  		DIV_FROM_REG(data->fan_div[nr])) );
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
340
341
  static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
  			   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
343
  	struct sis5595_data *data = dev_get_drvdata(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
344
345
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	unsigned long val = simple_strtoul(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
347
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
349
  	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
350
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  	return count;
  }
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
353
354
  static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
  			    char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
357
358
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
  	return sprintf(buf, "%d
  ", DIV_FROM_REG(data->fan_div[nr]) );
  }
  
  /* Note: we save and restore the fan minimum here, because its value is
     determined in part by the fan divisor.  This follows the principle of
d6e05edc5   Andreas Mohr   spelling fixes
365
     least surprise; the user doesn't expect the fan minimum to change just
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
     because the divisor changed. */
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
367
368
  static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
  			   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
370
  	struct sis5595_data *data = dev_get_drvdata(dev);
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
371
372
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	int nr = attr->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
  	unsigned long min;
  	unsigned long val = simple_strtoul(buf, NULL, 10);
  	int reg;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
376
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  	min = FAN_FROM_REG(data->fan_min[nr],
  			DIV_FROM_REG(data->fan_div[nr]));
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
379
  	reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
  
  	switch (val) {
  	case 1: data->fan_div[nr] = 0; break;
  	case 2: data->fan_div[nr] = 1; break;
  	case 4: data->fan_div[nr] = 2; break;
  	case 8: data->fan_div[nr] = 3; break;
  	default:
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
387
  		dev_err(dev, "fan_div value %ld not "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  			"supported. Choose one of 1, 2, 4 or 8!
  ", val);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
390
  		mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
397
398
399
400
401
  		return -EINVAL;
  	}
  	
  	switch (nr) {
  	case 0:
  		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
  		break;
  	case 1:
  		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
  		break;
  	}
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
402
  	sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  	data->fan_min[nr] =
  		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
405
  	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
406
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
  	return count;
  }
  
  #define show_fan_offset(offset)						\
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
411
412
413
414
415
416
  static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
  		show_fan, NULL, offset - 1);				\
  static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
  		show_fan_min, set_fan_min, offset - 1);			\
  static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
  		show_fan_div, set_fan_div, offset - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
  
  show_fan_offset(1);
  show_fan_offset(2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  /* Alarms */
a5099cfc2   Yani Ioannou   [PATCH] Driver Co...
421
  static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
427
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
  	return sprintf(buf, "%d
  ", data->alarms);
  }
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
428

5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
  			  char *buf)
  {
  	struct sis5595_data *data = sis5595_update_device(dev);
  	int nr = to_sensor_dev_attr(da)->index;
  	return sprintf(buf, "%u
  ", (data->alarms >> nr) & 1);
  }
  static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
  static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
  static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
  static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
  static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
  static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
  static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
  static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
445
446
447
448
449
450
451
452
  static ssize_t show_name(struct device *dev, struct device_attribute *attr,
  			 char *buf)
  {
  	struct sis5595_data *data = dev_get_drvdata(dev);
  	return sprintf(buf, "%s
  ", data->name);
  }
  static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
453
  static struct attribute *sis5595_attributes[] = {
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
454
455
456
  	&sensor_dev_attr_in0_input.dev_attr.attr,
  	&sensor_dev_attr_in0_min.dev_attr.attr,
  	&sensor_dev_attr_in0_max.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
457
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
458
459
460
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in1_min.dev_attr.attr,
  	&sensor_dev_attr_in1_max.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
461
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
462
463
464
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  	&sensor_dev_attr_in2_min.dev_attr.attr,
  	&sensor_dev_attr_in2_max.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
465
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
466
467
468
  	&sensor_dev_attr_in3_input.dev_attr.attr,
  	&sensor_dev_attr_in3_min.dev_attr.attr,
  	&sensor_dev_attr_in3_max.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
469
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
470
471
472
473
  
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
  	&sensor_dev_attr_fan1_div.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
474
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
475
476
477
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_min.dev_attr.attr,
  	&sensor_dev_attr_fan2_div.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
478
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
479
480
  
  	&dev_attr_alarms.attr,
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
481
  	&dev_attr_name.attr,
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
482
483
484
485
486
487
  	NULL
  };
  
  static const struct attribute_group sis5595_group = {
  	.attrs = sis5595_attributes,
  };
76e63860d   Ivo Manca   hwmon: (sis5595) ...
488
  static struct attribute *sis5595_attributes_in4[] = {
1f5f48dde   Jean Delvare   hwmon/sis5595: Us...
489
490
491
  	&sensor_dev_attr_in4_input.dev_attr.attr,
  	&sensor_dev_attr_in4_min.dev_attr.attr,
  	&sensor_dev_attr_in4_max.dev_attr.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
492
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
76e63860d   Ivo Manca   hwmon: (sis5595) ...
493
494
495
496
497
498
  	NULL
  };
  
  static const struct attribute_group sis5595_group_in4 = {
  	.attrs = sis5595_attributes_in4,
  };
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
499

76e63860d   Ivo Manca   hwmon: (sis5595) ...
500
  static struct attribute *sis5595_attributes_temp1[] = {
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
501
502
503
  	&dev_attr_temp1_input.attr,
  	&dev_attr_temp1_max.attr,
  	&dev_attr_temp1_max_hyst.attr,
5c726b3ba   Ivo Manca   hwmon: (sis5595) ...
504
  	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
505
506
  	NULL
  };
76e63860d   Ivo Manca   hwmon: (sis5595) ...
507
508
  static const struct attribute_group sis5595_group_temp1 = {
  	.attrs = sis5595_attributes_temp1,
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
509
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
   
  /* This is called when the module is loaded */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
512
  static int __devinit sis5595_probe(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
  {
  	int err = 0;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  	struct sis5595_data *data;
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
517
  	struct resource *res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  	char val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  	/* Reserve the ISA region */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
521
522
  	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
  	if (!request_region(res->start, SIS5595_EXTENT,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
523
  			    sis5595_driver.driver.name)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
  		err = -EBUSY;
  		goto exit;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527

ba9c2e8d1   Deepak Saxena   [PATCH] hwmon: kz...
528
  	if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
  		err = -ENOMEM;
  		goto exit_release;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
533
  	mutex_init(&data->lock);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
534
535
536
537
  	mutex_init(&data->update_lock);
  	data->addr = res->start;
  	data->name = "sis5595";
  	platform_set_drvdata(pdev, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  
  	/* Check revision and pin registers to determine whether 4 or 5 voltages */
7b6d1f044   Auke Kok   hwmon: (sis5595) ...
540
  	data->revision = s_bridge->revision;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
545
546
547
548
549
  	/* 4 voltages, 1 temp */
  	data->maxins = 3;
  	if (data->revision >= REV2MIN) {
  		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
  		if (!(val & 0x80))
  			/* 5 voltages, no temps */
  			data->maxins = 4;
  	}
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	/* Initialize the SIS5595 chip */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
551
  	sis5595_init_device(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
  
  	/* A few vars need to be filled upon startup */
  	for (i = 0; i < 2; i++) {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
555
  		data->fan_min[i] = sis5595_read_value(data,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
559
  					SIS5595_REG_FAN_MIN(i));
  	}
  
  	/* Register sysfs hooks */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
560
561
  	if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
  		goto exit_free;
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
562
  	if (data->maxins == 4) {
76e63860d   Ivo Manca   hwmon: (sis5595) ...
563
564
  		if ((err = sysfs_create_group(&pdev->dev.kobj,
  					      &sis5595_group_in4)))
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
565
566
  			goto exit_remove_files;
  	} else {
76e63860d   Ivo Manca   hwmon: (sis5595) ...
567
568
  		if ((err = sysfs_create_group(&pdev->dev.kobj,
  					      &sis5595_group_temp1)))
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
569
570
  			goto exit_remove_files;
  	}
1beeffe43   Tony Jones   hwmon: Convert fr...
571
572
573
  	data->hwmon_dev = hwmon_device_register(&pdev->dev);
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
a5ebe668a   Jean Delvare   hwmon: Fix unchec...
574
  		goto exit_remove_files;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
575
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  	return 0;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
577

a5ebe668a   Jean Delvare   hwmon: Fix unchec...
578
  exit_remove_files:
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
579
  	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
76e63860d   Ivo Manca   hwmon: (sis5595) ...
580
581
  	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
  	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
  exit_free:
  	kfree(data);
  exit_release:
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
585
  	release_region(res->start, SIS5595_EXTENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
  exit:
  	return err;
  }
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
589
  static int __devexit sis5595_remove(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
591
  	struct sis5595_data *data = platform_get_drvdata(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592

1beeffe43   Tony Jones   hwmon: Convert fr...
593
  	hwmon_device_unregister(data->hwmon_dev);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
594
  	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
76e63860d   Ivo Manca   hwmon: (sis5595) ...
595
596
  	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
  	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597

17e7dc437   Jean Delvare   hwmon/sis5595: Co...
598
599
  	release_region(data->addr, SIS5595_EXTENT);
  	platform_set_drvdata(pdev, NULL);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
600
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
  
  	return 0;
  }
  
  
  /* ISA access must be locked explicitly. */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
607
  static int sis5595_read_value(struct sis5595_data *data, u8 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
  {
  	int res;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
610
  	mutex_lock(&data->lock);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
611
612
  	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
  	res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
613
  	mutex_unlock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
  	return res;
  }
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
616
  static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  {
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
618
  	mutex_lock(&data->lock);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
619
620
  	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
  	outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
621
  	mutex_unlock(&data->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
  }
  
  /* Called when we have found a new SIS5595. */
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
625
  static void __devinit sis5595_init_device(struct sis5595_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
627
  	u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  	if (!(config & 0x01))
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
629
  		sis5595_write_value(data, SIS5595_REG_CONFIG,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
  				(config & 0xf7) | 0x01);
  }
  
  static struct sis5595_data *sis5595_update_device(struct device *dev)
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
635
  	struct sis5595_data *data = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	int i;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
637
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
  
  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
  	    || !data->valid) {
  
  		for (i = 0; i <= data->maxins; i++) {
  			data->in[i] =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
644
  			    sis5595_read_value(data, SIS5595_REG_IN(i));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  			data->in_min[i] =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
646
  			    sis5595_read_value(data,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  					       SIS5595_REG_IN_MIN(i));
  			data->in_max[i] =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
649
  			    sis5595_read_value(data,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
  					       SIS5595_REG_IN_MAX(i));
  		}
  		for (i = 0; i < 2; i++) {
  			data->fan[i] =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
654
  			    sis5595_read_value(data, SIS5595_REG_FAN(i));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  			data->fan_min[i] =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
656
  			    sis5595_read_value(data,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
  					       SIS5595_REG_FAN_MIN(i));
  		}
  		if (data->maxins == 3) {
  			data->temp =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
661
  			    sis5595_read_value(data, SIS5595_REG_TEMP);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  			data->temp_over =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
663
  			    sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  			data->temp_hyst =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
665
  			    sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  		}
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
667
  		i = sis5595_read_value(data, SIS5595_REG_FANDIV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
  		data->fan_div[0] = (i >> 4) & 0x03;
  		data->fan_div[1] = i >> 6;
  		data->alarms =
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
671
672
  		    sis5595_read_value(data, SIS5595_REG_ALARM1) |
  		    (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
676
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
  
  	return data;
  }
3dd3a1563   Márton Németh   hwmon: Make PCI d...
680
  static const struct pci_device_id sis5595_pci_ids[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
  	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
  	{ 0, }
  };
  
  MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);
  
  static int blacklist[] __devinitdata = {
  	PCI_DEVICE_ID_SI_540,
  	PCI_DEVICE_ID_SI_550,
  	PCI_DEVICE_ID_SI_630,
  	PCI_DEVICE_ID_SI_645,
  	PCI_DEVICE_ID_SI_730,
  	PCI_DEVICE_ID_SI_735,
  	PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
  				  that ID shows up in other chips so we
  				  use the 5511 ID for recognition */
  	PCI_DEVICE_ID_SI_5597,
  	PCI_DEVICE_ID_SI_5598,
  	0 };
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
700
701
702
703
704
705
706
707
708
  static int __devinit sis5595_device_add(unsigned short address)
  {
  	struct resource res = {
  		.start	= address,
  		.end	= address + SIS5595_EXTENT - 1,
  		.name	= "sis5595",
  		.flags	= IORESOURCE_IO,
  	};
  	int err;
b9acb64a3   Jean Delvare   hwmon: Check for ...
709
710
711
  	err = acpi_check_resource_conflict(&res);
  	if (err)
  		goto exit;
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
712
713
714
  	pdev = platform_device_alloc("sis5595", address);
  	if (!pdev) {
  		err = -ENOMEM;
4b2515dbb   Joe Perches   hwmon: (sis5595) ...
715
716
  		pr_err("Device allocation failed
  ");
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
717
718
719
720
721
  		goto exit;
  	}
  
  	err = platform_device_add_resources(pdev, &res, 1);
  	if (err) {
4b2515dbb   Joe Perches   hwmon: (sis5595) ...
722
723
  		pr_err("Device resource addition failed (%d)
  ", err);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
724
725
726
727
728
  		goto exit_device_put;
  	}
  
  	err = platform_device_add(pdev);
  	if (err) {
4b2515dbb   Joe Perches   hwmon: (sis5595) ...
729
730
  		pr_err("Device addition failed (%d)
  ", err);
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
731
732
733
734
735
736
737
738
739
740
  		goto exit_device_put;
  	}
  
  	return 0;
  
  exit_device_put:
  	platform_device_put(pdev);
  exit:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  static int __devinit sis5595_pci_probe(struct pci_dev *dev,
  				       const struct pci_device_id *id)
  {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
744
745
  	u16 address;
  	u8 enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	int *i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  
  	for (i = blacklist; *i != 0; i++) {
5460a9d0f   Mark M. Hoffman   hwmon: (sis5595) ...
749
750
751
752
753
  		struct pci_dev *d;
  		if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) {
  			dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x
  ", *i);
  			pci_dev_put(d);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
  			return -ENODEV;
  		}
  	}
  	
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
758
759
760
761
762
763
  	force_addr &= ~(SIS5595_EXTENT - 1);
  	if (force_addr) {
  		dev_warn(&dev->dev, "Forcing ISA address 0x%x
  ", force_addr);
  		pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  	if (PCIBIOS_SUCCESSFUL !=
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
765
766
767
  	    pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
  		dev_err(&dev->dev, "Failed to read ISA address
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  		return -ENODEV;
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
769
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
771
772
  	address &= ~(SIS5595_EXTENT - 1);
  	if (!address) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
  		dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr
  ");
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  	}
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
777
778
779
780
781
782
  	if (force_addr && address != force_addr) {
  		/* doesn't work for some chips? */
  		dev_err(&dev->dev, "Failed to force ISA address
  ");
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783

17e7dc437   Jean Delvare   hwmon/sis5595: Co...
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  	if (PCIBIOS_SUCCESSFUL !=
  	    pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
  		dev_err(&dev->dev, "Failed to read enable register
  ");
  		return -ENODEV;
  	}
  	if (!(enable & 0x80)) {
  		if ((PCIBIOS_SUCCESSFUL !=
  		     pci_write_config_byte(dev, SIS5595_ENABLE_REG,
  					   enable | 0x80))
  		 || (PCIBIOS_SUCCESSFUL !=
  		     pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
  		 || (!(enable & 0x80))) {
  			/* doesn't work for some chips! */
  			dev_err(&dev->dev, "Failed to enable HWM device
  ");
  			return -ENODEV;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  	}
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
803
804
805
806
807
808
809
810
811
812
  	if (platform_driver_register(&sis5595_driver)) {
  		dev_dbg(&dev->dev, "Failed to register sis5595 driver
  ");
  		goto exit;
  	}
  
  	s_bridge = pci_dev_get(dev);
  	/* Sets global pdev as a side effect */
  	if (sis5595_device_add(address))
  		goto exit_unregister;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
817
  	/* Always return failure here.  This is to allow other drivers to bind
  	 * to this pci device.  We don't really want to have control over the
  	 * pci device, we only wanted to read as few register values from it.
  	 */
  	return -ENODEV;
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
818
819
820
821
822
823
  
  exit_unregister:
  	pci_dev_put(dev);
  	platform_driver_unregister(&sis5595_driver);
  exit:
  	return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
  }
  
  static struct pci_driver sis5595_pci_driver = {
  	.name            = "sis5595",
  	.id_table        = sis5595_pci_ids,
  	.probe           = sis5595_pci_probe,
  };
  
  static int __init sm_sis5595_init(void)
  {
  	return pci_register_driver(&sis5595_pci_driver);
  }
  
  static void __exit sm_sis5595_exit(void)
  {
  	pci_unregister_driver(&sis5595_pci_driver);
  	if (s_bridge != NULL) {
17e7dc437   Jean Delvare   hwmon/sis5595: Co...
841
842
  		platform_device_unregister(pdev);
  		platform_driver_unregister(&sis5595_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
849
850
851
852
853
  		pci_dev_put(s_bridge);
  		s_bridge = NULL;
  	}
  }
  
  MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
  MODULE_DESCRIPTION("SiS 5595 Sensor device");
  MODULE_LICENSE("GPL");
  
  module_init(sm_sis5595_init);
  module_exit(sm_sis5595_exit);