blob: 55634110c2f962cc3fe04e81f78b09d8b60a24de [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Guenter Roeck9004ac82012-01-15 06:38:23 -08003 * via686a.c - Part of lm_sensors, Linux kernel modules
4 * for hardware monitoring
5 *
6 * Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
7 * Kyösti Mälkki <kmalkki@cc.hut.fi>,
8 * Mark Studebaker <mdsxyz123@yahoo.com>,
9 * and Bob Dougherty <bobd@stanford.edu>
10 *
11 * (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
12 * <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
Guenter Roeck9004ac82012-01-15 06:38:23 -080013 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
15/*
Guenter Roeck9004ac82012-01-15 06:38:23 -080016 * Supports the Via VT82C686A, VT82C686B south bridges.
17 * Reports all as a 686A.
18 * Warning - only supports a single device.
19 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Joe Perches774f7822010-10-20 06:51:51 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/jiffies.h>
Jean Delvare2ec342e2007-06-09 10:11:16 -040027#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040028#include <linux/hwmon.h>
Jean Delvare1e71a5a2007-06-09 10:11:16 -040029#include <linux/hwmon-sysfs.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040030#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/init.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010032#include <linux/mutex.h>
Jean Delvarea5ebe662006-09-24 21:24:46 +020033#include <linux/sysfs.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010034#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020035#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Guenter Roeck9004ac82012-01-15 06:38:23 -080037/*
38 * If force_addr is set to anything different from 0, we forcibly enable
39 * the device at the given address.
40 */
Jean Delvare02002962005-09-25 16:26:44 +020041static unsigned short force_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042module_param(force_addr, ushort, 0);
43MODULE_PARM_DESC(force_addr,
44 "Initialize the base address of the sensors");
45
Jean Delvare2ec342e2007-06-09 10:11:16 -040046static struct platform_device *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48/*
Guenter Roeck9004ac82012-01-15 06:38:23 -080049 * The Via 686a southbridge has a LM78-like chip integrated on the same IC.
50 * This driver is a customized copy of lm78.c
51 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53/* Many VIA686A constants specified below */
54
55/* Length of ISA address segment */
Jean Delvarebe8992c2005-05-16 19:00:52 +020056#define VIA686A_EXTENT 0x80
57#define VIA686A_BASE_REG 0x70
58#define VIA686A_ENABLE_REG 0x74
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60/* The VIA686A registers */
61/* ins numbered 0-4 */
Jean Delvarebe8992c2005-05-16 19:00:52 +020062#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
63#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
64#define VIA686A_REG_IN(nr) (0x22 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66/* fans numbered 1-2 */
Jean Delvarebe8992c2005-05-16 19:00:52 +020067#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
68#define VIA686A_REG_FAN(nr) (0x28 + (nr))
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/* temps numbered 1-3 */
Jean Delvare563db2f2005-05-17 22:38:57 +020071static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f };
72static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d };
73static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e };
Jean Delvarebe8992c2005-05-16 19:00:52 +020074/* bits 7-6 */
75#define VIA686A_REG_TEMP_LOW1 0x4b
76/* 2 = bits 5-4, 3 = bits 7-6 */
77#define VIA686A_REG_TEMP_LOW23 0x49
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Jean Delvarebe8992c2005-05-16 19:00:52 +020079#define VIA686A_REG_ALARM1 0x41
80#define VIA686A_REG_ALARM2 0x42
81#define VIA686A_REG_FANDIV 0x47
82#define VIA686A_REG_CONFIG 0x40
Guenter Roeck9004ac82012-01-15 06:38:23 -080083/*
84 * The following register sets temp interrupt mode (bits 1-0 for temp1,
85 * 3-2 for temp2, 5-4 for temp3). Modes are:
86 * 00 interrupt stays as long as value is out-of-range
87 * 01 interrupt is cleared once register is read (default)
88 * 10 comparator mode- like 00, but ignores hysteresis
89 * 11 same as 00
90 */
Jean Delvarebe8992c2005-05-16 19:00:52 +020091#define VIA686A_REG_TEMP_MODE 0x4b
Linus Torvalds1da177e2005-04-16 15:20:36 -070092/* We'll just assume that you want to set all 3 simultaneously: */
Jean Delvarebe8992c2005-05-16 19:00:52 +020093#define VIA686A_TEMP_MODE_MASK 0x3F
94#define VIA686A_TEMP_MODE_CONTINUOUS 0x00
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Guenter Roeck9004ac82012-01-15 06:38:23 -080096/*
97 * Conversions. Limit checking is only done on the TO_REG
98 * variants.
99 *
100 ******** VOLTAGE CONVERSIONS (Bob Dougherty) ********
101 * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
102 * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp
103 * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V
104 * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V
105 * voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V
106 * voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V
107 * in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
108 * That is:
109 * volts = (25*regVal+133)*factor
110 * regVal = (volts/factor-133)/25
111 * (These conversions were contributed by Jonathan Teh Soon Yew
112 * <j.teh@iname.com>)
113 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700114static inline u8 IN_TO_REG(long val, int in_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Guenter Roeck9004ac82012-01-15 06:38:23 -0800116 /*
117 * To avoid floating point, we multiply constants by 10 (100 for +12V).
118 * Rounding is done (120500 is actually 133000 - 12500).
119 * Remember that val is expressed in 0.001V/bit, which is why we divide
120 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
121 * for the constants.
122 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700123 if (in_num <= 1)
Guenter Roeck2a844c12013-01-09 08:09:34 -0800124 return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700125 else if (in_num == 2)
Guenter Roeck2a844c12013-01-09 08:09:34 -0800126 return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700127 else if (in_num == 3)
Guenter Roeck2a844c12013-01-09 08:09:34 -0800128 return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 else
Guenter Roeck2a844c12013-01-09 08:09:34 -0800130 return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
131 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700134static inline long IN_FROM_REG(u8 val, int in_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Guenter Roeck9004ac82012-01-15 06:38:23 -0800136 /*
137 * To avoid floating point, we multiply constants by 10 (100 for +12V).
138 * We also multiply them by 1000 because we want 0.001V/bit for the
139 * output value. Rounding is done.
140 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700141 if (in_num <= 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700143 else if (in_num == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700145 else if (in_num == 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
147 else
148 return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
149}
150
151/********* FAN RPM CONVERSIONS ********/
Guenter Roeck9004ac82012-01-15 06:38:23 -0800152/*
153 * Higher register values = slower fans (the fan's strobe gates a counter).
154 * But this chip saturates back at 0, not at 255 like all the other chips.
155 * So, 0 means 0 RPM
156 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static inline u8 FAN_TO_REG(long rpm, int div)
158{
159 if (rpm == 0)
160 return 0;
Guenter Roeck2a844c12013-01-09 08:09:34 -0800161 rpm = clamp_val(rpm, 1, 1000000);
162 return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
Guenter Roeck9004ac82012-01-15 06:38:23 -0800165#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
166 ((val) * (div)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168/******** TEMP CONVERSIONS (Bob Dougherty) *********/
Guenter Roeck9004ac82012-01-15 06:38:23 -0800169/*
170 * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
171 * if(temp<169)
172 * return double(temp)*0.427-32.08;
173 * else if(temp>=169 && temp<=202)
174 * return double(temp)*0.582-58.16;
175 * else
176 * return double(temp)*0.924-127.33;
177 *
178 * A fifth-order polynomial fits the unofficial data (provided by Alex van
179 * Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
180 * numbers on my machine (ie. they agree with what my BIOS tells me).
181 * Here's the fifth-order fit to the 8-bit data:
182 * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
183 * 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
184 *
185 * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
186 * finding my typos in this formula!)
187 *
188 * Alas, none of the elegant function-fit solutions will work because we
189 * aren't allowed to use floating point in the kernel and doing it with
190 * integers doesn't provide enough precision. So we'll do boring old
191 * look-up table stuff. The unofficial data (see below) have effectively
192 * 7-bit resolution (they are rounded to the nearest degree). I'm assuming
193 * that the transfer function of the device is monotonic and smooth, so a
194 * smooth function fit to the data will allow us to get better precision.
195 * I used the 5th-order poly fit described above and solved for
196 * VIA register values 0-255. I *10 before rounding, so we get tenth-degree
197 * precision. (I could have done all 1024 values for our 10-bit readings,
198 * but the function is very linear in the useful range (0-80 deg C), so
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700199 * we'll just use linear interpolation for 10-bit readings.) So, temp_lut
Guenter Roeck9004ac82012-01-15 06:38:23 -0800200 * is the temp at via register values 0-255:
201 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700202static const s16 temp_lut[] = {
Guenter Roeck9004ac82012-01-15 06:38:23 -0800203 -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200204 -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
205 -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
206 -255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
207 -173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
208 -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
209 -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
210 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
211 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
212 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
213 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
214 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
215 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
216 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
217 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
218 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
219 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
220 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
221 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
222 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
223 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
224 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225};
226
Guenter Roeck9004ac82012-01-15 06:38:23 -0800227/*
228 * the original LUT values from Alex van Kaam <darkside@chello.nl>
229 * (for via register values 12-240):
230 * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
231 * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
232 * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
233 * -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,
234 * 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,
235 * 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,
236 * 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,
237 * 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,
238 * 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,
239 * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
240 *
241 *
242 * Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed
243 * an extra term for a good fit to these inverse data!) and then
244 * solving for each temp value from -50 to 110 (the useable range for
245 * this chip). Here's the fit:
246 * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
247 * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
248 * Note that n=161:
249 */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700250static const u8 via_lut[] = {
Guenter Roeck9004ac82012-01-15 06:38:23 -0800251 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200252 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
253 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
254 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
255 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
256 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
257 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
258 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
259 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
260 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
261 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
262 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
263 239, 240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264};
265
Guenter Roeck9004ac82012-01-15 06:38:23 -0800266/*
267 * Converting temps to (8-bit) hyst and over registers
268 * No interpolation here.
269 * The +50 is because the temps start at -50
270 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271static inline u8 TEMP_TO_REG(long val)
272{
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700273 return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 (val < 0 ? val - 500 : val + 500) / 1000 + 50];
275}
276
277/* for 8-bit temperature hyst and over registers */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700278#define TEMP_FROM_REG(val) ((long)temp_lut[val] * 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280/* for 10-bit temperature readings */
281static inline long TEMP_FROM_REG10(u16 val)
282{
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700283 u16 eight_bits = val >> 2;
284 u16 two_bits = val & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 /* no interpolation for these */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700287 if (two_bits == 0 || eight_bits == 255)
288 return TEMP_FROM_REG(eight_bits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 /* do some linear interpolation */
Guenter Roeck088ce2a2013-03-13 16:40:39 -0700291 return (temp_lut[eight_bits] * (4 - two_bits) +
292 temp_lut[eight_bits + 1] * two_bits) * 25;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295#define DIV_FROM_REG(val) (1 << (val))
Guenter Roeck9004ac82012-01-15 06:38:23 -0800296#define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Guenter Roeck9004ac82012-01-15 06:38:23 -0800298/*
299 * For each registered chip, we need to keep some data in memory.
300 * The structure is dynamically allocated.
301 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302struct via686a_data {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400303 unsigned short addr;
304 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700305 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100306 struct mutex update_lock;
Paul Fertser952a11c2021-09-24 22:52:02 +0300307 bool valid; /* true if following fields are valid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 unsigned long last_updated; /* In jiffies */
309
310 u8 in[5]; /* Register value */
311 u8 in_max[5]; /* Register value */
312 u8 in_min[5]; /* Register value */
313 u8 fan[2]; /* Register value */
314 u8 fan_min[2]; /* Register value */
315 u16 temp[3]; /* Register value 10 bit */
316 u8 temp_over[3]; /* Register value */
317 u8 temp_hyst[3]; /* Register value */
318 u8 fan_div[2]; /* Register encoding, shifted right */
319 u16 alarms; /* Register encoding, combined */
320};
321
322static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
323
Jean Delvare2ec342e2007-06-09 10:11:16 -0400324static int via686a_probe(struct platform_device *pdev);
Bill Pemberton281dfd02012-11-19 13:25:51 -0500325static int via686a_remove(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Jean Delvare2ec342e2007-06-09 10:11:16 -0400327static inline int via686a_read_value(struct via686a_data *data, u8 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400329 return inb_p(data->addr + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Jean Delvare2ec342e2007-06-09 10:11:16 -0400332static inline void via686a_write_value(struct via686a_data *data, u8 reg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 u8 value)
334{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400335 outb_p(value, data->addr + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
338static struct via686a_data *via686a_update_device(struct device *dev);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400339static void via686a_init_device(struct via686a_data *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341/* following are the sysfs callback functions */
342
343/* 7 voltage sensors */
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800344static ssize_t in_show(struct device *dev, struct device_attribute *da,
345 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400347 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
348 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
350}
351
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800352static ssize_t in_min_show(struct device *dev, struct device_attribute *da,
353 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400355 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
356 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
358}
359
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800360static ssize_t in_max_show(struct device *dev, struct device_attribute *da,
361 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400363 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
364 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
366}
367
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800368static ssize_t in_min_store(struct device *dev, struct device_attribute *da,
369 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400370 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400371 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
372 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800373 unsigned long val;
374 int err;
375
376 err = kstrtoul(buf, 10, &val);
377 if (err)
378 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100380 mutex_lock(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200381 data->in_min[nr] = IN_TO_REG(val, nr);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400382 via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 data->in_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100384 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return count;
386}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800387static ssize_t in_max_store(struct device *dev, struct device_attribute *da,
388 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400389 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400390 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
391 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800392 unsigned long val;
393 int err;
394
395 err = kstrtoul(buf, 10, &val);
396 if (err)
397 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100399 mutex_lock(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200400 data->in_max[nr] = IN_TO_REG(val, nr);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400401 via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 data->in_max[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100403 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return count;
405}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800407static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
408static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
409static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
410static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
411static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
412static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
413static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
414static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
415static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
416static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
417static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
418static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
419static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
420static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
421static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
423/* 3 temperatures */
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800424static ssize_t temp_show(struct device *dev, struct device_attribute *da,
425 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400427 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
428 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
430}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800431static ssize_t temp_over_show(struct device *dev, struct device_attribute *da,
432 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400434 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
435 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
437}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800438static ssize_t temp_hyst_show(struct device *dev, struct device_attribute *da,
439 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400441 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
442 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
444}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800445static ssize_t temp_over_store(struct device *dev,
446 struct device_attribute *da, const char *buf,
447 size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400448 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400449 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
450 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800451 long val;
452 int err;
453
454 err = kstrtol(buf, 10, &val);
455 if (err)
456 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100458 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 data->temp_over[nr] = TEMP_TO_REG(val);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400460 via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
Jean Delvare563db2f2005-05-17 22:38:57 +0200461 data->temp_over[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100462 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 return count;
464}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800465static ssize_t temp_hyst_store(struct device *dev,
466 struct device_attribute *da, const char *buf,
467 size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400468 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400469 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
470 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800471 long val;
472 int err;
473
474 err = kstrtol(buf, 10, &val);
475 if (err)
476 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100478 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 data->temp_hyst[nr] = TEMP_TO_REG(val);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400480 via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
Jean Delvare563db2f2005-05-17 22:38:57 +0200481 data->temp_hyst[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100482 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return count;
484}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800486static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
487static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_over, 0);
488static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_hyst, 0);
489static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
490static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_over, 1);
491static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_hyst, 1);
492static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
493static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_over, 2);
494static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_hyst, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496/* 2 Fans */
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800497static ssize_t fan_show(struct device *dev, struct device_attribute *da,
498 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400500 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
501 int nr = attr->index;
Jean Delvarebe8992c2005-05-16 19:00:52 +0200502 return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
Guenter Roeck9004ac82012-01-15 06:38:23 -0800503 DIV_FROM_REG(data->fan_div[nr])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800505static ssize_t fan_min_show(struct device *dev, struct device_attribute *da,
506 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400508 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
509 int nr = attr->index;
Jean Delvarebe8992c2005-05-16 19:00:52 +0200510 return sprintf(buf, "%d\n",
Guenter Roeck9004ac82012-01-15 06:38:23 -0800511 FAN_FROM_REG(data->fan_min[nr],
512 DIV_FROM_REG(data->fan_div[nr])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800514static ssize_t fan_div_show(struct device *dev, struct device_attribute *da,
515 char *buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400517 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
518 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800519 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800521static ssize_t fan_min_store(struct device *dev, struct device_attribute *da,
522 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400523 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400524 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
525 int nr = attr->index;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800526 unsigned long val;
527 int err;
528
529 err = kstrtoul(buf, 10, &val);
530 if (err)
531 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100533 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare2ec342e2007-06-09 10:11:16 -0400535 via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100536 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return count;
538}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800539static ssize_t fan_div_store(struct device *dev, struct device_attribute *da,
540 const char *buf, size_t count) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400541 struct via686a_data *data = dev_get_drvdata(dev);
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400542 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
543 int nr = attr->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 int old;
Guenter Roeck9004ac82012-01-15 06:38:23 -0800545 unsigned long val;
546 int err;
547
548 err = kstrtoul(buf, 10, &val);
549 if (err)
550 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100552 mutex_lock(&data->update_lock);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400553 old = via686a_read_value(data, VIA686A_REG_FANDIV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 data->fan_div[nr] = DIV_TO_REG(val);
555 old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400556 via686a_write_value(data, VIA686A_REG_FANDIV, old);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100557 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 return count;
559}
560
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800561static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
562static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
563static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
564static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
565static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
566static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568/* Alarms */
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100569static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
Guenter Roeck9004ac82012-01-15 06:38:23 -0800570 char *buf)
571{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 struct via686a_data *data = via686a_update_device(dev);
Jean Delvare68188ba2005-05-16 18:52:38 +0200573 return sprintf(buf, "%u\n", data->alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
Guenter Roeck9004ac82012-01-15 06:38:23 -0800575
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100576static DEVICE_ATTR_RO(alarms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800578static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100579 char *buf)
580{
581 int bitnr = to_sensor_dev_attr(attr)->index;
582 struct via686a_data *data = via686a_update_device(dev);
583 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
584}
Guenter Roeck9d5bc092019-01-22 14:12:25 -0800585static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
586static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
587static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
588static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
589static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8);
590static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
591static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 11);
592static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 15);
593static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
594static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
Jean Delvare13ff05e2008-01-06 15:42:04 +0100595
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100596static ssize_t name_show(struct device *dev, struct device_attribute
Jean Delvare2ec342e2007-06-09 10:11:16 -0400597 *devattr, char *buf)
598{
599 struct via686a_data *data = dev_get_drvdata(dev);
600 return sprintf(buf, "%s\n", data->name);
601}
Julia Lawall8b2bd7a2016-12-22 13:05:09 +0100602static DEVICE_ATTR_RO(name);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400603
Jean Delvarea5ebe662006-09-24 21:24:46 +0200604static struct attribute *via686a_attributes[] = {
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400605 &sensor_dev_attr_in0_input.dev_attr.attr,
606 &sensor_dev_attr_in1_input.dev_attr.attr,
607 &sensor_dev_attr_in2_input.dev_attr.attr,
608 &sensor_dev_attr_in3_input.dev_attr.attr,
609 &sensor_dev_attr_in4_input.dev_attr.attr,
610 &sensor_dev_attr_in0_min.dev_attr.attr,
611 &sensor_dev_attr_in1_min.dev_attr.attr,
612 &sensor_dev_attr_in2_min.dev_attr.attr,
613 &sensor_dev_attr_in3_min.dev_attr.attr,
614 &sensor_dev_attr_in4_min.dev_attr.attr,
615 &sensor_dev_attr_in0_max.dev_attr.attr,
616 &sensor_dev_attr_in1_max.dev_attr.attr,
617 &sensor_dev_attr_in2_max.dev_attr.attr,
618 &sensor_dev_attr_in3_max.dev_attr.attr,
619 &sensor_dev_attr_in4_max.dev_attr.attr,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100620 &sensor_dev_attr_in0_alarm.dev_attr.attr,
621 &sensor_dev_attr_in1_alarm.dev_attr.attr,
622 &sensor_dev_attr_in2_alarm.dev_attr.attr,
623 &sensor_dev_attr_in3_alarm.dev_attr.attr,
624 &sensor_dev_attr_in4_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200625
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400626 &sensor_dev_attr_temp1_input.dev_attr.attr,
627 &sensor_dev_attr_temp2_input.dev_attr.attr,
628 &sensor_dev_attr_temp3_input.dev_attr.attr,
629 &sensor_dev_attr_temp1_max.dev_attr.attr,
630 &sensor_dev_attr_temp2_max.dev_attr.attr,
631 &sensor_dev_attr_temp3_max.dev_attr.attr,
632 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
633 &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
634 &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100635 &sensor_dev_attr_temp1_alarm.dev_attr.attr,
636 &sensor_dev_attr_temp2_alarm.dev_attr.attr,
637 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200638
Jean Delvare1e71a5a2007-06-09 10:11:16 -0400639 &sensor_dev_attr_fan1_input.dev_attr.attr,
640 &sensor_dev_attr_fan2_input.dev_attr.attr,
641 &sensor_dev_attr_fan1_min.dev_attr.attr,
642 &sensor_dev_attr_fan2_min.dev_attr.attr,
643 &sensor_dev_attr_fan1_div.dev_attr.attr,
644 &sensor_dev_attr_fan2_div.dev_attr.attr,
Jean Delvare13ff05e2008-01-06 15:42:04 +0100645 &sensor_dev_attr_fan1_alarm.dev_attr.attr,
646 &sensor_dev_attr_fan2_alarm.dev_attr.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200647
648 &dev_attr_alarms.attr,
Jean Delvare2ec342e2007-06-09 10:11:16 -0400649 &dev_attr_name.attr,
Jean Delvarea5ebe662006-09-24 21:24:46 +0200650 NULL
651};
652
653static const struct attribute_group via686a_group = {
654 .attrs = via686a_attributes,
655};
656
Jean Delvare2ec342e2007-06-09 10:11:16 -0400657static struct platform_driver via686a_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100658 .driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100659 .name = "via686a",
660 },
Jean Delvare2ec342e2007-06-09 10:11:16 -0400661 .probe = via686a_probe,
Bill Pemberton9e5e9b72012-11-19 13:21:20 -0500662 .remove = via686a_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663};
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665/* This is called when the module is loaded */
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500666static int via686a_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 struct via686a_data *data;
Jean Delvare2ec342e2007-06-09 10:11:16 -0400669 struct resource *res;
670 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 /* Reserve the ISA region */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400673 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700674 if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT,
675 via686a_driver.driver.name)) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400676 dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
677 (unsigned long)res->start, (unsigned long)res->end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 return -ENODEV;
679 }
680
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700681 data = devm_kzalloc(&pdev->dev, sizeof(struct via686a_data),
682 GFP_KERNEL);
683 if (!data)
684 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Jean Delvare2ec342e2007-06-09 10:11:16 -0400686 platform_set_drvdata(pdev, data);
687 data->addr = res->start;
688 data->name = "via686a";
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100689 mutex_init(&data->update_lock);
Jean Delvarebe8992c2005-05-16 19:00:52 +0200690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 /* Initialize the VIA686A chip */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400692 via686a_init_device(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 /* Register sysfs hooks */
Guenter Roeck9004ac82012-01-15 06:38:23 -0800695 err = sysfs_create_group(&pdev->dev.kobj, &via686a_group);
696 if (err)
Guenter Roeckfd55bc02012-06-02 11:35:54 -0700697 return err;
Jean Delvarea5ebe662006-09-24 21:24:46 +0200698
Tony Jones1beeffe2007-08-20 13:46:20 -0700699 data->hwmon_dev = hwmon_device_register(&pdev->dev);
700 if (IS_ERR(data->hwmon_dev)) {
701 err = PTR_ERR(data->hwmon_dev);
Jean Delvarea5ebe662006-09-24 21:24:46 +0200702 goto exit_remove_files;
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400703 }
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return 0;
706
Jean Delvarea5ebe662006-09-24 21:24:46 +0200707exit_remove_files:
Jean Delvare2ec342e2007-06-09 10:11:16 -0400708 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 return err;
710}
711
Bill Pemberton281dfd02012-11-19 13:25:51 -0500712static int via686a_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400714 struct via686a_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Tony Jones1beeffe2007-08-20 13:46:20 -0700716 hwmon_device_unregister(data->hwmon_dev);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400717 sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
Mark M. Hoffman943b0832005-07-15 21:39:18 -0400718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return 0;
720}
721
Jean Delvaref7906742011-01-12 21:55:09 +0100722static void via686a_update_fan_div(struct via686a_data *data)
723{
724 int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
725 data->fan_div[0] = (reg >> 4) & 0x03;
726 data->fan_div[1] = reg >> 6;
727}
728
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500729static void via686a_init_device(struct via686a_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 u8 reg;
732
733 /* Start monitoring */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400734 reg = via686a_read_value(data, VIA686A_REG_CONFIG);
735 via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
737 /* Configure temp interrupt mode for continuous-interrupt operation */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400738 reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
739 via686a_write_value(data, VIA686A_REG_TEMP_MODE,
Jean Delvare58fe0802007-06-09 10:11:16 -0400740 (reg & ~VIA686A_TEMP_MODE_MASK)
741 | VIA686A_TEMP_MODE_CONTINUOUS);
Jean Delvaref7906742011-01-12 21:55:09 +0100742
743 /* Pre-read fan clock divisor values */
744 via686a_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747static struct via686a_data *via686a_update_device(struct device *dev)
748{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400749 struct via686a_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 int i;
751
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100752 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
755 || !data->valid) {
756 for (i = 0; i <= 4; i++) {
757 data->in[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400758 via686a_read_value(data, VIA686A_REG_IN(i));
759 data->in_min[i] = via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 VIA686A_REG_IN_MIN
761 (i));
762 data->in_max[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400763 via686a_read_value(data, VIA686A_REG_IN_MAX(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
765 for (i = 1; i <= 2; i++) {
766 data->fan[i - 1] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400767 via686a_read_value(data, VIA686A_REG_FAN(i));
768 data->fan_min[i - 1] = via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 VIA686A_REG_FAN_MIN(i));
770 }
771 for (i = 0; i <= 2; i++) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400772 data->temp[i] = via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200773 VIA686A_REG_TEMP[i]) << 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 data->temp_over[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400775 via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200776 VIA686A_REG_TEMP_OVER[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 data->temp_hyst[i] =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400778 via686a_read_value(data,
Jean Delvare563db2f2005-05-17 22:38:57 +0200779 VIA686A_REG_TEMP_HYST[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
Guenter Roeck9004ac82012-01-15 06:38:23 -0800781 /*
782 * add in lower 2 bits
783 * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
784 * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
785 * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400787 data->temp[0] |= (via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 VIA686A_REG_TEMP_LOW1)
789 & 0xc0) >> 6;
790 data->temp[1] |=
Jean Delvare2ec342e2007-06-09 10:11:16 -0400791 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 0x30) >> 4;
793 data->temp[2] |=
Jean Delvare2ec342e2007-06-09 10:11:16 -0400794 (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 0xc0) >> 6;
796
Jean Delvaref7906742011-01-12 21:55:09 +0100797 via686a_update_fan_div(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 data->alarms =
Jean Delvare2ec342e2007-06-09 10:11:16 -0400799 via686a_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 VIA686A_REG_ALARM1) |
Jean Delvare2ec342e2007-06-09 10:11:16 -0400801 (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 data->last_updated = jiffies;
Paul Fertser952a11c2021-09-24 22:52:02 +0300803 data->valid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
805
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100806 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 return data;
809}
810
Jingoo Hancd9bb052013-12-03 07:10:29 +0000811static const struct pci_device_id via686a_pci_ids[] = {
Jean Delvarebe8992c2005-05-16 19:00:52 +0200812 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
Guenter Roeck9004ac82012-01-15 06:38:23 -0800813 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
816
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500817static int via686a_device_add(unsigned short address)
Jean Delvare2ec342e2007-06-09 10:11:16 -0400818{
819 struct resource res = {
820 .start = address,
821 .end = address + VIA686A_EXTENT - 1,
822 .name = "via686a",
823 .flags = IORESOURCE_IO,
824 };
825 int err;
826
Jean Delvareb9acb642009-01-07 16:37:35 +0100827 err = acpi_check_resource_conflict(&res);
828 if (err)
829 goto exit;
830
Jean Delvare2ec342e2007-06-09 10:11:16 -0400831 pdev = platform_device_alloc("via686a", address);
832 if (!pdev) {
833 err = -ENOMEM;
Joe Perches774f7822010-10-20 06:51:51 +0000834 pr_err("Device allocation failed\n");
Jean Delvare2ec342e2007-06-09 10:11:16 -0400835 goto exit;
836 }
837
838 err = platform_device_add_resources(pdev, &res, 1);
839 if (err) {
Joe Perches774f7822010-10-20 06:51:51 +0000840 pr_err("Device resource addition failed (%d)\n", err);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400841 goto exit_device_put;
842 }
843
844 err = platform_device_add(pdev);
845 if (err) {
Joe Perches774f7822010-10-20 06:51:51 +0000846 pr_err("Device addition failed (%d)\n", err);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400847 goto exit_device_put;
848 }
849
850 return 0;
851
852exit_device_put:
853 platform_device_put(pdev);
854exit:
855 return err;
856}
857
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500858static int via686a_pci_probe(struct pci_dev *dev,
Jean Delvarebe8992c2005-05-16 19:00:52 +0200859 const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Jean Delvare2ec342e2007-06-09 10:11:16 -0400861 u16 address, val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Jean Delvare2ec342e2007-06-09 10:11:16 -0400863 if (force_addr) {
864 address = force_addr & ~(VIA686A_EXTENT - 1);
865 dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
866 if (PCIBIOS_SUCCESSFUL !=
867 pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
868 return -ENODEV;
869 }
Jean Delvarebe8992c2005-05-16 19:00:52 +0200870 if (PCIBIOS_SUCCESSFUL !=
871 pci_read_config_word(dev, VIA686A_BASE_REG, &val))
872 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Jean Delvare2d8672c2005-07-19 23:56:35 +0200874 address = val & ~(VIA686A_EXTENT - 1);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400875 if (address == 0) {
Guenter Roeckb55f3752013-01-10 10:01:24 -0800876 dev_err(&dev->dev,
877 "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
Jean Delvarebe8992c2005-05-16 19:00:52 +0200878 return -ENODEV;
879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Jean Delvare2ec342e2007-06-09 10:11:16 -0400881 if (PCIBIOS_SUCCESSFUL !=
882 pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
883 return -ENODEV;
884 if (!(val & 0x0001)) {
885 if (!force_addr) {
Guenter Roeckb55f3752013-01-10 10:01:24 -0800886 dev_warn(&dev->dev,
887 "Sensors disabled, enable with force_addr=0x%x\n",
888 address);
Jean Delvare2ec342e2007-06-09 10:11:16 -0400889 return -ENODEV;
890 }
891
892 dev_warn(&dev->dev, "Enabling sensors\n");
893 if (PCIBIOS_SUCCESSFUL !=
894 pci_write_config_word(dev, VIA686A_ENABLE_REG,
895 val | 0x0001))
896 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
898
Jean Delvare2ec342e2007-06-09 10:11:16 -0400899 if (platform_driver_register(&via686a_driver))
900 goto exit;
901
902 /* Sets global pdev as a side effect */
903 if (via686a_device_add(address))
904 goto exit_unregister;
905
Guenter Roeck9004ac82012-01-15 06:38:23 -0800906 /*
907 * Always return failure here. This is to allow other drivers to bind
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 * to this pci device. We don't really want to have control over the
909 * pci device, we only wanted to read as few register values from it.
910 */
Jean Delvare2ec342e2007-06-09 10:11:16 -0400911 s_bridge = pci_dev_get(dev);
912 return -ENODEV;
913
914exit_unregister:
915 platform_driver_unregister(&via686a_driver);
916exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return -ENODEV;
918}
919
920static struct pci_driver via686a_pci_driver = {
Jean Delvarebe8992c2005-05-16 19:00:52 +0200921 .name = "via686a",
922 .id_table = via686a_pci_ids,
923 .probe = via686a_pci_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924};
925
926static int __init sm_via686a_init(void)
927{
Jean Delvarebe8992c2005-05-16 19:00:52 +0200928 return pci_register_driver(&via686a_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
930
931static void __exit sm_via686a_exit(void)
932{
933 pci_unregister_driver(&via686a_pci_driver);
934 if (s_bridge != NULL) {
Jean Delvare2ec342e2007-06-09 10:11:16 -0400935 platform_device_unregister(pdev);
936 platform_driver_unregister(&via686a_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 pci_dev_put(s_bridge);
938 s_bridge = NULL;
939 }
940}
941
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200942MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
Jean Delvarebe8992c2005-05-16 19:00:52 +0200943 "Mark Studebaker <mdsxyz123@yahoo.com> "
944 "and Bob Dougherty <bobd@stanford.edu>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945MODULE_DESCRIPTION("VIA 686A Sensor device");
946MODULE_LICENSE("GPL");
947
948module_init(sm_via686a_init);
949module_exit(sm_via686a_exit);