blob: c9dcce8c3dc34fa7ec8e7eeb0c8ee6812dc159ce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Guenter Roeck9004ac82012-01-15 06:38:23 -08002 * 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28/*
Guenter Roeck9004ac82012-01-15 06:38:23 -080029 * Supports the Via VT82C686A, VT82C686B south bridges.
30 * Reports all as a 686A.
31 * Warning - only supports a single device.
32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Joe Perches774f7822010-10-20 06:51:51 +000034#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/module.h>
37#include <linux/slab.h>
38#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/jiffies.h>
Jean Delvare2ec342e2007-06-09 10:11:16 -040040#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040041#include <linux/hwmon.h>
Jean Delvare1e71a5a2007-06-09 10:11:16 -040042#include <linux/hwmon-sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040043#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/init.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010045#include <linux/mutex.h>
Jean Delvarea5ebe662006-09-24 21:24:46 +020046#include <linux/sysfs.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010047#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020048#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50
Guenter Roeck9004ac82012-01-15 06:38:23 -080051/*
52 * If force_addr is set to anything different from 0, we forcibly enable
53 * the device at the given address.
54 */
Jean Delvare02002962005-09-25 16:26:44 +020055static unsigned short force_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056module_param(force_addr, ushort, 0);
57MODULE_PARM_DESC(force_addr,
58 "Initialize the base address of the sensors");
59
Jean Delvare2ec342e2007-06-09 10:11:16 -040060static struct platform_device *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62/*
Guenter Roeck9004ac82012-01-15 06:38:23 -080063 * 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67/* Many VIA686A constants specified below */
68
69/* Length of ISA address segment */
Jean Delvarebe8992c2005-05-16 19:00:52 +020070#define VIA686A_EXTENT 0x80
71#define VIA686A_BASE_REG 0x70
72#define VIA686A_ENABLE_REG 0x74
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/* The VIA686A registers */
75/* ins numbered 0-4 */
Jean Delvarebe8992c2005-05-16 19:00:52 +020076#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))
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* fans numbered 1-2 */
Jean Delvarebe8992c2005-05-16 19:00:52 +020081#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
82#define VIA686A_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* temps numbered 1-3 */
Jean Delvare563db2f2005-05-17 22:38:57 +020085static 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 };
Jean Delvarebe8992c2005-05-16 19:00:52 +020088/* 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Jean Delvarebe8992c2005-05-16 19:00:52 +020093#define VIA686A_REG_ALARM1 0x41
94#define VIA686A_REG_ALARM2 0x42
95#define VIA686A_REG_FANDIV 0x47
96#define VIA686A_REG_CONFIG 0x40
Guenter Roeck9004ac82012-01-15 06:38:23 -080097/*
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 */
Jean Delvarebe8992c2005-05-16 19:00:52 +0200105#define VIA686A_REG_TEMP_MODE 0x4b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/* We'll just assume that you want to set all 3 simultaneously: */
Jean Delvarebe8992c2005-05-16 19:00:52 +0200107#define VIA686A_TEMP_MODE_MASK 0x3F
108#define VIA686A_TEMP_MODE_CONTINUOUS 0x00
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Guenter Roeck9004ac82012-01-15 06:38:23 -0800110/*
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 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700128static inline u8 IN_TO_REG(long val, int in_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Guenter Roeck9004ac82012-01-15 06:38:23 -0800130 /*
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 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700137 if (in_num <= 1)
Guenter Roeck2a844c12013-01-09 08:09:34 -0800138 return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700139 else if (in_num == 2)
Guenter Roeck2a844c12013-01-09 08:09:34 -0800140 return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700141 else if (in_num == 3)
Guenter Roeck2a844c12013-01-09 08:09:34 -0800142 return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 else
Guenter Roeck2a844c12013-01-09 08:09:34 -0800144 return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
145 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700148static inline long IN_FROM_REG(u8 val, int in_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Guenter Roeck9004ac82012-01-15 06:38:23 -0800150 /*
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 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700155 if (in_num <= 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700157 else if (in_num == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700159 else if (in_num == 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 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 ********/
Guenter Roeck9004ac82012-01-15 06:38:23 -0800166/*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static inline u8 FAN_TO_REG(long rpm, int div)
172{
173 if (rpm == 0)
174 return 0;
Guenter Roeck2a844c12013-01-09 08:09:34 -0800175 rpm = clamp_val(rpm, 1, 1000000);
176 return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177}
178
Guenter Roeck9004ac82012-01-15 06:38:23 -0800179#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
180 ((val) * (div)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182/******** TEMP CONVERSIONS (Bob Dougherty) *********/
Guenter Roeck9004ac82012-01-15 06:38:23 -0800183/*
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
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700213 * we'll just use linear interpolation for 10-bit readings.) So, temp_lut
Guenter Roeck9004ac82012-01-15 06:38:23 -0800214 * is the temp at via register values 0-255:
215 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700216static const s16 temp_lut[] = {
Guenter Roeck9004ac82012-01-15 06:38:23 -0800217 -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200218 -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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239};
240
Guenter Roeck9004ac82012-01-15 06:38:23 -0800241/*
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 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700264static const u8 via_lut[] = {
Guenter Roeck9004ac82012-01-15 06:38:23 -0800265 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200266 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278};
279
Guenter Roeck9004ac82012-01-15 06:38:23 -0800280/*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285static inline u8 TEMP_TO_REG(long val)
286{
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700287 return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 (val < 0 ? val - 500 : val + 500) / 1000 + 50];
289}
290
291/* for 8-bit temperature hyst and over registers */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700292#define TEMP_FROM_REG(val) ((long)temp_lut[val] * 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294/* for 10-bit temperature readings */
295static inline long TEMP_FROM_REG10(u16 val)
296{
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700297 u16 eight_bits = val >> 2;
298 u16 two_bits = val & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 /* no interpolation for these */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700301 if (two_bits == 0 || eight_bits == 255)
302 return TEMP_FROM_REG(eight_bits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 /* do some linear interpolation */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700305 return (temp_lut[eight_bits] * (4 - two_bits) +
306 temp_lut[eight_bits + 1] * two_bits) * 25;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309#define DIV_FROM_REG(val) (1 << (val))
Guenter Roeck9004ac82012-01-15 06:38:23 -0800310#define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Guenter Roeck9004ac82012-01-15 06:38:23 -0800312/*
313 * For each registered chip, we need to keep some data in memory.
314 * The structure is dynamically allocated.
315 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316struct via686a_data {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400317 unsigned short addr;
318 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700319 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100320 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 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
Jean Delvare2ec342e2007-06-09 10:11:16 -0400338static int via686a_probe(struct platform_device *pdev);
Bill Pemberton281dfd02012-11-19 13:25:51 -0500339static int via686a_remove(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Jean Delvare2ec342e2007-06-09 10:11:16 -0400341static inline int via686a_read_value(struct via686a_data *data, u8 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400343 return inb_p(data->addr + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
Jean Delvare2ec342e2007-06-09 10:11:16 -0400346static inline void via686a_write_value(struct via686a_data *data, u8 reg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 u8 value)
348{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400349 outb_p(value, data->addr + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
352static struct via686a_data *via686a_update_device(struct device *dev);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400353static void via686a_init_device(struct via686a_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355/* following are the sysfs callback functions */
356
357/* 7 voltage sensors */
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400358static ssize_t show_in(struct device *dev, struct device_attribute *da,
359 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400361 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
362 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
364}
365
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400366static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
367 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400369 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
370 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
372}
373
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400374static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
375 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400377 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
378 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
380}
381
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400382static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
383 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400384 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400385 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
386 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800387 unsigned long val;
388 int err;
389
390 err = kstrtoul(buf, 10, &val);
391 if (err)
392 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100394 mutex_lock(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200395 data->in_min[nr] = IN_TO_REG(val, nr);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400396 via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 data->in_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100398 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return count;
400}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400401static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
402 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400403 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400404 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
405 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800406 unsigned long val;
407 int err;
408
409 err = kstrtoul(buf, 10, &val);
410 if (err)
411 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100413 mutex_lock(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200414 data->in_max[nr] = IN_TO_REG(val, nr);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400415 via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 data->in_max[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100417 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return count;
419}
420#define show_in_offset(offset) \
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400421static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428show_in_offset(0);
429show_in_offset(1);
430show_in_offset(2);
431show_in_offset(3);
432show_in_offset(4);
433
434/* 3 temperatures */
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400435static ssize_t show_temp(struct device *dev, struct device_attribute *da,
436 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400438 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
439 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
441}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400442static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
443 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400445 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
446 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
448}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400449static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
450 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400452 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
453 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
455}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400456static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
457 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400458 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400459 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
460 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800461 long val;
462 int err;
463
464 err = kstrtol(buf, 10, &val);
465 if (err)
466 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100468 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 data->temp_over[nr] = TEMP_TO_REG(val);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400470 via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
Jean Delvare563db2f2005-05-17 22:38:57 +0200471 data->temp_over[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100472 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 return count;
474}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400475static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
476 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400477 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400478 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
479 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800480 long val;
481 int err;
482
483 err = kstrtol(buf, 10, &val);
484 if (err)
485 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100487 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 data->temp_hyst[nr] = TEMP_TO_REG(val);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400489 via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
Jean Delvare563db2f2005-05-17 22:38:57 +0200490 data->temp_hyst[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100491 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return count;
493}
494#define show_temp_offset(offset) \
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400495static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502show_temp_offset(1);
503show_temp_offset(2);
504show_temp_offset(3);
505
506/* 2 Fans */
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400507static ssize_t show_fan(struct device *dev, struct device_attribute *da,
508 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400510 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
511 int nr = attr->index;
Jean Delvarebe8992c2005-05-16 19:00:52 +0200512 return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
Guenter Roeck9004ac82012-01-15 06:38:23 -0800513 DIV_FROM_REG(data->fan_div[nr])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400515static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
516 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400518 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
519 int nr = attr->index;
Jean Delvarebe8992c2005-05-16 19:00:52 +0200520 return sprintf(buf, "%d\n",
Guenter Roeck9004ac82012-01-15 06:38:23 -0800521 FAN_FROM_REG(data->fan_min[nr],
522 DIV_FROM_REG(data->fan_div[nr])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400524static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
525 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400527 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
528 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800529 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400531static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
532 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400533 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400534 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
535 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800536 unsigned long val;
537 int err;
538
539 err = kstrtoul(buf, 10, &val);
540 if (err)
541 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100543 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare2ec342e2007-06-09 10:11:16 -0400545 via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100546 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return count;
548}
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400549static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
550 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400551 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400552 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
553 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 int old;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800555 unsigned long val;
556 int err;
557
558 err = kstrtoul(buf, 10, &val);
559 if (err)
560 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100562 mutex_lock(&data->update_lock);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400563 old = via686a_read_value(data, VIA686A_REG_FANDIV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 data->fan_div[nr] = DIV_TO_REG(val);
565 old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400566 via686a_write_value(data, VIA686A_REG_FANDIV, old);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100567 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 return count;
569}
570
571#define show_fan_offset(offset) \
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400572static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579show_fan_offset(1);
580show_fan_offset(2);
581
582/* Alarms */
Guenter Roeck9004ac82012-01-15 06:38:23 -0800583static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
584 char *buf)
585{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200587 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588}
Guenter Roeck9004ac82012-01-15 06:38:23 -0800589
Jean Delvare1d66c642005-04-18 21:16:59 -0700590static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Jean Delvare13ff05e2008-01-06 15:42:04 +0100592static 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
Jean Delvare2ec342e2007-06-09 10:11:16 -0400610static 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
Jean Delvarea5ebe662006-09-24 21:24:46 +0200618static struct attribute *via686a_attributes[] = {
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400619 &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,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100634 &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,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200639
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400640 &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,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100649 &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,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200652
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400653 &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,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100659 &sensor_dev_attr_fan1_alarm.dev_attr.attr,
660 &sensor_dev_attr_fan2_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200661
662 &dev_attr_alarms.attr,
Jean Delvare2ec342e2007-06-09 10:11:16 -0400663 &dev_attr_name.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200664 NULL
665};
666
667static const struct attribute_group via686a_group = {
668 .attrs = via686a_attributes,
669};
670
Jean Delvare2ec342e2007-06-09 10:11:16 -0400671static struct platform_driver via686a_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100672 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200673 .owner = THIS_MODULE,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100674 .name = "via686a",
675 },
Jean Delvare2ec342e2007-06-09 10:11:16 -0400676 .probe = via686a_probe,
Bill Pemberton9e5e9b72012-11-19 13:21:20 -0500677 .remove = via686a_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678};
679
680
681/* This is called when the module is loaded */
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500682static int via686a_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 struct via686a_data *data;
Jean Delvare2ec342e2007-06-09 10:11:16 -0400685 struct resource *res;
686 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 /* Reserve the ISA region */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400689 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700690 if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
691 via686a_driver.driver.name)) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400692 dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
693 (unsigned long)res->start, (unsigned long)res->end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return -ENODEV;
695 }
696
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700697 data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
698 GFP_KERNEL);
699 if (!data)
700 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Jean Delvare2ec342e2007-06-09 10:11:16 -0400702 platform_set_drvdata(pdev, data);
703 data->addr = res->start;
704 data->name = "via686a";
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100705 mutex_init(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* Initialize the VIA686A chip */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400708 via686a_init_device(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 /* Register sysfs hooks */
Guenter Roeck9004ac82012-01-15 06:38:23 -0800711 err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
712 if (err)
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700713 return err;
Jean Delvarea5ebe662006-09-24 21:24:46 +0200714
Tony Jones1beeffe2007-08-20 13:46:20 -0700715 data->hwmon_dev = hwmon_device_register(&pdev->dev);
716 if (IS_ERR(data->hwmon_dev)) {
717 err = PTR_ERR(data->hwmon_dev);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200718 goto exit_remove_files;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400719 }
720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return 0;
722
Jean Delvarea5ebe662006-09-24 21:24:46 +0200723exit_remove_files:
Jean Delvare2ec342e2007-06-09 10:11:16 -0400724 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return err;
726}
727
Bill Pemberton281dfd02012-11-19 13:25:51 -0500728static int via686a_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400730 struct via686a_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Tony Jones1beeffe2007-08-20 13:46:20 -0700732 hwmon_device_unregister(data->hwmon_dev);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400733 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return 0;
736}
737
Jean Delvaref7906742011-01-12 21:55:09 +0100738static 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
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500745static void via686a_init_device(struct via686a_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 u8 reg;
748
749 /* Start monitoring */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400750 reg = via686a_read_value(data, VIA686A_REG_CONFIG);
751 via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 /* Configure temp interrupt mode for continuous-interrupt operation */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400754 reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
755 via686a_write_value(data, VIA686A_REG_TEMP_MODE,
Jean Delvare58fe0802007-06-09 10:11:16 -0400756 (reg & ~VIA686A_TEMP_MODE_MASK)
757 | VIA686A_TEMP_MODE_CONTINUOUS);
Jean Delvaref7906742011-01-12 21:55:09 +0100758
759 /* Pre-read fan clock divisor values */
760 via686a_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
763static struct via686a_data *via686a_update_device(struct device *dev)
764{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400765 struct via686a_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 int i;
767
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100768 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
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] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400774 via686a_read_value(data, VIA686A_REG_IN(i));
775 data->in_min[i] = via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 VIA686A_REG_IN_MIN
777 (i));
778 data->in_max[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400779 via686a_read_value(data, VIA686A_REG_IN_MAX(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
781 for (i = 1; i <= 2; i++) {
782 data->fan[i - 1] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400783 via686a_read_value(data, VIA686A_REG_FAN(i));
784 data->fan_min[i - 1] = via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 VIA686A_REG_FAN_MIN(i));
786 }
787 for (i = 0; i <= 2; i++) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400788 data->temp[i] = via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200789 VIA686A_REG_TEMP[i]) << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 data->temp_over[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400791 via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200792 VIA686A_REG_TEMP_OVER[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 data->temp_hyst[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400794 via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200795 VIA686A_REG_TEMP_HYST[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
Guenter Roeck9004ac82012-01-15 06:38:23 -0800797 /*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400803 data->temp[0] |= (via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 VIA686A_REG_TEMP_LOW1)
805 & 0xc0) >> 6;
806 data->temp[1] |=
Jean Delvare2ec342e2007-06-09 10:11:16 -0400807 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 0x30) >> 4;
809 data->temp[2] |=
Jean Delvare2ec342e2007-06-09 10:11:16 -0400810 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 0xc0) >> 6;
812
Jean Delvaref7906742011-01-12 21:55:09 +0100813 via686a_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 data->alarms =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400815 via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 VIA686A_REG_ALARM1) |
Jean Delvare2ec342e2007-06-09 10:11:16 -0400817 (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 data->last_updated = jiffies;
819 data->valid = 1;
820 }
821
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100822 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 return data;
825}
826
Frans Meulenbroeks600151b2012-01-05 19:50:17 +0100827static DEFINE_PCI_DEVICE_TABLE(via686a_pci_ids) = {
Jean Delvarebe8992c2005-05-16 19:00:52 +0200828 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
Guenter Roeck9004ac82012-01-15 06:38:23 -0800829 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
832
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500833static int via686a_device_add(unsigned short address)
Jean Delvare2ec342e2007-06-09 10:11:16 -0400834{
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
Jean Delvareb9acb642009-01-07 16:37:35 +0100843 err = acpi_check_resource_conflict(&res);
844 if (err)
845 goto exit;
846
Jean Delvare2ec342e2007-06-09 10:11:16 -0400847 pdev = platform_device_alloc("via686a", address);
848 if (!pdev) {
849 err = -ENOMEM;
Joe Perches774f7822010-10-20 06:51:51 +0000850 pr_err("Device allocation failed\n");
Jean Delvare2ec342e2007-06-09 10:11:16 -0400851 goto exit;
852 }
853
854 err = platform_device_add_resources(pdev, &res, 1);
855 if (err) {
Joe Perches774f7822010-10-20 06:51:51 +0000856 pr_err("Device resource addition failed (%d)\n", err);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400857 goto exit_device_put;
858 }
859
860 err = platform_device_add(pdev);
861 if (err) {
Joe Perches774f7822010-10-20 06:51:51 +0000862 pr_err("Device addition failed (%d)\n", err);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400863 goto exit_device_put;
864 }
865
866 return 0;
867
868exit_device_put:
869 platform_device_put(pdev);
870exit:
871 return err;
872}
873
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500874static int via686a_pci_probe(struct pci_dev *dev,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200875 const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400877 u16 address, val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Jean Delvare2ec342e2007-06-09 10:11:16 -0400879 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 }
Jean Delvarebe8992c2005-05-16 19:00:52 +0200886 if (PCIBIOS_SUCCESSFUL !=
887 pci_read_config_word(dev, VIA686A_BASE_REG, &val))
888 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
Jean Delvare2d8672c2005-07-19 23:56:35 +0200890 address = val & ~(VIA686A_EXTENT - 1);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400891 if (address == 0) {
Guenter Roeckb55f3752013-01-10 10:01:24 -0800892 dev_err(&dev->dev,
893 "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
Jean Delvarebe8992c2005-05-16 19:00:52 +0200894 return -ENODEV;
895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Jean Delvare2ec342e2007-06-09 10:11:16 -0400897 if (PCIBIOS_SUCCESSFUL !=
898 pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
899 return -ENODEV;
900 if (!(val & 0x0001)) {
901 if (!force_addr) {
Guenter Roeckb55f3752013-01-10 10:01:24 -0800902 dev_warn(&dev->dev,
903 "Sensors disabled, enable with force_addr=0x%x\n",
904 address);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400905 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 }
914
Jean Delvare2ec342e2007-06-09 10:11:16 -0400915 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
Guenter Roeck9004ac82012-01-15 06:38:23 -0800922 /*
923 * Always return failure here. This is to allow other drivers to bind
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 * 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 */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400927 s_bridge = pci_dev_get(dev);
928 return -ENODEV;
929
930exit_unregister:
931 platform_driver_unregister(&via686a_driver);
932exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return -ENODEV;
934}
935
936static struct pci_driver via686a_pci_driver = {
Jean Delvarebe8992c2005-05-16 19:00:52 +0200937 .name = "via686a",
938 .id_table = via686a_pci_ids,
939 .probe = via686a_pci_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940};
941
942static int __init sm_via686a_init(void)
943{
Jean Delvarebe8992c2005-05-16 19:00:52 +0200944 return pci_register_driver(&via686a_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
947static void __exit sm_via686a_exit(void)
948{
949 pci_unregister_driver(&via686a_pci_driver);
950 if (s_bridge != NULL) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400951 platform_device_unregister(pdev);
952 platform_driver_unregister(&via686a_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 pci_dev_put(s_bridge);
954 s_bridge = NULL;
955 }
956}
957
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200958MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
Jean Delvarebe8992c2005-05-16 19:00:52 +0200959 "Mark Studebaker <mdsxyz123@yahoo.com> "
960 "and Bob Dougherty <bobd@stanford.edu>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961MODULE_DESCRIPTION("VIA 686A Sensor device");
962MODULE_LICENSE("GPL");
963
964module_init(sm_via686a_init);
965module_exit(sm_via686a_exit);