hwmon: (smsc47m1) Add individual alarm files
[linux-2.6-block.git] / drivers / hwmon / via686a.c
CommitLineData
1da177e4
LT
1/*
2 via686a.c - Part of lm_sensors, Linux kernel modules
6328c0e1 3 for hardware monitoring
be8992c2 4
1da177e4 5 Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
96de0e25 6 Kyösti Mälkki <kmalkki@cc.hut.fi>,
1da177e4
LT
7 Mark Studebaker <mdsxyz123@yahoo.com>,
8 and Bob Dougherty <bobd@stanford.edu>
be8992c2 9 (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
1da177e4
LT
10 <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27/*
28 Supports the Via VT82C686A, VT82C686B south bridges.
29 Reports all as a 686A.
30 Warning - only supports a single device.
31*/
32
1da177e4
LT
33#include <linux/module.h>
34#include <linux/slab.h>
35#include <linux/pci.h>
1da177e4 36#include <linux/jiffies.h>
2ec342e6 37#include <linux/platform_device.h>
943b0830 38#include <linux/hwmon.h>
1e71a5a2 39#include <linux/hwmon-sysfs.h>
943b0830 40#include <linux/err.h>
1da177e4 41#include <linux/init.h>
9a61bf63 42#include <linux/mutex.h>
a5ebe668 43#include <linux/sysfs.h>
1da177e4
LT
44#include <asm/io.h>
45
46
47/* If force_addr is set to anything different from 0, we forcibly enable
48 the device at the given address. */
02002963 49static unsigned short force_addr;
1da177e4
LT
50module_param(force_addr, ushort, 0);
51MODULE_PARM_DESC(force_addr,
52 "Initialize the base address of the sensors");
53
2ec342e6 54static struct platform_device *pdev;
1da177e4
LT
55
56/*
57 The Via 686a southbridge has a LM78-like chip integrated on the same IC.
58 This driver is a customized copy of lm78.c
59*/
60
61/* Many VIA686A constants specified below */
62
63/* Length of ISA address segment */
be8992c2
JD
64#define VIA686A_EXTENT 0x80
65#define VIA686A_BASE_REG 0x70
66#define VIA686A_ENABLE_REG 0x74
1da177e4
LT
67
68/* The VIA686A registers */
69/* ins numbered 0-4 */
be8992c2
JD
70#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
71#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
72#define VIA686A_REG_IN(nr) (0x22 + (nr))
1da177e4
LT
73
74/* fans numbered 1-2 */
be8992c2
JD
75#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
76#define VIA686A_REG_FAN(nr) (0x28 + (nr))
1da177e4 77
1da177e4 78/* temps numbered 1-3 */
563db2fe
JD
79static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f };
80static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d };
81static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e };
be8992c2
JD
82/* bits 7-6 */
83#define VIA686A_REG_TEMP_LOW1 0x4b
84/* 2 = bits 5-4, 3 = bits 7-6 */
85#define VIA686A_REG_TEMP_LOW23 0x49
86
87#define VIA686A_REG_ALARM1 0x41
88#define VIA686A_REG_ALARM2 0x42
89#define VIA686A_REG_FANDIV 0x47
90#define VIA686A_REG_CONFIG 0x40
91/* The following register sets temp interrupt mode (bits 1-0 for temp1,
1da177e4
LT
92 3-2 for temp2, 5-4 for temp3). Modes are:
93 00 interrupt stays as long as value is out-of-range
94 01 interrupt is cleared once register is read (default)
95 10 comparator mode- like 00, but ignores hysteresis
96 11 same as 00 */
be8992c2 97#define VIA686A_REG_TEMP_MODE 0x4b
1da177e4 98/* We'll just assume that you want to set all 3 simultaneously: */
be8992c2
JD
99#define VIA686A_TEMP_MODE_MASK 0x3F
100#define VIA686A_TEMP_MODE_CONTINUOUS 0x00
1da177e4
LT
101
102/* Conversions. Limit checking is only done on the TO_REG
be8992c2 103 variants.
1da177e4
LT
104
105********* VOLTAGE CONVERSIONS (Bob Dougherty) ********
106 From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
107 voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp
108 voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V
109 voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V
110 voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V
111 voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V
112 in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
113 That is:
114 volts = (25*regVal+133)*factor
115 regVal = (volts/factor-133)/25
be8992c2 116 (These conversions were contributed by Jonathan Teh Soon Yew
1da177e4
LT
117 <j.teh@iname.com>) */
118static inline u8 IN_TO_REG(long val, int inNum)
119{
120 /* To avoid floating point, we multiply constants by 10 (100 for +12V).
121 Rounding is done (120500 is actually 133000 - 12500).
122 Remember that val is expressed in 0.001V/bit, which is why we divide
123 by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
124 for the constants. */
125 if (inNum <= 1)
126 return (u8)
127 SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255);
128 else if (inNum == 2)
129 return (u8)
130 SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255);
131 else if (inNum == 3)
132 return (u8)
133 SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255);
134 else
135 return (u8)
136 SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255);
137}
138
139static inline long IN_FROM_REG(u8 val, int inNum)
140{
141 /* To avoid floating point, we multiply constants by 10 (100 for +12V).
142 We also multiply them by 1000 because we want 0.001V/bit for the
143 output value. Rounding is done. */
144 if (inNum <= 1)
145 return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
146 else if (inNum == 2)
147 return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
148 else if (inNum == 3)
149 return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
150 else
151 return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
152}
153
154/********* FAN RPM CONVERSIONS ********/
155/* Higher register values = slower fans (the fan's strobe gates a counter).
156 But this chip saturates back at 0, not at 255 like all the other chips.
157 So, 0 means 0 RPM */
158static inline u8 FAN_TO_REG(long rpm, int div)
159{
160 if (rpm == 0)
161 return 0;
162 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
163 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
164}
165
166#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div)))
167
168/******** TEMP CONVERSIONS (Bob Dougherty) *********/
169/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
170 if(temp<169)
6328c0e1 171 return double(temp)*0.427-32.08;
1da177e4 172 else if(temp>=169 && temp<=202)
6328c0e1 173 return double(temp)*0.582-58.16;
1da177e4 174 else
6328c0e1 175 return double(temp)*0.924-127.33;
1da177e4 176
be8992c2
JD
177 A fifth-order polynomial fits the unofficial data (provided by Alex van
178 Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
179 numbers on my machine (ie. they agree with what my BIOS tells me).
1da177e4 180 Here's the fifth-order fit to the 8-bit data:
be8992c2 181 temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
6328c0e1 182 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
1da177e4 183
be8992c2 184 (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
1da177e4
LT
185 finding my typos in this formula!)
186
be8992c2
JD
187 Alas, none of the elegant function-fit solutions will work because we
188 aren't allowed to use floating point in the kernel and doing it with
189 integers doesn't provide enough precision. So we'll do boring old
190 look-up table stuff. The unofficial data (see below) have effectively
191 7-bit resolution (they are rounded to the nearest degree). I'm assuming
192 that the transfer function of the device is monotonic and smooth, so a
193 smooth function fit to the data will allow us to get better precision.
1da177e4 194 I used the 5th-order poly fit described above and solved for
be8992c2
JD
195 VIA register values 0-255. I *10 before rounding, so we get tenth-degree
196 precision. (I could have done all 1024 values for our 10-bit readings,
197 but the function is very linear in the useful range (0-80 deg C), so
198 we'll just use linear interpolation for 10-bit readings.) So, tempLUT
1da177e4 199 is the temp at via register values 0-255: */
088341bd 200static const s16 tempLUT[] =
be8992c2
JD
201{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
202 -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
203 -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
204 -255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
205 -173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
206 -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
207 -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
208 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
209 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
210 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
211 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
212 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
213 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
214 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
215 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
216 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
217 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
218 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
219 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
220 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
221 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
222 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
1da177e4
LT
223};
224
be8992c2 225/* the original LUT values from Alex van Kaam <darkside@chello.nl>
1da177e4
LT
226 (for via register values 12-240):
227{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
228-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
229-15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
230-3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12,
23112,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22,
23222,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33,
23333,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,
23445,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60,
23561,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84,
23685,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
237
238
239 Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed
be8992c2
JD
240 an extra term for a good fit to these inverse data!) and then
241 solving for each temp value from -50 to 110 (the useable range for
242 this chip). Here's the fit:
243 viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
1da177e4
LT
244 - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
245 Note that n=161: */
246static const u8 viaLUT[] =
be8992c2
JD
247{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
248 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
249 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
250 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
251 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
252 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
253 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
254 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
255 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
256 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
257 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
258 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
259 239, 240
1da177e4
LT
260};
261
262/* Converting temps to (8-bit) hyst and over registers
263 No interpolation here.
264 The +50 is because the temps start at -50 */
265static inline u8 TEMP_TO_REG(long val)
266{
be8992c2 267 return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
1da177e4
LT
268 (val < 0 ? val - 500 : val + 500) / 1000 + 50];
269}
270
271/* for 8-bit temperature hyst and over registers */
088341bd 272#define TEMP_FROM_REG(val) ((long)tempLUT[val] * 100)
1da177e4
LT
273
274/* for 10-bit temperature readings */
275static inline long TEMP_FROM_REG10(u16 val)
276{
277 u16 eightBits = val >> 2;
278 u16 twoBits = val & 3;
279
280 /* no interpolation for these */
281 if (twoBits == 0 || eightBits == 255)
282 return TEMP_FROM_REG(eightBits);
283
284 /* do some linear interpolation */
285 return (tempLUT[eightBits] * (4 - twoBits) +
be8992c2 286 tempLUT[eightBits + 1] * twoBits) * 25;
1da177e4
LT
287}
288
1da177e4
LT
289#define DIV_FROM_REG(val) (1 << (val))
290#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
291
ed6bafbf
JD
292/* For each registered chip, we need to keep some data in memory.
293 The structure is dynamically allocated. */
1da177e4 294struct via686a_data {
2ec342e6
JD
295 unsigned short addr;
296 const char *name;
1beeffe4 297 struct device *hwmon_dev;
9a61bf63 298 struct mutex update_lock;
1da177e4
LT
299 char valid; /* !=0 if following fields are valid */
300 unsigned long last_updated; /* In jiffies */
301
302 u8 in[5]; /* Register value */
303 u8 in_max[5]; /* Register value */
304 u8 in_min[5]; /* Register value */
305 u8 fan[2]; /* Register value */
306 u8 fan_min[2]; /* Register value */
307 u16 temp[3]; /* Register value 10 bit */
308 u8 temp_over[3]; /* Register value */
309 u8 temp_hyst[3]; /* Register value */
310 u8 fan_div[2]; /* Register encoding, shifted right */
311 u16 alarms; /* Register encoding, combined */
312};
313
314static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
315
2ec342e6 316static int via686a_probe(struct platform_device *pdev);
d0546128 317static int __devexit via686a_remove(struct platform_device *pdev);
1da177e4 318
2ec342e6 319static inline int via686a_read_value(struct via686a_data *data, u8 reg)
1da177e4 320{
2ec342e6 321 return inb_p(data->addr + reg);
1da177e4
LT
322}
323
2ec342e6 324static inline void via686a_write_value(struct via686a_data *data, u8 reg,
1da177e4
LT
325 u8 value)
326{
2ec342e6 327 outb_p(value, data->addr + reg);
1da177e4
LT
328}
329
330static struct via686a_data *via686a_update_device(struct device *dev);
2ec342e6 331static void via686a_init_device(struct via686a_data *data);
1da177e4
LT
332
333/* following are the sysfs callback functions */
334
335/* 7 voltage sensors */
1e71a5a2
JD
336static ssize_t show_in(struct device *dev, struct device_attribute *da,
337 char *buf) {
1da177e4 338 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
339 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
340 int nr = attr->index;
1da177e4
LT
341 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
342}
343
1e71a5a2
JD
344static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
345 char *buf) {
1da177e4 346 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
347 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
348 int nr = attr->index;
1da177e4
LT
349 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
350}
351
1e71a5a2
JD
352static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
353 char *buf) {
1da177e4 354 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
355 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
356 int nr = attr->index;
1da177e4
LT
357 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
358}
359
1e71a5a2
JD
360static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
361 const char *buf, size_t count) {
2ec342e6 362 struct via686a_data *data = dev_get_drvdata(dev);
1e71a5a2
JD
363 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
364 int nr = attr->index;
1da177e4
LT
365 unsigned long val = simple_strtoul(buf, NULL, 10);
366
9a61bf63 367 mutex_lock(&data->update_lock);
be8992c2 368 data->in_min[nr] = IN_TO_REG(val, nr);
2ec342e6 369 via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
1da177e4 370 data->in_min[nr]);
9a61bf63 371 mutex_unlock(&data->update_lock);
1da177e4
LT
372 return count;
373}
1e71a5a2
JD
374static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
375 const char *buf, size_t count) {
2ec342e6 376 struct via686a_data *data = dev_get_drvdata(dev);
1e71a5a2
JD
377 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
378 int nr = attr->index;
1da177e4
LT
379 unsigned long val = simple_strtoul(buf, NULL, 10);
380
9a61bf63 381 mutex_lock(&data->update_lock);
be8992c2 382 data->in_max[nr] = IN_TO_REG(val, nr);
2ec342e6 383 via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
1da177e4 384 data->in_max[nr]);
9a61bf63 385 mutex_unlock(&data->update_lock);
1da177e4
LT
386 return count;
387}
388#define show_in_offset(offset) \
1e71a5a2
JD
389static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
390 show_in, NULL, offset); \
391static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
392 show_in_min, set_in_min, offset); \
393static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
394 show_in_max, set_in_max, offset);
1da177e4
LT
395
396show_in_offset(0);
397show_in_offset(1);
398show_in_offset(2);
399show_in_offset(3);
400show_in_offset(4);
401
402/* 3 temperatures */
1e71a5a2
JD
403static ssize_t show_temp(struct device *dev, struct device_attribute *da,
404 char *buf) {
1da177e4 405 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
406 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
407 int nr = attr->index;
1da177e4
LT
408 return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
409}
1e71a5a2
JD
410static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
411 char *buf) {
1da177e4 412 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
413 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
414 int nr = attr->index;
1da177e4
LT
415 return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
416}
1e71a5a2
JD
417static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
418 char *buf) {
1da177e4 419 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
420 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
421 int nr = attr->index;
1da177e4
LT
422 return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
423}
1e71a5a2
JD
424static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
425 const char *buf, size_t count) {
2ec342e6 426 struct via686a_data *data = dev_get_drvdata(dev);
1e71a5a2
JD
427 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
428 int nr = attr->index;
1da177e4
LT
429 int val = simple_strtol(buf, NULL, 10);
430
9a61bf63 431 mutex_lock(&data->update_lock);
1da177e4 432 data->temp_over[nr] = TEMP_TO_REG(val);
2ec342e6 433 via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
563db2fe 434 data->temp_over[nr]);
9a61bf63 435 mutex_unlock(&data->update_lock);
1da177e4
LT
436 return count;
437}
1e71a5a2
JD
438static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
439 const char *buf, size_t count) {
2ec342e6 440 struct via686a_data *data = dev_get_drvdata(dev);
1e71a5a2
JD
441 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
442 int nr = attr->index;
1da177e4
LT
443 int val = simple_strtol(buf, NULL, 10);
444
9a61bf63 445 mutex_lock(&data->update_lock);
1da177e4 446 data->temp_hyst[nr] = TEMP_TO_REG(val);
2ec342e6 447 via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
563db2fe 448 data->temp_hyst[nr]);
9a61bf63 449 mutex_unlock(&data->update_lock);
1da177e4
LT
450 return count;
451}
452#define show_temp_offset(offset) \
1e71a5a2
JD
453static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
454 show_temp, NULL, offset - 1); \
455static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
456 show_temp_over, set_temp_over, offset - 1); \
457static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
458 show_temp_hyst, set_temp_hyst, offset - 1);
1da177e4
LT
459
460show_temp_offset(1);
461show_temp_offset(2);
462show_temp_offset(3);
463
464/* 2 Fans */
1e71a5a2
JD
465static ssize_t show_fan(struct device *dev, struct device_attribute *da,
466 char *buf) {
1da177e4 467 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
468 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
469 int nr = attr->index;
be8992c2 470 return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
1da177e4
LT
471 DIV_FROM_REG(data->fan_div[nr])) );
472}
1e71a5a2
JD
473static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
474 char *buf) {
1da177e4 475 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
476 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
477 int nr = attr->index;
be8992c2 478 return sprintf(buf, "%d\n",
1da177e4
LT
479 FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
480}
1e71a5a2
JD
481static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
482 char *buf) {
1da177e4 483 struct via686a_data *data = via686a_update_device(dev);
1e71a5a2
JD
484 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
485 int nr = attr->index;
be8992c2 486 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
1da177e4 487}
1e71a5a2
JD
488static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
489 const char *buf, size_t count) {
2ec342e6 490 struct via686a_data *data = dev_get_drvdata(dev);
1e71a5a2
JD
491 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
492 int nr = attr->index;
1da177e4
LT
493 int val = simple_strtol(buf, NULL, 10);
494
9a61bf63 495 mutex_lock(&data->update_lock);
1da177e4 496 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
2ec342e6 497 via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
9a61bf63 498 mutex_unlock(&data->update_lock);
1da177e4
LT
499 return count;
500}
1e71a5a2
JD
501static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
502 const char *buf, size_t count) {
2ec342e6 503 struct via686a_data *data = dev_get_drvdata(dev);
1e71a5a2
JD
504 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
505 int nr = attr->index;
1da177e4
LT
506 int val = simple_strtol(buf, NULL, 10);
507 int old;
508
9a61bf63 509 mutex_lock(&data->update_lock);
2ec342e6 510 old = via686a_read_value(data, VIA686A_REG_FANDIV);
1da177e4
LT
511 data->fan_div[nr] = DIV_TO_REG(val);
512 old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
2ec342e6 513 via686a_write_value(data, VIA686A_REG_FANDIV, old);
9a61bf63 514 mutex_unlock(&data->update_lock);
1da177e4
LT
515 return count;
516}
517
518#define show_fan_offset(offset) \
1e71a5a2
JD
519static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
520 show_fan, NULL, offset - 1); \
521static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
522 show_fan_min, set_fan_min, offset - 1); \
523static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
524 show_fan_div, set_fan_div, offset - 1);
1da177e4
LT
525
526show_fan_offset(1);
527show_fan_offset(2);
528
529/* Alarms */
a5099cfc 530static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) {
1da177e4 531 struct via686a_data *data = via686a_update_device(dev);
68188ba7 532 return sprintf(buf, "%u\n", data->alarms);
1da177e4 533}
1d66c64c 534static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
1da177e4 535
2ec342e6
JD
536static ssize_t show_name(struct device *dev, struct device_attribute
537 *devattr, char *buf)
538{
539 struct via686a_data *data = dev_get_drvdata(dev);
540 return sprintf(buf, "%s\n", data->name);
541}
542static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
543
a5ebe668 544static struct attribute *via686a_attributes[] = {
1e71a5a2
JD
545 &sensor_dev_attr_in0_input.dev_attr.attr,
546 &sensor_dev_attr_in1_input.dev_attr.attr,
547 &sensor_dev_attr_in2_input.dev_attr.attr,
548 &sensor_dev_attr_in3_input.dev_attr.attr,
549 &sensor_dev_attr_in4_input.dev_attr.attr,
550 &sensor_dev_attr_in0_min.dev_attr.attr,
551 &sensor_dev_attr_in1_min.dev_attr.attr,
552 &sensor_dev_attr_in2_min.dev_attr.attr,
553 &sensor_dev_attr_in3_min.dev_attr.attr,
554 &sensor_dev_attr_in4_min.dev_attr.attr,
555 &sensor_dev_attr_in0_max.dev_attr.attr,
556 &sensor_dev_attr_in1_max.dev_attr.attr,
557 &sensor_dev_attr_in2_max.dev_attr.attr,
558 &sensor_dev_attr_in3_max.dev_attr.attr,
559 &sensor_dev_attr_in4_max.dev_attr.attr,
560
561 &sensor_dev_attr_temp1_input.dev_attr.attr,
562 &sensor_dev_attr_temp2_input.dev_attr.attr,
563 &sensor_dev_attr_temp3_input.dev_attr.attr,
564 &sensor_dev_attr_temp1_max.dev_attr.attr,
565 &sensor_dev_attr_temp2_max.dev_attr.attr,
566 &sensor_dev_attr_temp3_max.dev_attr.attr,
567 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
568 &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
569 &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
570
571 &sensor_dev_attr_fan1_input.dev_attr.attr,
572 &sensor_dev_attr_fan2_input.dev_attr.attr,
573 &sensor_dev_attr_fan1_min.dev_attr.attr,
574 &sensor_dev_attr_fan2_min.dev_attr.attr,
575 &sensor_dev_attr_fan1_div.dev_attr.attr,
576 &sensor_dev_attr_fan2_div.dev_attr.attr,
a5ebe668
JD
577
578 &dev_attr_alarms.attr,
2ec342e6 579 &dev_attr_name.attr,
a5ebe668
JD
580 NULL
581};
582
583static const struct attribute_group via686a_group = {
584 .attrs = via686a_attributes,
585};
586
2ec342e6 587static struct platform_driver via686a_driver = {
cdaf7934 588 .driver = {
87218842 589 .owner = THIS_MODULE,
cdaf7934
LR
590 .name = "via686a",
591 },
2ec342e6
JD
592 .probe = via686a_probe,
593 .remove = __devexit_p(via686a_remove),
1da177e4
LT
594};
595
596
597/* This is called when the module is loaded */
2ec342e6 598static int __devinit via686a_probe(struct platform_device *pdev)
1da177e4 599{
1da177e4 600 struct via686a_data *data;
2ec342e6
JD
601 struct resource *res;
602 int err;
1da177e4
LT
603
604 /* Reserve the ISA region */
2ec342e6
JD
605 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
606 if (!request_region(res->start, VIA686A_EXTENT,
cdaf7934 607 via686a_driver.driver.name)) {
2ec342e6
JD
608 dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
609 (unsigned long)res->start, (unsigned long)res->end);
1da177e4
LT
610 return -ENODEV;
611 }
612
ba9c2e8d 613 if (!(data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
1da177e4 614 err = -ENOMEM;
943b0830 615 goto exit_release;
1da177e4 616 }
1da177e4 617
2ec342e6
JD
618 platform_set_drvdata(pdev, data);
619 data->addr = res->start;
620 data->name = "via686a";
9a61bf63 621 mutex_init(&data->update_lock);
be8992c2 622
1da177e4 623 /* Initialize the VIA686A chip */
2ec342e6 624 via686a_init_device(data);
1da177e4
LT
625
626 /* Register sysfs hooks */
2ec342e6
JD
627 if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
628 goto exit_free;
a5ebe668 629
1beeffe4
TJ
630 data->hwmon_dev = hwmon_device_register(&pdev->dev);
631 if (IS_ERR(data->hwmon_dev)) {
632 err = PTR_ERR(data->hwmon_dev);
a5ebe668 633 goto exit_remove_files;
943b0830
MH
634 }
635
1da177e4
LT
636 return 0;
637
a5ebe668 638exit_remove_files:
2ec342e6 639 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
943b0830 640exit_free:
1da177e4 641 kfree(data);
943b0830 642exit_release:
2ec342e6 643 release_region(res->start, VIA686A_EXTENT);
1da177e4
LT
644 return err;
645}
646
2ec342e6 647static int __devexit via686a_remove(struct platform_device *pdev)
1da177e4 648{
2ec342e6 649 struct via686a_data *data = platform_get_drvdata(pdev);
1da177e4 650
1beeffe4 651 hwmon_device_unregister(data->hwmon_dev);
2ec342e6 652 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
943b0830 653
2ec342e6
JD
654 release_region(data->addr, VIA686A_EXTENT);
655 platform_set_drvdata(pdev, NULL);
943b0830 656 kfree(data);
1da177e4
LT
657
658 return 0;
659}
660
2ec342e6 661static void __devinit via686a_init_device(struct via686a_data *data)
1da177e4
LT
662{
663 u8 reg;
664
665 /* Start monitoring */
2ec342e6
JD
666 reg = via686a_read_value(data, VIA686A_REG_CONFIG);
667 via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
1da177e4
LT
668
669 /* Configure temp interrupt mode for continuous-interrupt operation */
2ec342e6
JD
670 reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
671 via686a_write_value(data, VIA686A_REG_TEMP_MODE,
58fe0809
JD
672 (reg & ~VIA686A_TEMP_MODE_MASK)
673 | VIA686A_TEMP_MODE_CONTINUOUS);
1da177e4
LT
674}
675
676static struct via686a_data *via686a_update_device(struct device *dev)
677{
2ec342e6 678 struct via686a_data *data = dev_get_drvdata(dev);
1da177e4
LT
679 int i;
680
9a61bf63 681 mutex_lock(&data->update_lock);
1da177e4
LT
682
683 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
684 || !data->valid) {
685 for (i = 0; i <= 4; i++) {
686 data->in[i] =
2ec342e6
JD
687 via686a_read_value(data, VIA686A_REG_IN(i));
688 data->in_min[i] = via686a_read_value(data,
1da177e4
LT
689 VIA686A_REG_IN_MIN
690 (i));
691 data->in_max[i] =
2ec342e6 692 via686a_read_value(data, VIA686A_REG_IN_MAX(i));
1da177e4
LT
693 }
694 for (i = 1; i <= 2; i++) {
695 data->fan[i - 1] =
2ec342e6
JD
696 via686a_read_value(data, VIA686A_REG_FAN(i));
697 data->fan_min[i - 1] = via686a_read_value(data,
1da177e4
LT
698 VIA686A_REG_FAN_MIN(i));
699 }
700 for (i = 0; i <= 2; i++) {
2ec342e6 701 data->temp[i] = via686a_read_value(data,
563db2fe 702 VIA686A_REG_TEMP[i]) << 2;
1da177e4 703 data->temp_over[i] =
2ec342e6 704 via686a_read_value(data,
563db2fe 705 VIA686A_REG_TEMP_OVER[i]);
1da177e4 706 data->temp_hyst[i] =
2ec342e6 707 via686a_read_value(data,
563db2fe 708 VIA686A_REG_TEMP_HYST[i]);
1da177e4 709 }
be8992c2 710 /* add in lower 2 bits
1da177e4
LT
711 temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
712 temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
713 temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
714 */
2ec342e6 715 data->temp[0] |= (via686a_read_value(data,
1da177e4
LT
716 VIA686A_REG_TEMP_LOW1)
717 & 0xc0) >> 6;
718 data->temp[1] |=
2ec342e6 719 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
1da177e4
LT
720 0x30) >> 4;
721 data->temp[2] |=
2ec342e6 722 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
1da177e4
LT
723 0xc0) >> 6;
724
2ec342e6 725 i = via686a_read_value(data, VIA686A_REG_FANDIV);
1da177e4
LT
726 data->fan_div[0] = (i >> 4) & 0x03;
727 data->fan_div[1] = i >> 6;
728 data->alarms =
2ec342e6 729 via686a_read_value(data,
1da177e4 730 VIA686A_REG_ALARM1) |
2ec342e6 731 (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
1da177e4
LT
732 data->last_updated = jiffies;
733 data->valid = 1;
734 }
735
9a61bf63 736 mutex_unlock(&data->update_lock);
1da177e4
LT
737
738 return data;
739}
740
741static struct pci_device_id via686a_pci_ids[] = {
be8992c2
JD
742 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
743 { 0, }
1da177e4
LT
744};
745
746MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
747
2ec342e6
JD
748static int __devinit via686a_device_add(unsigned short address)
749{
750 struct resource res = {
751 .start = address,
752 .end = address + VIA686A_EXTENT - 1,
753 .name = "via686a",
754 .flags = IORESOURCE_IO,
755 };
756 int err;
757
758 pdev = platform_device_alloc("via686a", address);
759 if (!pdev) {
760 err = -ENOMEM;
761 printk(KERN_ERR "via686a: Device allocation failed\n");
762 goto exit;
763 }
764
765 err = platform_device_add_resources(pdev, &res, 1);
766 if (err) {
767 printk(KERN_ERR "via686a: Device resource addition failed "
768 "(%d)\n", err);
769 goto exit_device_put;
770 }
771
772 err = platform_device_add(pdev);
773 if (err) {
774 printk(KERN_ERR "via686a: Device addition failed (%d)\n",
775 err);
776 goto exit_device_put;
777 }
778
779 return 0;
780
781exit_device_put:
782 platform_device_put(pdev);
783exit:
784 return err;
785}
786
1da177e4 787static int __devinit via686a_pci_probe(struct pci_dev *dev,
be8992c2 788 const struct pci_device_id *id)
1da177e4 789{
2ec342e6 790 u16 address, val;
be8992c2 791
2ec342e6
JD
792 if (force_addr) {
793 address = force_addr & ~(VIA686A_EXTENT - 1);
794 dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
795 if (PCIBIOS_SUCCESSFUL !=
796 pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
797 return -ENODEV;
798 }
be8992c2
JD
799 if (PCIBIOS_SUCCESSFUL !=
800 pci_read_config_word(dev, VIA686A_BASE_REG, &val))
801 return -ENODEV;
802
2d8672c5 803 address = val & ~(VIA686A_EXTENT - 1);
2ec342e6 804 if (address == 0) {
be8992c2
JD
805 dev_err(&dev->dev, "base address not set - upgrade BIOS "
806 "or use force_addr=0xaddr\n");
807 return -ENODEV;
808 }
be8992c2 809
2ec342e6
JD
810 if (PCIBIOS_SUCCESSFUL !=
811 pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
812 return -ENODEV;
813 if (!(val & 0x0001)) {
814 if (!force_addr) {
815 dev_warn(&dev->dev, "Sensors disabled, enable "
816 "with force_addr=0x%x\n", address);
817 return -ENODEV;
818 }
819
820 dev_warn(&dev->dev, "Enabling sensors\n");
821 if (PCIBIOS_SUCCESSFUL !=
822 pci_write_config_word(dev, VIA686A_ENABLE_REG,
823 val | 0x0001))
824 return -ENODEV;
1da177e4
LT
825 }
826
2ec342e6
JD
827 if (platform_driver_register(&via686a_driver))
828 goto exit;
829
830 /* Sets global pdev as a side effect */
831 if (via686a_device_add(address))
832 goto exit_unregister;
833
1da177e4
LT
834 /* Always return failure here. This is to allow other drivers to bind
835 * to this pci device. We don't really want to have control over the
836 * pci device, we only wanted to read as few register values from it.
837 */
2ec342e6
JD
838 s_bridge = pci_dev_get(dev);
839 return -ENODEV;
840
841exit_unregister:
842 platform_driver_unregister(&via686a_driver);
843exit:
1da177e4
LT
844 return -ENODEV;
845}
846
847static struct pci_driver via686a_pci_driver = {
be8992c2
JD
848 .name = "via686a",
849 .id_table = via686a_pci_ids,
850 .probe = via686a_pci_probe,
1da177e4
LT
851};
852
853static int __init sm_via686a_init(void)
854{
be8992c2 855 return pci_register_driver(&via686a_pci_driver);
1da177e4
LT
856}
857
858static void __exit sm_via686a_exit(void)
859{
860 pci_unregister_driver(&via686a_pci_driver);
861 if (s_bridge != NULL) {
2ec342e6
JD
862 platform_device_unregister(pdev);
863 platform_driver_unregister(&via686a_driver);
1da177e4
LT
864 pci_dev_put(s_bridge);
865 s_bridge = NULL;
866 }
867}
868
96de0e25 869MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
be8992c2
JD
870 "Mark Studebaker <mdsxyz123@yahoo.com> "
871 "and Bob Dougherty <bobd@stanford.edu>");
1da177e4
LT
872MODULE_DESCRIPTION("VIA 686A Sensor device");
873MODULE_LICENSE("GPL");
874
875module_init(sm_via686a_init);
876module_exit(sm_via686a_exit);