root/lm-sensors/trunk/kernel/chips/via686a.c @ 914

Revision 914, 32.8 KB (checked in by bobd, 13 years ago)

(bob dougherty) Fixed typos in temp-conversion polynomial fit formula. (thanks to Uwe Anderson for finding them.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    via686a.c - Part of lm_sensors, Linux kernel modules
3                for hardware monitoring
4               
5    Copyright (c) 1998, 1999,2000  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    (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
10    <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27#include <linux/version.h>
28#include <linux/module.h>
29#include <linux/malloc.h>
30#include <linux/proc_fs.h>
31#include <linux/ioport.h>
32#include <linux/sysctl.h>
33#include <linux/pci.h>
34#include <asm/errno.h>
35#include <asm/io.h>
36#include <linux/types.h>
37#include <linux/i2c.h>
38#include "version.h"
39#include "i2c-isa.h"
40#include "sensors.h"
41#include <linux/init.h>
42
43#ifndef PCI_DEVICE_ID_VIA_82C686_4
44#define PCI_DEVICE_ID_VIA_82C686_4 0x3057
45#endif
46
47#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1))
48#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
49#endif
50
51#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
52#define THIS_MODULE NULL
53#endif
54
55/* Addresses to scan.
56   Note that we can't determine the ISA address until we have initialized
57   our module */
58static unsigned short normal_i2c[] = { SENSORS_I2C_END };
59static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
60static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
61static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
62
63/* Insmod parameters */
64SENSORS_INSMOD_1(via686a);
65
66/*
67   The Via 686a southbridge has a LM78-like chip integrated on the same IC.
68   This driver is a customized copy of lm78.c
69*/
70
71/* Many VIA686A constants specified below */
72
73/* Length of ISA address segment */
74#define VIA686A_EXTENT 0x80
75#define VIA686A_BASE_REG 0x70
76#define VIA686A_ENABLE_REG 0x74
77
78/* The VIA686A registers */
79/* ins numbered 0-4 */
80#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
81#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
82#define VIA686A_REG_IN(nr)     (0x22 + (nr))
83
84/* fans numbered 1-2 */
85#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
86#define VIA686A_REG_FAN(nr)     (0x28 + (nr))
87
88// the following values are as speced by VIA:
89static const u8 regtemp[] = { 0x20, 0x21, 0x1f };
90static const u8 regover[] = { 0x39, 0x3d, 0x1d };
91static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e };
92
93/* temps numbered 1-3 */
94#define VIA686A_REG_TEMP(nr)            (regtemp[(nr) - 1])
95#define VIA686A_REG_TEMP_OVER(nr)       (regover[(nr) - 1])
96#define VIA686A_REG_TEMP_HYST(nr)       (reghyst[(nr) - 1])
97#define VIA686A_REG_TEMP_LOW1   0x4b    // bits 7-6
98#define VIA686A_REG_TEMP_LOW23  0x49    // 2 = bits 5-4, 3 = bits 7-6
99
100#define VIA686A_REG_ALARM1 0x41
101#define VIA686A_REG_ALARM2 0x42
102#define VIA686A_REG_FANDIV 0x47
103#define VIA686A_REG_CONFIG 0x40
104// The following register sets temp interrupt mode (bits 1-0 for temp1,
105// 3-2 for temp2, 5-4 for temp3).  Modes are:
106//    00 interrupt stays as long as value is out-of-range
107//    01 interrupt is cleared once register is read (default)
108//    10 comparator mode- like 00, but ignores hysteresis
109//    11 same as 00
110#define VIA686A_REG_TEMP_MODE 0x4b
111// We'll just assume that you want to set all 3 simulataneously:
112#define VIA686A_TEMP_MODE_MASK 0x3F
113#define VIA686A_TEMP_MODE_CONTINUOUS (0x00)
114
115/* Conversions. Rounding and limit checking is only done on the TO_REG
116   variants. */
117
118/********* VOLTAGE CONVERSIONS (Bob Dougherty) ********/
119// From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
120// voltagefactor[0]=1.25/2628; (2628/1.25=2102.4)   // Vccp
121// voltagefactor[1]=1.25/2628; (2628/1.25=2102.4)   // +2.5V
122// voltagefactor[2]=1.67/2628; (2628/1.67=1573.7)   // +3.3V
123// voltagefactor[3]=2.6/2628;  (2628/2.60=1010.8)   // +5V
124// voltagefactor[4]=6.3/2628;  (2628/6.30=417.14)   // +12V
125// in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
126// That is:
127// volts = (25*regVal+133)*factor
128// regVal = (volts/factor-133)/25
129// (These conversions were contributed by Jonathan Teh Soon Yew
130// <j.teh@iname.com>)
131//
132// These get us close, but they don't completely agree with what my BIOS
133// says- they are all a bit low.  But, it all we have to go on...
134extern inline u8 IN_TO_REG(long val, int inNum)
135{
136        // to avoid floating point, we multiply everything by 100.
137        // val is guaranteed to be positive, so we can achieve the effect of
138        // rounding by (...*10+5)/10.  Note that the *10 is hidden in the
139        // /250 (which should really be /2500).
140        // At the end, we need to /100 because we *100 everything and we need
141        // to /10 because of the rounding thing, so we /1000. 
142        if (inNum <= 1)
143                return (u8)
144                    SENSORS_LIMIT(((val * 210240 - 13300) / 250 + 5) / 1000, 
145                                  0, 255);
146        else if (inNum == 2)
147                return (u8)
148                    SENSORS_LIMIT(((val * 157370 - 13300) / 250 + 5) / 1000, 
149                                  0, 255);
150        else if (inNum == 3)
151                return (u8)
152                    SENSORS_LIMIT(((val * 101080 - 13300) / 250 + 5) / 1000, 
153                                  0, 255);
154        else
155                return (u8) SENSORS_LIMIT(((val * 41714 - 13300) / 250 + 5)
156                                          / 1000, 0, 255);
157}
158
159extern inline long IN_FROM_REG(u8 val, int inNum)
160{
161        // to avoid floating point, we multiply everything by 100.
162        // val is guaranteed to be positive, so we can achieve the effect of
163        // rounding by adding 0.5.  Or, to avoid fp math, we do (...*10+5)/10.
164        // We need to scale with *100 anyway, so no need to /100 at the end.
165        if (inNum <= 1)
166                return (long) (((250000 * val + 13300) / 210240 * 10 + 5) /10);
167        else if (inNum == 2)
168                return (long) (((250000 * val + 13300) / 157370 * 10 + 5) /10);
169        else if (inNum == 3)
170                return (long) (((250000 * val + 13300) / 101080 * 10 + 5) /10);
171        else
172                return (long) (((250000 * val + 13300) / 41714 * 10 + 5) /10);
173}
174
175/********* FAN RPM CONVERSIONS ********/
176// Higher register values = slower fans (the fan's strobe gates a counter).
177// But this chip saturates back at 0, not at 255 like all the other chips.
178// So, 0 means 0 RPM
179extern inline u8 FAN_TO_REG(long rpm, int div)
180{
181        if (rpm == 0)
182                return 0;
183        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
184        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
185}
186
187#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div)))
188
189/******** TEMP CONVERSIONS (Bob Dougherty) *********/
190// linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
191//      if(temp<169)
192//              return double(temp)*0.427-32.08;
193//      else if(temp>=169 && temp<=202)
194//              return double(temp)*0.582-58.16;
195//      else
196//              return double(temp)*0.924-127.33;
197//
198// A fifth-order polynomial fits the unofficial data (provided by Alex van
199// Kaam <darkside@chello.nl>) a bit better.  It also give more reasonable
200// numbers on my machine (ie. they agree with what my BIOS tells me). 
201// Here's the fifth-order fit to the 8-bit data:
202// temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
203//        2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
204//
205// (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
206// finding my typos in this formula!)
207//
208// Alas, none of the elegant function-fit solutions will work because we
209// aren't allowed to use floating point in the kernel and doing it with
210// integers doesn't rpovide enough precision.  So we'll do boring old
211// look-up table stuff.  The unofficial data (see below) have effectively
212// 7-bit resolution (they are rounded to the nearest degree).  I'm assuming
213// that the transfer function of the device is monotonic and smooth, so a
214// smooth function fit to the data will allow us to get better precision. 
215// I used the 5th-order poly fit described above and solved for
216// VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
217// precision.  (I could have done all 1024 values for our 10-bit readings,
218// but the function is very linear in the useful range (0-80 deg C), so
219// we'll just use linear interpolation for 10-bit readings.)  So, tempLUT
220// is the temp at via register values 0-255:
221static const long tempLUT[] =
222    { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
223            -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
224            -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
225            -255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
226            -173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
227            -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
228            -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
229            20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
230            88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
231            142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
232            193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
233            245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
234            299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
235            353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
236            409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
237            469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
238            538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
239            621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
240            728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
241            870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
242            1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
243            1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
244};
245
246/* the original LUT values from Alex van Kaam <darkside@chello.nl>
247   (for via register values 12-240):
248{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
249-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
250-15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
251-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,
25212,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22,
25322,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33,
25433,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,
25545,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60,
25661,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84,
25785,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
258*/
259
260// Here's the reverse LUT.  I got it by doing a 6-th order poly fit (needed
261// an extra term for a good fit to these inverse data!) and then
262// solving for each temp value from -50 to 110 (the useable range for
263// this chip).  Here's the fit:
264// viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
265// - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
266// Note that n=161:
267static const u8 viaLUT[] =
268    { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
269            23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
270            41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
271            69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
272            103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
273            131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
274            158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
275            182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
276            200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
277            214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
278            225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
279            233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
280            239, 240
281};
282
283/* Converting temps to (8-bit) hyst and over registers */
284// No interpolation here.  Just check the limits and go.
285// The +5 effectively rounds off properly and the +50 is because
286// the temps start at -50
287extern inline u8 TEMP_TO_REG(long val)
288{
289        return (u8)
290            SENSORS_LIMIT(viaLUT[((val <= -500) ? 0 : (val >= 1100) ? 160 : 
291                                  ((val + 5) / 10 + 50))], 0, 255);
292}
293
294/* for 8-bit temperature hyst and over registers */
295// The temp values are already *10, so we don't need to do that.
296// But we _will_ round these off to the nearest degree with (...*10+5)/10
297#define TEMP_FROM_REG(val) ((tempLUT[(val)]*10+5)/10)
298
299/* for 10-bit temperature readings */
300// You might _think_ this is too long to inline, but's it's really only
301// called once...
302extern inline long TEMP_FROM_REG10(u16 val)
303{
304        // the temp values are already *10, so we don't need to do that.
305        long temp;
306        u16 eightBits = val >> 2;
307        u16 twoBits = val & 3;
308
309        // handle the extremes first (they won't interpolate well! ;-)
310        if (val == 0)
311                return (long) tempLUT[0];
312        if (val == 1023)
313                return (long) tempLUT[255];
314
315        if (twoBits == 0)
316                return (long) tempLUT[eightBits];
317        else {
318                // do some interpolation by multipying the lower and upper
319                // bounds by 25, 50 or 75, then /100.
320                temp = ((25 * (4 - twoBits)) * tempLUT[eightBits]
321                        + (25 * twoBits) * tempLUT[eightBits + 1]);
322                // increase the magnitude by 50 to achieve rounding.
323                if (temp > 0)
324                        temp += 50;
325                else
326                        temp -= 50;
327                return (temp / 100);
328        }
329}
330
331#define ALARMS_FROM_REG(val) (val)
332
333#define DIV_FROM_REG(val) (1 << (val))
334#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
335
336/* Initial limits */
337#define VIA686A_INIT_IN_0 200
338#define VIA686A_INIT_IN_1 250
339#define VIA686A_INIT_IN_2 330
340#define VIA686A_INIT_IN_3 500
341#define VIA686A_INIT_IN_4 1200
342
343#define VIA686A_INIT_IN_PERCENTAGE 10
344
345#define VIA686A_INIT_IN_MIN_0 (VIA686A_INIT_IN_0 - VIA686A_INIT_IN_0 \
346        * VIA686A_INIT_IN_PERCENTAGE / 100)
347#define VIA686A_INIT_IN_MAX_0 (VIA686A_INIT_IN_0 + VIA686A_INIT_IN_0 \
348        * VIA686A_INIT_IN_PERCENTAGE / 100)
349#define VIA686A_INIT_IN_MIN_1 (VIA686A_INIT_IN_1 - VIA686A_INIT_IN_1 \
350        * VIA686A_INIT_IN_PERCENTAGE / 100)
351#define VIA686A_INIT_IN_MAX_1 (VIA686A_INIT_IN_1 + VIA686A_INIT_IN_1 \
352        * VIA686A_INIT_IN_PERCENTAGE / 100)
353#define VIA686A_INIT_IN_MIN_2 (VIA686A_INIT_IN_2 - VIA686A_INIT_IN_2 \
354        * VIA686A_INIT_IN_PERCENTAGE / 100)
355#define VIA686A_INIT_IN_MAX_2 (VIA686A_INIT_IN_2 + VIA686A_INIT_IN_2 \
356        * VIA686A_INIT_IN_PERCENTAGE / 100)
357#define VIA686A_INIT_IN_MIN_3 (VIA686A_INIT_IN_3 - VIA686A_INIT_IN_3 \
358        * VIA686A_INIT_IN_PERCENTAGE / 100)
359#define VIA686A_INIT_IN_MAX_3 (VIA686A_INIT_IN_3 + VIA686A_INIT_IN_3 \
360        * VIA686A_INIT_IN_PERCENTAGE / 100)
361#define VIA686A_INIT_IN_MIN_4 (VIA686A_INIT_IN_4 - VIA686A_INIT_IN_4 \
362        * VIA686A_INIT_IN_PERCENTAGE / 100)
363#define VIA686A_INIT_IN_MAX_4 (VIA686A_INIT_IN_4 + VIA686A_INIT_IN_4 \
364        * VIA686A_INIT_IN_PERCENTAGE / 100)
365
366#define VIA686A_INIT_FAN_MIN    3000
367
368#define VIA686A_INIT_TEMP_OVER 600
369#define VIA686A_INIT_TEMP_HYST 500
370
371#ifdef MODULE
372extern int init_module(void);
373extern int cleanup_module(void);
374#endif                          /* MODULE */
375
376/* This module may seem overly long and complicated. In fact, it is not so
377   bad. Quite a lot of bookkeeping is done. A real driver can often cut
378   some corners. */
379
380/* For each registered VIA686A, we need to keep some data in memory. That
381   data is pointed to by via686a_list[NR]->data. The structure itself is
382   dynamically allocated, at the same time when a new via686a client is
383   allocated. */
384struct via686a_data {
385        struct semaphore lock;
386        int sysctl_id;
387
388        struct semaphore update_lock;
389        char valid;             /* !=0 if following fields are valid */
390        unsigned long last_updated;     /* In jiffies */
391
392        u8 in[5];               /* Register value */
393        u8 in_max[5];           /* Register value */
394        u8 in_min[5];           /* Register value */
395        u8 fan[2];              /* Register value */
396        u8 fan_min[2];          /* Register value */
397        u16 temp[3];            /* Register value 10 bit */
398        u8 temp_over[3];        /* Register value */
399        u8 temp_hyst[3];        /* Register value */
400        u8 fan_div[2];          /* Register encoding, shifted right */
401        u16 alarms;             /* Register encoding, combined */
402};
403
404
405#ifdef MODULE
406static
407#else
408extern
409#endif
410int __init sensors_via686a_init(void);
411static int __init via686a_cleanup(void);
412
413static int via686a_attach_adapter(struct i2c_adapter *adapter);
414static int via686a_detect(struct i2c_adapter *adapter, int address,
415                          unsigned short flags, int kind);
416static int via686a_detach_client(struct i2c_client *client);
417static int via686a_command(struct i2c_client *client, unsigned int cmd,
418                           void *arg);
419static void via686a_inc_use(struct i2c_client *client);
420static void via686a_dec_use(struct i2c_client *client);
421
422static int via686a_read_value(struct i2c_client *client, u8 register);
423static void via686a_write_value(struct i2c_client *client, u8 register,
424                                u8 value);
425static void via686a_update_client(struct i2c_client *client);
426static void via686a_init_client(struct i2c_client *client);
427static int via686a_find(int *address);
428
429
430static void via686a_in(struct i2c_client *client, int operation,
431                       int ctl_name, int *nrels_mag, long *results);
432static void via686a_fan(struct i2c_client *client, int operation,
433                        int ctl_name, int *nrels_mag, long *results);
434static void via686a_temp(struct i2c_client *client, int operation,
435                         int ctl_name, int *nrels_mag, long *results);
436static void via686a_alarms(struct i2c_client *client, int operation,
437                           int ctl_name, int *nrels_mag, long *results);
438static void via686a_fan_div(struct i2c_client *client, int operation,
439                            int ctl_name, int *nrels_mag, long *results);
440
441static int via686a_id = 0;
442
443/* The driver. I choose to use type i2c_driver, as at is identical to both
444   smbus_driver and isa_driver, and clients could be of either kind */
445static struct i2c_driver via686a_driver = {
446        /* name */ "VIA 686A",
447        /* id */ I2C_DRIVERID_VIA686A,
448        /* flags */ I2C_DF_NOTIFY,
449        /* attach_adapter */ &via686a_attach_adapter,
450        /* detach_client */ &via686a_detach_client,
451        /* command */ &via686a_command,
452        /* inc_use */ &via686a_inc_use,
453        /* dec_use */ &via686a_dec_use
454};
455
456/* Used by via686a_init/cleanup */
457static int __initdata via686a_initialized = 0;
458
459/* The /proc/sys entries */
460/* These files are created for each detected VIA686A. This is just a template;
461   though at first sight, you might think we could use a statically
462   allocated list, we need some way to get back to the parent - which
463   is done through one of the 'extra' fields which are initialized
464   when a new copy is allocated. */
465static ctl_table via686a_dir_table_template[] = {
466        {VIA686A_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
467         &sensors_sysctl_real, NULL, &via686a_in},
468        {VIA686A_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
469         &sensors_sysctl_real, NULL, &via686a_in},
470        {VIA686A_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
471         &sensors_sysctl_real, NULL, &via686a_in},
472        {VIA686A_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
473         &sensors_sysctl_real, NULL, &via686a_in},
474        {VIA686A_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
475         &sensors_sysctl_real, NULL, &via686a_in},
476        {VIA686A_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
477         &sensors_sysctl_real, NULL, &via686a_fan},
478        {VIA686A_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
479         &sensors_sysctl_real, NULL, &via686a_fan},
480        {VIA686A_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &sensors_proc_real,
481         &sensors_sysctl_real, NULL, &via686a_temp},
482        {VIA686A_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
483         &sensors_proc_real, &sensors_sysctl_real, NULL, &via686a_temp},
484        {VIA686A_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
485         &sensors_proc_real, &sensors_sysctl_real, NULL, &via686a_temp},
486        {VIA686A_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
487         &sensors_proc_real, &sensors_sysctl_real, NULL, &via686a_fan_div},
488        {VIA686A_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
489         &sensors_proc_real, &sensors_sysctl_real, NULL, &via686a_alarms},
490        {0}
491};
492
493static inline int via686a_read_value(struct i2c_client *client, u8 reg)
494{
495        return (inb_p(client->addr + reg));
496}
497
498static inline void via686a_write_value(struct i2c_client *client, u8 reg,
499                                       u8 value)
500{
501        outb_p(value, client->addr + reg);
502}
503
504/* This is called when the module is loaded */
505int via686a_attach_adapter(struct i2c_adapter *adapter)
506{
507        return sensors_detect(adapter, &addr_data, via686a_detect);
508}
509
510/* Locate chip and get correct base address */
511int via686a_find(int *address)
512{
513        struct pci_dev *s_bridge;
514        u16 val;
515
516        if (!pci_present())
517                return -ENODEV;
518
519        if (!(s_bridge = pci_find_device(PCI_VENDOR_ID_VIA,
520                                         PCI_DEVICE_ID_VIA_82C686_4,
521                                         NULL))) return -ENODEV;
522
523        if (PCIBIOS_SUCCESSFUL !=
524            pci_read_config_word(s_bridge, VIA686A_BASE_REG, &val))
525                return -ENODEV;
526        *address = (val & 0xff80);
527        if (*address == 0) {
528                printk("via686a.o: sensors not enabled - upgrade BIOS?\n");
529                return -ENODEV;
530        }
531
532        if (PCIBIOS_SUCCESSFUL !=
533            pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
534                return -ENODEV;
535        if (!(val & 0x01)) {
536                printk("via686a.o: enabling sensors\n");
537                pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
538                                      val | 0x01);
539        }
540        return 0;
541}
542
543int via686a_detect(struct i2c_adapter *adapter, int address,
544                   unsigned short flags, int kind)
545{
546        int i;
547        struct i2c_client *new_client;
548        struct via686a_data *data;
549        int err = 0;
550        const char *type_name = "via686a";
551
552        /* Make sure we are probing the ISA bus!!  */
553        if (!i2c_is_isa_adapter(adapter)) {
554                printk
555                ("via686a.o: via686a_detect called for an I2C bus adapter?!?\n");
556                return 0;
557        }
558
559        if (check_region(address, VIA686A_EXTENT)) {
560                printk("via686a.o: region 0x%x already in use!\n",
561                       address);
562                err = -ENODEV;
563                goto ERROR0;
564        }
565
566        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
567                                   sizeof(struct via686a_data),
568                                   GFP_KERNEL))) {
569                err = -ENOMEM;
570                goto ERROR0;
571        }
572
573        data = (struct via686a_data *) (new_client + 1);
574        new_client->addr = address;
575        init_MUTEX(&data->lock);
576        new_client->data = data;
577        new_client->adapter = adapter;
578        new_client->driver = &via686a_driver;
579        new_client->flags = 0;
580
581        /* Reserve the ISA region */
582        request_region(address, VIA686A_EXTENT, type_name);
583
584        /* Fill in the remaining client fields and put into the global list */
585        strcpy(new_client->name, "Via 686A Integrated Sensors");
586
587        new_client->id = via686a_id++;
588        data->valid = 0;
589        init_MUTEX(&data->update_lock);
590
591        /* Tell the I2C layer a new client has arrived */
592        if ((err = i2c_attach_client(new_client)))
593                goto ERROR3;
594
595        /* Register a new directory entry with module sensors */
596        if ((i = sensors_register_entry((struct i2c_client *) new_client,
597                                        type_name,
598                                        via686a_dir_table_template,
599                                        THIS_MODULE)) < 0) {
600                err = i;
601                goto ERROR4;
602        }
603        data->sysctl_id = i;
604
605        /* Initialize the VIA686A chip */
606        via686a_init_client(new_client);
607        return 0;
608
609      ERROR4:
610        i2c_detach_client(new_client);
611      ERROR3:
612        release_region(address, VIA686A_EXTENT);
613        kfree(new_client);
614      ERROR0:
615        return err;
616}
617
618int via686a_detach_client(struct i2c_client *client)
619{
620        int err;
621
622        sensors_deregister_entry(((struct via686a_data *) 
623                                  (client->data))->sysctl_id);
624
625        if ((err = i2c_detach_client(client))) {
626                printk
627                ("via686a.o: Client deregistration failed, client not detached.\n");
628                return err;
629        }
630
631        release_region(client->addr, VIA686A_EXTENT);
632        kfree(client);
633
634        return 0;
635}
636
637/* No commands defined yet */
638int via686a_command(struct i2c_client *client, unsigned int cmd, void *arg)
639{
640        return 0;
641}
642
643void via686a_inc_use(struct i2c_client *client)
644{
645        MOD_INC_USE_COUNT;
646}
647
648void via686a_dec_use(struct i2c_client *client)
649{
650        MOD_DEC_USE_COUNT;
651}
652
653/* Called when we have found a new VIA686A. Set limits, etc. */
654void via686a_init_client(struct i2c_client *client)
655{
656        int i;
657
658        /* Reset the device */
659        via686a_write_value(client, VIA686A_REG_CONFIG, 0x80);
660
661        via686a_write_value(client, VIA686A_REG_IN_MIN(0),
662                            IN_TO_REG(VIA686A_INIT_IN_MIN_0, 0));
663        via686a_write_value(client, VIA686A_REG_IN_MAX(0),
664                            IN_TO_REG(VIA686A_INIT_IN_MAX_0, 0));
665        via686a_write_value(client, VIA686A_REG_IN_MIN(1),
666                            IN_TO_REG(VIA686A_INIT_IN_MIN_1, 1));
667        via686a_write_value(client, VIA686A_REG_IN_MAX(1),
668                            IN_TO_REG(VIA686A_INIT_IN_MAX_1, 1));
669        via686a_write_value(client, VIA686A_REG_IN_MIN(2),
670                            IN_TO_REG(VIA686A_INIT_IN_MIN_2, 2));
671        via686a_write_value(client, VIA686A_REG_IN_MAX(2),
672                            IN_TO_REG(VIA686A_INIT_IN_MAX_2, 2));
673        via686a_write_value(client, VIA686A_REG_IN_MIN(3),
674                            IN_TO_REG(VIA686A_INIT_IN_MIN_3, 3));
675        via686a_write_value(client, VIA686A_REG_IN_MAX(3),
676                            IN_TO_REG(VIA686A_INIT_IN_MAX_3, 3));
677        via686a_write_value(client, VIA686A_REG_IN_MIN(4),
678                            IN_TO_REG(VIA686A_INIT_IN_MIN_4, 4));
679        via686a_write_value(client, VIA686A_REG_IN_MAX(4),
680                            IN_TO_REG(VIA686A_INIT_IN_MAX_4, 4));
681        via686a_write_value(client, VIA686A_REG_FAN_MIN(1),
682                            FAN_TO_REG(VIA686A_INIT_FAN_MIN, 2));
683        via686a_write_value(client, VIA686A_REG_FAN_MIN(2),
684                            FAN_TO_REG(VIA686A_INIT_FAN_MIN, 2));
685        for (i = 1; i <= 3; i++) {
686                via686a_write_value(client, VIA686A_REG_TEMP_OVER(i),
687                                    TEMP_TO_REG(VIA686A_INIT_TEMP_OVER));
688                via686a_write_value(client, VIA686A_REG_TEMP_HYST(i),
689                                    TEMP_TO_REG(VIA686A_INIT_TEMP_HYST));
690        }
691
692        /* Start monitoring */
693        via686a_write_value(client, VIA686A_REG_CONFIG, 0x01);
694
695        /* Cofigure temp interrupt mode for continuous-interrupt operation */
696        via686a_write_value(client, VIA686A_REG_TEMP_MODE, 
697                            via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
698                            !VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS);
699}
700
701void via686a_update_client(struct i2c_client *client)
702{
703        struct via686a_data *data = client->data;
704        int i;
705
706        down(&data->update_lock);
707
708        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
709            (jiffies < data->last_updated) || !data->valid) {
710
711                for (i = 0; i <= 4; i++) {
712                        data->in[i] =
713                            via686a_read_value(client, VIA686A_REG_IN(i));
714                        data->in_min[i] = via686a_read_value(client,
715                                                             VIA686A_REG_IN_MIN
716                                                             (i));
717                        data->in_max[i] =
718                            via686a_read_value(client, VIA686A_REG_IN_MAX(i));
719                }
720                for (i = 1; i <= 2; i++) {
721                        data->fan[i - 1] =
722                            via686a_read_value(client, VIA686A_REG_FAN(i));
723                        data->fan_min[i - 1] = via686a_read_value(client,
724                                                     VIA686A_REG_FAN_MIN(i));
725                }
726                for (i = 1; i <= 3; i++) {
727                        data->temp[i - 1] = via686a_read_value(client,
728                                                 VIA686A_REG_TEMP(i)) << 2;
729                        data->temp_over[i - 1] =
730                            via686a_read_value(client,
731                                               VIA686A_REG_TEMP_OVER(i));
732                        data->temp_hyst[i - 1] =
733                            via686a_read_value(client,
734                                               VIA686A_REG_TEMP_HYST(i));
735                }
736                /* add in lower 2 bits
737                   temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
738                   temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
739                   temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
740                 */
741                data->temp[0] |= (via686a_read_value(client,
742                                                     VIA686A_REG_TEMP_LOW1)
743                                  & 0xc0) >> 6;
744                data->temp[1] |=
745                    (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
746                     0x30) >> 4;
747                data->temp[2] |=
748                    (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
749                     0xc0) >> 6;
750
751                i = via686a_read_value(client, VIA686A_REG_FANDIV);
752                data->fan_div[0] = (i >> 4) & 0x03;
753                data->fan_div[1] = i >> 6;
754                data->alarms =
755                    via686a_read_value(client,
756                                       VIA686A_REG_ALARM1) |
757                    (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
758                data->last_updated = jiffies;
759                data->valid = 1;
760        }
761
762        up(&data->update_lock);
763}
764
765
766/* The next few functions are the call-back functions of the /proc/sys and
767   sysctl files. Which function is used is defined in the ctl_table in
768   the extra1 field.
769   Each function must return the magnitude (power of 10 to divide the date
770   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
771   put a maximum of *nrels elements in results reflecting the data of this
772   file, and set *nrels to the number it actually put in it, if operation==
773   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
774   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
775   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
776   large enough (by checking the incoming value of *nrels). This is not very
777   good practice, but as long as you put less than about 5 values in results,
778   you can assume it is large enough. */
779void via686a_in(struct i2c_client *client, int operation, int ctl_name,
780                int *nrels_mag, long *results)
781{
782        struct via686a_data *data = client->data;
783        int nr = ctl_name - VIA686A_SYSCTL_IN0;
784
785        if (operation == SENSORS_PROC_REAL_INFO)
786                *nrels_mag = 2;
787        else if (operation == SENSORS_PROC_REAL_READ) {
788                via686a_update_client(client);
789                results[0] = IN_FROM_REG(data->in_min[nr], nr);
790                results[1] = IN_FROM_REG(data->in_max[nr], nr);
791                results[2] = IN_FROM_REG(data->in[nr], nr);
792                *nrels_mag = 3;
793        } else if (operation == SENSORS_PROC_REAL_WRITE) {
794                if (*nrels_mag >= 1) {
795                        data->in_min[nr] = IN_TO_REG(results[0], nr);
796                        via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
797                                            data->in_min[nr]);
798                }
799                if (*nrels_mag >= 2) {
800                        data->in_max[nr] = IN_TO_REG(results[1], nr);
801                        via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
802                                            data->in_max[nr]);
803                }
804        }
805}
806
807void via686a_fan(struct i2c_client *client, int operation, int ctl_name,
808                 int *nrels_mag, long *results)
809{
810        struct via686a_data *data = client->data;
811        int nr = ctl_name - VIA686A_SYSCTL_FAN1 + 1;
812
813        if (operation == SENSORS_PROC_REAL_INFO)
814                *nrels_mag = 0;
815        else if (operation == SENSORS_PROC_REAL_READ) {
816                via686a_update_client(client);
817                results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
818                                          DIV_FROM_REG(data->fan_div
819                                                       [nr - 1]));
820                results[1] =
821                    FAN_FROM_REG(data->fan[nr - 1],
822                                 DIV_FROM_REG(data->fan_div[nr - 1]));
823                *nrels_mag = 2;
824        } else if (operation == SENSORS_PROC_REAL_WRITE) {
825                if (*nrels_mag >= 1) {
826                        data->fan_min[nr - 1] = FAN_TO_REG(results[0], 
827                                                           DIV_FROM_REG(data->
828                                                              fan_div[nr -1]));
829                        via686a_write_value(client,
830                                            VIA686A_REG_FAN_MIN(nr),
831                                            data->fan_min[nr - 1]);
832                }
833        }
834}
835
836void via686a_temp(struct i2c_client *client, int operation, int ctl_name,
837                  int *nrels_mag, long *results)
838{
839        struct via686a_data *data = client->data;
840        int nr = ctl_name - VIA686A_SYSCTL_TEMP;
841
842        if (operation == SENSORS_PROC_REAL_INFO)
843                *nrels_mag = 1;
844        else if (operation == SENSORS_PROC_REAL_READ) {
845                via686a_update_client(client);
846                results[0] = TEMP_FROM_REG(data->temp_over[nr]);
847                results[1] = TEMP_FROM_REG(data->temp_hyst[nr]);
848                results[2] = TEMP_FROM_REG10(data->temp[nr]);
849                *nrels_mag = 3;
850        } else if (operation == SENSORS_PROC_REAL_WRITE) {
851                if (*nrels_mag >= 1) {
852                        data->temp_over[nr] = TEMP_TO_REG(results[0]);
853                        via686a_write_value(client,
854                                            VIA686A_REG_TEMP_OVER(nr + 1),
855                                            data->temp_over[nr]);
856                }
857                if (*nrels_mag >= 2) {
858                        data->temp_hyst[nr] = TEMP_TO_REG(results[1]);
859                        via686a_write_value(client,
860                                            VIA686A_REG_TEMP_HYST(nr + 1),
861                                            data->temp_hyst[nr]);
862                }
863        }
864}
865
866void via686a_alarms(struct i2c_client *client, int operation, int ctl_name,
867                    int *nrels_mag, long *results)
868{
869        struct via686a_data *data = client->data;
870        if (operation == SENSORS_PROC_REAL_INFO)
871                *nrels_mag = 0;
872        else if (operation == SENSORS_PROC_REAL_READ) {
873                via686a_update_client(client);
874                results[0] = ALARMS_FROM_REG(data->alarms);
875                *nrels_mag = 1;
876        }
877}
878
879void via686a_fan_div(struct i2c_client *client, int operation,
880                     int ctl_name, int *nrels_mag, long *results)
881{
882        struct via686a_data *data = client->data;
883        int old;
884
885        if (operation == SENSORS_PROC_REAL_INFO)
886                *nrels_mag = 0;
887        else if (operation == SENSORS_PROC_REAL_READ) {
888                via686a_update_client(client);
889                results[0] = DIV_FROM_REG(data->fan_div[0]);
890                results[1] = DIV_FROM_REG(data->fan_div[1]);
891                *nrels_mag = 2;
892        } else if (operation == SENSORS_PROC_REAL_WRITE) {
893                old = via686a_read_value(client, VIA686A_REG_FANDIV);
894                if (*nrels_mag >= 2) {
895                        data->fan_div[1] = DIV_TO_REG(results[1]);
896                        old = (old & 0x3f) | (data->fan_div[1] << 6);
897                }
898                if (*nrels_mag >= 1) {
899                        data->fan_div[0] = DIV_TO_REG(results[0]);
900                        old = (old & 0xcf) | (data->fan_div[0] << 4);
901                        via686a_write_value(client, VIA686A_REG_FANDIV,
902                                            old);
903                }
904        }
905}
906
907int __init sensors_via686a_init(void)
908{
909        int res, addr;
910
911        printk("via686a.o version %s (%s)\n", LM_VERSION, LM_DATE);
912        via686a_initialized = 0;
913
914        if (via686a_find(&addr)) {
915                printk("via686a.o: No Via 686A sensors found.\n");
916                return -ENODEV;
917        }
918        normal_isa[0] = addr;
919
920        if ((res = i2c_add_driver(&via686a_driver))) {
921                printk("via686a.o: Driver registration failed.\n");
922                via686a_cleanup();
923                return res;
924        }
925        via686a_initialized++;
926        return 0;
927}
928
929int __init via686a_cleanup(void)
930{
931        int res;
932
933        if (via686a_initialized >= 1) {
934                if ((res = i2c_del_driver(&via686a_driver))) {
935                        printk
936                            ("via686a.o: Driver deregistration failed.\n");
937                        return res;
938                }
939                via686a_initialized--;
940        }
941        return 0;
942}
943
944EXPORT_NO_SYMBOLS;
945
946#ifdef MODULE
947
948MODULE_AUTHOR
949    ("Kyösti Mälkki <kmalkki@cc.hut.fi>, Mark Studebaker <mdsxyz123@yahoo.com>, Bob Dougherty <bobd@stanford.edu>");
950MODULE_DESCRIPTION("VIA 686A Sensor device");
951
952int init_module(void)
953{
954        return sensors_via686a_init();
955}
956
957int cleanup_module(void)
958{
959        return via686a_cleanup();
960}
961
962#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.