Merge remote-tracking branch 'asoc/topic/arizona' into asoc-next
[deliverable/linux.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 = {
87218842 673 .owner = THIS_MODULE,
cdaf7934
LR
674 .name = "via686a",
675 },
2ec342e6 676 .probe = via686a_probe,
9e5e9b7a 677 .remove = via686a_remove,
1da177e4
LT
678};
679
680
681/* This is called when the module is loaded */
6c931ae1 682static int via686a_probe(struct platform_device *pdev)
1da177e4 683{
1da177e4 684 struct via686a_data *data;
2ec342e6
JD
685 struct resource *res;
686 int err;
1da177e4
LT
687
688 /* Reserve the ISA region */
2ec342e6 689 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
fd55bc00
GR
690 if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
691 via686a_driver.driver.name)) {
2ec342e6
JD
692 dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
693 (unsigned long)res->start, (unsigned long)res->end);
1da177e4
LT
694 return -ENODEV;
695 }
696
fd55bc00
GR
697 data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
698 GFP_KERNEL);
699 if (!data)
700 return -ENOMEM;
1da177e4 701
2ec342e6
JD
702 platform_set_drvdata(pdev, data);
703 data->addr = res->start;
704 data->name = "via686a";
9a61bf63 705 mutex_init(&data->update_lock);
be8992c2 706
1da177e4 707 /* Initialize the VIA686A chip */
2ec342e6 708 via686a_init_device(data);
1da177e4
LT
709
710 /* Register sysfs hooks */
9004ac81
GR
711 err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
712 if (err)
fd55bc00 713 return err;
a5ebe668 714
1beeffe4
TJ
715 data->hwmon_dev = hwmon_device_register(&pdev->dev);
716 if (IS_ERR(data->hwmon_dev)) {
717 err = PTR_ERR(data->hwmon_dev);
a5ebe668 718 goto exit_remove_files;
943b0830
MH
719 }
720
1da177e4
LT
721 return 0;
722
a5ebe668 723exit_remove_files:
2ec342e6 724 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
1da177e4
LT
725 return err;
726}
727
281dfd0b 728static int via686a_remove(struct platform_device *pdev)
1da177e4 729{
2ec342e6 730 struct via686a_data *data = platform_get_drvdata(pdev);
1da177e4 731
1beeffe4 732 hwmon_device_unregister(data->hwmon_dev);
2ec342e6 733 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
943b0830 734
1da177e4
LT
735 return 0;
736}
737
f790674d
JD
738static void via686a_update_fan_div(struct via686a_data *data)
739{
740 int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
741 data->fan_div[0] = (reg >> 4) & 0x03;
742 data->fan_div[1] = reg >> 6;
743}
744
6c931ae1 745static void via686a_init_device(struct via686a_data *data)
1da177e4
LT
746{
747 u8 reg;
748
749 /* Start monitoring */
2ec342e6
JD
750 reg = via686a_read_value(data, VIA686A_REG_CONFIG);
751 via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
1da177e4
LT
752
753 /* Configure temp interrupt mode for continuous-interrupt operation */
2ec342e6
JD
754 reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
755 via686a_write_value(data, VIA686A_REG_TEMP_MODE,
58fe0809
JD
756 (reg & ~VIA686A_TEMP_MODE_MASK)
757 | VIA686A_TEMP_MODE_CONTINUOUS);
f790674d
JD
758
759 /* Pre-read fan clock divisor values */
760 via686a_update_fan_div(data);
1da177e4
LT
761}
762
763static struct via686a_data *via686a_update_device(struct device *dev)
764{
2ec342e6 765 struct via686a_data *data = dev_get_drvdata(dev);
1da177e4
LT
766 int i;
767
9a61bf63 768 mutex_lock(&data->update_lock);
1da177e4
LT
769
770 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
771 || !data->valid) {
772 for (i = 0; i <= 4; i++) {
773 data->in[i] =
2ec342e6
JD
774 via686a_read_value(data, VIA686A_REG_IN(i));
775 data->in_min[i] = via686a_read_value(data,
1da177e4
LT
776 VIA686A_REG_IN_MIN
777 (i));
778 data->in_max[i] =
2ec342e6 779 via686a_read_value(data, VIA686A_REG_IN_MAX(i));
1da177e4
LT
780 }
781 for (i = 1; i <= 2; i++) {
782 data->fan[i - 1] =
2ec342e6
JD
783 via686a_read_value(data, VIA686A_REG_FAN(i));
784 data->fan_min[i - 1] = via686a_read_value(data,
1da177e4
LT
785 VIA686A_REG_FAN_MIN(i));
786 }
787 for (i = 0; i <= 2; i++) {
2ec342e6 788 data->temp[i] = via686a_read_value(data,
563db2fe 789 VIA686A_REG_TEMP[i]) << 2;
1da177e4 790 data->temp_over[i] =
2ec342e6 791 via686a_read_value(data,
563db2fe 792 VIA686A_REG_TEMP_OVER[i]);
1da177e4 793 data->temp_hyst[i] =
2ec342e6 794 via686a_read_value(data,
563db2fe 795 VIA686A_REG_TEMP_HYST[i]);
1da177e4 796 }
9004ac81
GR
797 /*
798 * add in lower 2 bits
799 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
800 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
801 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
1da177e4 802 */
2ec342e6 803 data->temp[0] |= (via686a_read_value(data,
1da177e4
LT
804 VIA686A_REG_TEMP_LOW1)
805 & 0xc0) >> 6;
806 data->temp[1] |=
2ec342e6 807 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
1da177e4
LT
808 0x30) >> 4;
809 data->temp[2] |=
2ec342e6 810 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
1da177e4
LT
811 0xc0) >> 6;
812
f790674d 813 via686a_update_fan_div(data);
1da177e4 814 data->alarms =
2ec342e6 815 via686a_read_value(data,
1da177e4 816 VIA686A_REG_ALARM1) |
2ec342e6 817 (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
1da177e4
LT
818 data->last_updated = jiffies;
819 data->valid = 1;
820 }
821
9a61bf63 822 mutex_unlock(&data->update_lock);
1da177e4
LT
823
824 return data;
825}
826
600151b9 827static DEFINE_PCI_DEVICE_TABLE(via686a_pci_ids) = {
be8992c2 828 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
9004ac81 829 { }
1da177e4 830};
1da177e4
LT
831MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
832
6c931ae1 833static int via686a_device_add(unsigned short address)
2ec342e6
JD
834{
835 struct resource res = {
836 .start = address,
837 .end = address + VIA686A_EXTENT - 1,
838 .name = "via686a",
839 .flags = IORESOURCE_IO,
840 };
841 int err;
842
b9acb64a
JD
843 err = acpi_check_resource_conflict(&res);
844 if (err)
845 goto exit;
846
2ec342e6
JD
847 pdev = platform_device_alloc("via686a", address);
848 if (!pdev) {
849 err = -ENOMEM;
774f7827 850 pr_err("Device allocation failed\n");
2ec342e6
JD
851 goto exit;
852 }
853
854 err = platform_device_add_resources(pdev, &res, 1);
855 if (err) {
774f7827 856 pr_err("Device resource addition failed (%d)\n", err);
2ec342e6
JD
857 goto exit_device_put;
858 }
859
860 err = platform_device_add(pdev);
861 if (err) {
774f7827 862 pr_err("Device addition failed (%d)\n", err);
2ec342e6
JD
863 goto exit_device_put;
864 }
865
866 return 0;
867
868exit_device_put:
869 platform_device_put(pdev);
870exit:
871 return err;
872}
873
6c931ae1 874static int via686a_pci_probe(struct pci_dev *dev,
be8992c2 875 const struct pci_device_id *id)
1da177e4 876{
2ec342e6 877 u16 address, val;
be8992c2 878
2ec342e6
JD
879 if (force_addr) {
880 address = force_addr & ~(VIA686A_EXTENT - 1);
881 dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
882 if (PCIBIOS_SUCCESSFUL !=
883 pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
884 return -ENODEV;
885 }
be8992c2
JD
886 if (PCIBIOS_SUCCESSFUL !=
887 pci_read_config_word(dev, VIA686A_BASE_REG, &val))
888 return -ENODEV;
889
2d8672c5 890 address = val & ~(VIA686A_EXTENT - 1);
2ec342e6 891 if (address == 0) {
b55f3757
GR
892 dev_err(&dev->dev,
893 "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
be8992c2
JD
894 return -ENODEV;
895 }
be8992c2 896
2ec342e6
JD
897 if (PCIBIOS_SUCCESSFUL !=
898 pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
899 return -ENODEV;
900 if (!(val & 0x0001)) {
901 if (!force_addr) {
b55f3757
GR
902 dev_warn(&dev->dev,
903 "Sensors disabled, enable with force_addr=0x%x\n",
904 address);
2ec342e6
JD
905 return -ENODEV;
906 }
907
908 dev_warn(&dev->dev, "Enabling sensors\n");
909 if (PCIBIOS_SUCCESSFUL !=
910 pci_write_config_word(dev, VIA686A_ENABLE_REG,
911 val | 0x0001))
912 return -ENODEV;
1da177e4
LT
913 }
914
2ec342e6
JD
915 if (platform_driver_register(&via686a_driver))
916 goto exit;
917
918 /* Sets global pdev as a side effect */
919 if (via686a_device_add(address))
920 goto exit_unregister;
921
9004ac81
GR
922 /*
923 * Always return failure here. This is to allow other drivers to bind
1da177e4
LT
924 * to this pci device. We don't really want to have control over the
925 * pci device, we only wanted to read as few register values from it.
926 */
2ec342e6
JD
927 s_bridge = pci_dev_get(dev);
928 return -ENODEV;
929
930exit_unregister:
931 platform_driver_unregister(&via686a_driver);
932exit:
1da177e4
LT
933 return -ENODEV;
934}
935
936static struct pci_driver via686a_pci_driver = {
be8992c2
JD
937 .name = "via686a",
938 .id_table = via686a_pci_ids,
939 .probe = via686a_pci_probe,
1da177e4
LT
940};
941
942static int __init sm_via686a_init(void)
943{
be8992c2 944 return pci_register_driver(&via686a_pci_driver);
1da177e4
LT
945}
946
947static void __exit sm_via686a_exit(void)
948{
949 pci_unregister_driver(&via686a_pci_driver);
950 if (s_bridge != NULL) {
2ec342e6
JD
951 platform_device_unregister(pdev);
952 platform_driver_unregister(&via686a_driver);
1da177e4
LT
953 pci_dev_put(s_bridge);
954 s_bridge = NULL;
955 }
956}
957
96de0e25 958MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
be8992c2
JD
959 "Mark Studebaker <mdsxyz123@yahoo.com> "
960 "and Bob Dougherty <bobd@stanford.edu>");
1da177e4
LT
961MODULE_DESCRIPTION("VIA 686A Sensor device");
962MODULE_LICENSE("GPL");
963
964module_init(sm_via686a_init);
965module_exit(sm_via686a_exit);
This page took 0.861835 seconds and 5 git commands to generate.