blob: 81f35e3a06b8439f455f01cc50daf79960d943f5 [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 */
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100583static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
Guenter Roeck9004ac82012-01-15 06:38:23 -0800584 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
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100590static DEVICE_ATTR_RO(alarms);
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
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100610static ssize_t name_show(struct device *dev, struct device_attribute
Jean Delvare2ec342e2007-06-09 10:11:16 -0400611 *devattr, char *buf)
612{
613 struct via686a_data *data = dev_get_drvdata(dev);
614 return sprintf(buf, "%s\n", data->name);
615}
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100616static DEVICE_ATTR_RO(name);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400617
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 = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100673 .name = "via686a",
674 },
Jean Delvare2ec342e2007-06-09 10:11:16 -0400675 .probe = via686a_probe,
Bill Pemberton9e5e9b72012-11-19 13:21:20 -0500676 .remove = via686a_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677};
678
679
680/* This is called when the module is loaded */
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500681static int via686a_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 struct via686a_data *data;
Jean Delvare2ec342e2007-06-09 10:11:16 -0400684 struct resource *res;
685 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 /* Reserve the ISA region */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400688 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700689 if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
690 via686a_driver.driver.name)) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400691 dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
692 (unsigned long)res->start, (unsigned long)res->end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return -ENODEV;
694 }
695
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700696 data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
697 GFP_KERNEL);
698 if (!data)
699 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Jean Delvare2ec342e2007-06-09 10:11:16 -0400701 platform_set_drvdata(pdev, data);
702 data->addr = res->start;
703 data->name = "via686a";
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100704 mutex_init(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /* Initialize the VIA686A chip */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400707 via686a_init_device(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 /* Register sysfs hooks */
Guenter Roeck9004ac82012-01-15 06:38:23 -0800710 err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
711 if (err)
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700712 return err;
Jean Delvarea5ebe662006-09-24 21:24:46 +0200713
Tony Jones1beeffe2007-08-20 13:46:20 -0700714 data->hwmon_dev = hwmon_device_register(&pdev->dev);
715 if (IS_ERR(data->hwmon_dev)) {
716 err = PTR_ERR(data->hwmon_dev);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200717 goto exit_remove_files;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400718 }
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return 0;
721
Jean Delvarea5ebe662006-09-24 21:24:46 +0200722exit_remove_files:
Jean Delvare2ec342e2007-06-09 10:11:16 -0400723 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return err;
725}
726
Bill Pemberton281dfd02012-11-19 13:25:51 -0500727static int via686a_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400729 struct via686a_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
Tony Jones1beeffe2007-08-20 13:46:20 -0700731 hwmon_device_unregister(data->hwmon_dev);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400732 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return 0;
735}
736
Jean Delvaref7906742011-01-12 21:55:09 +0100737static 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
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500744static void via686a_init_device(struct via686a_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
746 u8 reg;
747
748 /* Start monitoring */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400749 reg = via686a_read_value(data, VIA686A_REG_CONFIG);
750 via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752 /* Configure temp interrupt mode for continuous-interrupt operation */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400753 reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
754 via686a_write_value(data, VIA686A_REG_TEMP_MODE,
Jean Delvare58fe0802007-06-09 10:11:16 -0400755 (reg & ~VIA686A_TEMP_MODE_MASK)
756 | VIA686A_TEMP_MODE_CONTINUOUS);
Jean Delvaref7906742011-01-12 21:55:09 +0100757
758 /* Pre-read fan clock divisor values */
759 via686a_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
762static struct via686a_data *via686a_update_device(struct device *dev)
763{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400764 struct via686a_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 int i;
766
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100767 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
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] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400773 via686a_read_value(data, VIA686A_REG_IN(i));
774 data->in_min[i] = via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 VIA686A_REG_IN_MIN
776 (i));
777 data->in_max[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400778 via686a_read_value(data, VIA686A_REG_IN_MAX(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 for (i = 1; i <= 2; i++) {
781 data->fan[i - 1] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400782 via686a_read_value(data, VIA686A_REG_FAN(i));
783 data->fan_min[i - 1] = via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 VIA686A_REG_FAN_MIN(i));
785 }
786 for (i = 0; i <= 2; i++) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400787 data->temp[i] = via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200788 VIA686A_REG_TEMP[i]) << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 data->temp_over[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400790 via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200791 VIA686A_REG_TEMP_OVER[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 data->temp_hyst[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400793 via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200794 VIA686A_REG_TEMP_HYST[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 }
Guenter Roeck9004ac82012-01-15 06:38:23 -0800796 /*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400802 data->temp[0] |= (via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 VIA686A_REG_TEMP_LOW1)
804 & 0xc0) >> 6;
805 data->temp[1] |=
Jean Delvare2ec342e2007-06-09 10:11:16 -0400806 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 0x30) >> 4;
808 data->temp[2] |=
Jean Delvare2ec342e2007-06-09 10:11:16 -0400809 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 0xc0) >> 6;
811
Jean Delvaref7906742011-01-12 21:55:09 +0100812 via686a_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 data->alarms =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400814 via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 VIA686A_REG_ALARM1) |
Jean Delvare2ec342e2007-06-09 10:11:16 -0400816 (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 data->last_updated = jiffies;
818 data->valid = 1;
819 }
820
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100821 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 return data;
824}
825
Jingoo Hancd9bb052013-12-03 07:10:29 +0000826static const struct pci_device_id via686a_pci_ids[] = {
Jean Delvarebe8992c2005-05-16 19:00:52 +0200827 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
Guenter Roeck9004ac82012-01-15 06:38:23 -0800828 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
831
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500832static int via686a_device_add(unsigned short address)
Jean Delvare2ec342e2007-06-09 10:11:16 -0400833{
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
Jean Delvareb9acb642009-01-07 16:37:35 +0100842 err = acpi_check_resource_conflict(&res);
843 if (err)
844 goto exit;
845
Jean Delvare2ec342e2007-06-09 10:11:16 -0400846 pdev = platform_device_alloc("via686a", address);
847 if (!pdev) {
848 err = -ENOMEM;
Joe Perches774f7822010-10-20 06:51:51 +0000849 pr_err("Device allocation failed\n");
Jean Delvare2ec342e2007-06-09 10:11:16 -0400850 goto exit;
851 }
852
853 err = platform_device_add_resources(pdev, &res, 1);
854 if (err) {
Joe Perches774f7822010-10-20 06:51:51 +0000855 pr_err("Device resource addition failed (%d)\n", err);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400856 goto exit_device_put;
857 }
858
859 err = platform_device_add(pdev);
860 if (err) {
Joe Perches774f7822010-10-20 06:51:51 +0000861 pr_err("Device addition failed (%d)\n", err);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400862 goto exit_device_put;
863 }
864
865 return 0;
866
867exit_device_put:
868 platform_device_put(pdev);
869exit:
870 return err;
871}
872
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500873static int via686a_pci_probe(struct pci_dev *dev,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200874 const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400876 u16 address, val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Jean Delvare2ec342e2007-06-09 10:11:16 -0400878 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 }
Jean Delvarebe8992c2005-05-16 19:00:52 +0200885 if (PCIBIOS_SUCCESSFUL !=
886 pci_read_config_word(dev, VIA686A_BASE_REG, &val))
887 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Jean Delvare2d8672c2005-07-19 23:56:35 +0200889 address = val & ~(VIA686A_EXTENT - 1);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400890 if (address == 0) {
Guenter Roeckb55f3752013-01-10 10:01:24 -0800891 dev_err(&dev->dev,
892 "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
Jean Delvarebe8992c2005-05-16 19:00:52 +0200893 return -ENODEV;
894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
Jean Delvare2ec342e2007-06-09 10:11:16 -0400896 if (PCIBIOS_SUCCESSFUL !=
897 pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
898 return -ENODEV;
899 if (!(val & 0x0001)) {
900 if (!force_addr) {
Guenter Roeckb55f3752013-01-10 10:01:24 -0800901 dev_warn(&dev->dev,
902 "Sensors disabled, enable with force_addr=0x%x\n",
903 address);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400904 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
913
Jean Delvare2ec342e2007-06-09 10:11:16 -0400914 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
Guenter Roeck9004ac82012-01-15 06:38:23 -0800921 /*
922 * Always return failure here. This is to allow other drivers to bind
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 * 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 */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400926 s_bridge = pci_dev_get(dev);
927 return -ENODEV;
928
929exit_unregister:
930 platform_driver_unregister(&via686a_driver);
931exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return -ENODEV;
933}
934
935static struct pci_driver via686a_pci_driver = {
Jean Delvarebe8992c2005-05-16 19:00:52 +0200936 .name = "via686a",
937 .id_table = via686a_pci_ids,
938 .probe = via686a_pci_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939};
940
941static int __init sm_via686a_init(void)
942{
Jean Delvarebe8992c2005-05-16 19:00:52 +0200943 return pci_register_driver(&via686a_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946static void __exit sm_via686a_exit(void)
947{
948 pci_unregister_driver(&via686a_pci_driver);
949 if (s_bridge != NULL) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400950 platform_device_unregister(pdev);
951 platform_driver_unregister(&via686a_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 pci_dev_put(s_bridge);
953 s_bridge = NULL;
954 }
955}
956
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200957MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
Jean Delvarebe8992c2005-05-16 19:00:52 +0200958 "Mark Studebaker <mdsxyz123@yahoo.com> "
959 "and Bob Dougherty <bobd@stanford.edu>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960MODULE_DESCRIPTION("VIA 686A Sensor device");
961MODULE_LICENSE("GPL");
962
963module_init(sm_via686a_init);
964module_exit(sm_via686a_exit);