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