root/lm-sensors/trunk/kernel/chips/lm87.c @ 1544

Revision 1544, 33.3 KB (checked in by mds, 12 years ago)

add multiple VRM support to lm87; patch from

Dave Johnson <ddj@…>

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    LM87.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 2000  Frodo Looijaard <frodol@dds.nl>
5                        Philip Edelbrock <phil@netroedge.com>
6                        Stephen Rousset <stephen.rousset@rocketlogix.com>
7                        Dan Eaton <dan.eaton@rocketlogix.com>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24
25#include <linux/version.h>
26#include <linux/module.h>
27#include <linux/slab.h>
28#include <linux/proc_fs.h>
29#include <linux/ioport.h>
30#include <linux/sysctl.h>
31#include <asm/errno.h>
32#include <asm/io.h>
33#include <linux/types.h>
34#include <linux/i2c.h>
35#include "version.h"
36#include "sensors.h"
37#include "sensors_vid.h"
38#include <linux/init.h>
39
40/* Chip configuration settings.  These should be set to reflect the
41HARDWARE configuration of your chip.  By default (read: when all of
42these are left commented out), this driver assumes that the
43configuration is the same as National's defaults for the Channel Mode
44register.
45
46Set to '1' the appropriate defines, as nessesary:
47
48 - External temp sensors 2 (possible second CPU temp)
49   This will disable the 2.5V and Vccp2 readings.
50   Ironically, National decided that you can read the
51   temperature of a second CPU or it's core voltage,
52   but not both!  Comment out if FAULT is reported.  */
53
54/* #define LM87_EXT2 1 */
55
56/* Aux analog input. When enabled, the Fan 1 reading
57   will be disabled */
58
59/* #define LM87_AIN1 1 */
60
61/* Aux analog input 2. When enabled, the Fan 2 reading
62   will be disabled */
63
64/* #define LM87_AIN2 1 */
65
66/* Internal Vcc is 5V instead of 3.3V */
67
68/* #define LM87_5V_VCC 1 */
69
70/* That's the end of the hardware config defines.  I would have made
71   them insmod params, but it would be too much work. ;') */
72
73
74#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
75    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
76#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
77#endif
78
79#ifndef THIS_MODULE
80#define THIS_MODULE NULL
81#endif
82
83/* Addresses to scan */
84static unsigned short normal_i2c[] = { SENSORS_I2C_END };
85static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END };
86static unsigned int normal_isa[] = { SENSORS_ISA_END };
87static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
88
89/* Insmod parameters */
90SENSORS_INSMOD_1(lm87);
91
92/* The following is the calculation for the register offset
93 * for the monitored items minimum and maximum locations.
94 */
95#define LM87_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
96#define LM87_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
97#define LM87_REG_IN(nr) (0x20 + (nr))
98
99/* Initial limits */
100
101/*
102 * LM87 register definition
103 *
104 */
105
106      /* The LM87 registers */
107#define LM87_INT_TEMP_HI_LIMIT_LOCKABLE  0x13
108#define LM87_EXT_TEMP_HI_LIMIT_LOCKABLE  0x14
109#define LM87_REG_TEST                    0x15
110#define LM87_REG_CHANNEL_MODE            0x16
111#define LM87_REG_INT_TEMP_HI_LIMIT       0x17
112#define LM87_REG_EXT_TEMP_HI_LIMIT       0x18
113#define LM87_REG_ANALOG_OUT              0x19
114
115      /* These are all read-only */
116#define LM87_REG_2_5V_EXT_TEMP_2         0x20
117#define LM87_REG_VCCP1                   0x21
118#define LM87_REG_3_3V                    0x22 
119#define LM87_REG_5V                      0x23
120#define LM87_REG_12V                     0x24
121#define LM87_REG_VCCP2                   0x25
122#define LM87_REG_EXT_TEMP_1              0x26
123#define LM87_REG_INT_TEMP                0x27  /* LM87 temp. */
124#define LM87_REG_FAN1_AIN1               0x28
125#define LM87_REG_FAN2_AIN2               0x29
126
127/* These are read/write */
128#define LM87_REG_AIN1_LOW                0x1A
129#define LM87_REG_AIN2_LOW                0x1B
130#define LM87_REG_2_5V_EXT_TEMP_2_HIGH    0x2B 
131#define LM87_REG_2_5V_EXT_TEMP_2_LOW     0x2C 
132#define LM87_REG_VCCP1_HIGH              0x2D 
133#define LM87_REG_VCCP1_LOW               0x2E 
134#define LM87_REG_3_3V_HIGH               0x2F
135#define LM87_REG_3_3V_LOW                0x30
136#define LM87_REG_5V_HIGH                 0x31
137#define LM87_REG_5V_LOW                  0x32
138#define LM87_REG_12V_HIGH                0x33
139#define LM87_REG_12V_LOW                 0x34
140#define LM87_REG_VCCP2_HIGH              0x35
141#define LM87_REG_VCCP2_LOW               0x36
142#define LM87_REG_EXT_TEMP_1_HIGH         0x37   
143#define LM87_REG_EXT_TEMP_1_LOW          0x38 
144#define LM87_REG_INT_TEMP_HIGH           0x39 
145#define LM87_REG_INT_TEMP_LOW            0x3A 
146#define LM87_REG_FAN1_AIN1_LIMIT         0x3B
147#define LM87_REG_FAN2_AIN2_LIMIT         0x3C
148#define LM87_REG_COMPANY_ID              0x3E
149#define LM87_REG_DIE_REV                 0x3F
150
151#define LM87_REG_CONFIG                  0x40
152#define LM87_REG_INT1_STAT               0x41
153#define LM87_REG_INT2_STAT               0x42
154#define LM87_REG_INT1_MASK               0x43
155#define LM87_REG_INT2_MASK               0x44
156#define LM87_REG_CHASSIS_CLEAR           0x46
157#define LM87_REG_VID_FAN_DIV             0x47
158#define LM87_REG_VID4                    0x49
159#define LM87_REG_CONFIG_2                0x4A
160#define LM87_REG_INTRPT_STATUS_1_MIRROR  0x4C
161#define LM87_REG_INTRPT_STATUS_2_MIRROR  0x4D
162#define LM87_REG_SMBALERT_NUM_ENABLE     0x80
163
164
165
166/* Conversions. Rounding and limit checking is only done on the TO_REG
167   variants. Note that you should be a bit careful with which arguments
168   these macros are called: arguments may be evaluated more than once.
169   Fixing this is just not worth it. */
170
171#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255))
172#define IN_FROM_REG(val,nr) (val)
173
174extern inline u8 FAN_TO_REG(long rpm, int div)
175{
176        if (rpm == 0)
177                return 255;
178        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
179        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
180                             254);
181}
182
183#define FAN_FROM_REG(val,div) ((val)==0?-1:\
184                               (val)==255?0:1350000/((div)*(val)))
185
186#define TEMP_FROM_REG(temp)  (temp * 10)
187
188#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
189
190#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
191                                                      ((val)+5)/10),0,255)
192#if 0
193#define TEMP_FROM_REG(temp) \
194   ((temp)<256?((((temp)&0x1fe) >> 1) * 10)      + ((temp) & 1) * 5:  \
195               ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5)  \
196
197#define TEMP_LIMIT_FROM_REG(val) (val)
198
199#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val),0,255)
200#endif
201
202
203#define ALARMS_FROM_REG(val) (val)
204
205#define DIV_FROM_REG(val) (1 << (val))
206#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1)))
207
208#define LM87_INIT_FAN_MIN 3000
209
210#define LM87_INIT_EXT_TEMP_MAX 600
211#define LM87_INIT_EXT_TEMP_MIN 100
212#define LM87_INIT_INT_TEMP_MAX 600
213#define LM87_INIT_INT_TEMP_MIN 100
214
215#ifdef MODULE
216extern int init_module(void);
217extern int cleanup_module(void);
218#endif                          /* MODULE */
219
220/* For each registered LM87, we need to keep some data in memory. That
221   data is pointed to by LM87_list[NR]->data. The structure itself is
222   dynamically allocated, at the same time when a new LM87 client is
223   allocated. */
224struct lm87_data {
225        int sysctl_id;
226        enum chips type;
227
228        struct semaphore update_lock;
229        char valid;             /* !=0 if following fields are valid */
230        unsigned long last_updated;     /* In jiffies */
231
232        u8  in[6];              /* Scaled Register value */
233        u8  in_max[6];          /* Scaled Register value */
234        u8  in_min[6];          /* Scaled Register value */
235        u8  ain1;               /* Register value */
236        u8  ain1_min;           /* Register value */
237        u8  ain1_max;           /* Register value */
238        u8  ain2;               /* Register value */
239        u8  ain2_min;           /* Register value */
240        u8  ain2_max;           /* Register value */
241        u8  fan;                /* Register value */
242        u8  fan_min;            /* Register value */
243        u8  fan_div;            /* Register encoding, shifted right */
244        u8  fan2;               /* Register value */
245        u8  fan2_min;           /* Register value */
246        u8  fan2_div;           /* Register encoding, shifted right */
247        int ext2_temp;          /* Temp, shifted right */
248        int ext_temp;           /* Temp, shifted right */
249        int int_temp;           /* Temp, shifted right */
250        u8  ext_temp_max;       /* Register value */
251        u8  ext_temp_min;       /* Register value */
252        u8  ext2_temp_max;      /* Register value */
253        u8  ext2_temp_min;      /* Register value */
254        u8  int_temp_max;       /* Register value */
255        u8  int_temp_min;       /* Register value */
256        u16 alarms;             /* Register encoding, combined */
257        u8  analog_out;         /* Register value */
258        u8  vid;                /* Register value combined */
259        u8  vrm;                /* VRM version * 10 */
260};
261
262#ifdef MODULE
263static
264#else
265extern
266#endif
267int __init sensors_lm87_init(void);
268static int __init lm87_cleanup(void);
269
270static int lm87_attach_adapter(struct i2c_adapter *adapter);
271static int lm87_detect(struct i2c_adapter *adapter, int address,
272                          unsigned short flags, int kind);
273static int lm87_detach_client(struct i2c_client *client);
274static int lm87_command(struct i2c_client *client, unsigned int cmd,
275                           void *arg);
276static void lm87_inc_use(struct i2c_client *client);
277static void lm87_dec_use(struct i2c_client *client);
278
279static int lm87_read_value(struct i2c_client *client, u8 register);
280static int lm87_write_value(struct i2c_client *client, u8 register,
281                               u8 value);
282static void lm87_update_client(struct i2c_client *client);
283static void lm87_init_client(struct i2c_client *client);
284
285
286static void lm87_in(struct i2c_client *client, int operation,
287                       int ctl_name, int *nrels_mag, long *results);
288#if defined (LM87_AIN1) || defined (LM87_AIN2)
289static void lm87_ain(struct i2c_client *client, int operation,
290                       int ctl_name, int *nrels_mag, long *results);
291#endif
292static void lm87_fan(struct i2c_client *client, int operation,
293                        int ctl_name, int *nrels_mag, long *results);
294static void lm87_temp(struct i2c_client *client, int operation,
295                         int ctl_name, int *nrels_mag, long *results);
296static void lm87_alarms(struct i2c_client *client, int operation,
297                           int ctl_name, int *nrels_mag, long *results);
298static void lm87_fan_div(struct i2c_client *client, int operation,
299                            int ctl_name, int *nrels_mag, long *results);
300static void lm87_analog_out(struct i2c_client *client, int operation,
301                               int ctl_name, int *nrels_mag,
302                               long *results);
303static void lm87_vid(struct i2c_client *client, int operation,
304                        int ctl_name, int *nrels_mag, long *results);
305static void lm87_vrm(struct i2c_client *client, int operation,
306                        int ctl_name, int *nrels_mag, long *results);
307
308/* I choose here for semi-static LM87 allocation. Complete dynamic
309   allocation could also be used; the code needed for this would probably
310   take more memory than the datastructure takes now. */
311static int lm87_id = 0;
312
313static struct i2c_driver LM87_driver = {
314        /* name */          "LM87 sensor driver",
315        /* id */             I2C_DRIVERID_LM87,
316        /* flags */          I2C_DF_NOTIFY,
317        /* attach_adapter */ &lm87_attach_adapter,
318        /* detach_client */  &lm87_detach_client,
319        /* command */        &lm87_command,
320        /* inc_use */        &lm87_inc_use,
321        /* dec_use */        &lm87_dec_use
322};
323
324/* Used by LM87_init/cleanup */
325static int __initdata lm87_initialized = 0;
326
327/* The /proc/sys entries */
328/* These files are created for each detected LM87. This is just a template;
329   though at first sight, you might think we could use a statically
330   allocated list, we need some way to get back to the parent - which
331   is done through one of the 'extra' fields which are initialized
332   when a new copy is allocated. */
333
334static ctl_table LM87_dir_table_template[] = {
335#ifdef LM87_AIN1
336        {LM87_SYSCTL_AIN1, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
337          &i2c_sysctl_real, NULL, &lm87_ain},
338#endif
339#ifdef LM87_AIN2
340        {LM87_SYSCTL_AIN2, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
341          &i2c_sysctl_real, NULL, &lm87_ain},
342#endif
343#ifndef LM87_EXT2
344        {LM87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
345          &i2c_sysctl_real, NULL, &lm87_in},
346        {LM87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
347          &i2c_sysctl_real, NULL, &lm87_in},
348#endif
349        {LM87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
350          &i2c_sysctl_real, NULL, &lm87_in},
351        {LM87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
352          &i2c_sysctl_real, NULL, &lm87_in},
353        {LM87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
354          &i2c_sysctl_real, NULL, &lm87_in},
355        {LM87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
356          &i2c_sysctl_real, NULL, &lm87_in},
357#ifndef LM87_AIN1
358        {LM87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
359          &i2c_sysctl_real, NULL, &lm87_fan},
360        {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
361          &i2c_sysctl_real, NULL, &lm87_fan_div},
362#define LM87_FANDIV_FLAG
363#endif
364#ifndef LM87_AIN2
365        {LM87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
366          &i2c_sysctl_real, NULL, &lm87_fan},
367#ifndef LM87_FANDIV_FLAG
368        {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
369          &i2c_sysctl_real, NULL, &lm87_fan_div},
370#endif /* LM87_FANDIV_FLAG */
371#endif /* LM87_AIN2 */
372#ifdef LM87_EXT2
373        {LM87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
374          &i2c_sysctl_real, NULL, &lm87_temp},
375#endif
376        {LM87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
377          &i2c_sysctl_real, NULL, &lm87_temp},
378        {LM87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
379          &i2c_sysctl_real, NULL, &lm87_temp},
380        {LM87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
381          &i2c_sysctl_real, NULL, &lm87_alarms},
382        {LM87_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
383          &i2c_sysctl_real, NULL, &lm87_analog_out},
384        {LM87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
385          &i2c_sysctl_real, NULL, &lm87_vid},
386        {LM87_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
387         &i2c_sysctl_real, NULL, &lm87_vrm},
388        {0}
389};
390
391int lm87_attach_adapter(struct i2c_adapter *adapter)
392{
393        int error;
394        struct i2c_client_address_data  lm87_client_data;
395
396        lm87_client_data.normal_i2c       = addr_data.normal_i2c;
397        lm87_client_data.normal_i2c_range = addr_data.normal_i2c_range;
398        lm87_client_data.probe            = addr_data.probe;
399        lm87_client_data.probe_range      = addr_data.probe_range;
400        lm87_client_data.ignore           = addr_data.ignore;
401        lm87_client_data.ignore_range     = addr_data.ignore_range;
402        lm87_client_data.force            = addr_data.forces->force;
403
404        error = i2c_probe(adapter, &lm87_client_data, lm87_detect);
405        i2c_detect(adapter, &addr_data, lm87_detect);
406
407        return error;
408}
409
410static int lm87_detect(struct i2c_adapter *adapter, int address,
411                          unsigned short flags, int kind)
412{
413        int i;
414        struct i2c_client *new_client;
415        struct lm87_data *data;
416        int err = 0;
417        const char *type_name = "";
418        const char *client_name = "";
419
420        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
421                goto ERROR0;
422
423        /* OK. For now, we presume we have a valid client. We now create the
424           client structure, even though we cannot fill it completely yet.
425           But it allows us to access LM87_{read,write}_value. */
426
427        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
428                                   sizeof(struct lm87_data),
429                                   GFP_KERNEL))) {
430                err = -ENOMEM;
431                goto ERROR0;
432        }
433
434        data = (struct lm87_data *) (new_client + 1);
435        new_client->addr = address;
436        new_client->data = data;
437        new_client->adapter = adapter;
438        new_client->driver = &LM87_driver;
439        new_client->flags = 0;
440
441        /* Now, we do the remaining detection. */
442
443        if (kind < 0) {
444                if (((lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)
445                     != 0x00) ||
446                    (lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02))
447               goto ERROR1;
448        }
449
450        /* Fill in the remaining client fields and put into the global list */
451        type_name = "lm87";
452        client_name = "LM87 chip";
453        strcpy(new_client->name, client_name);
454        data->type = kind;
455
456        new_client->id = lm87_id++;
457        data->valid = 0;
458        init_MUTEX(&data->update_lock);
459
460        /* Tell the I2C layer a new client has arrived */
461        if ((err = i2c_attach_client(new_client)))
462                goto ERROR3;
463
464        /* Register a new directory entry with module sensors */
465        if ((i = i2c_register_entry(new_client,
466                                        type_name,
467                                        LM87_dir_table_template,
468                                        THIS_MODULE)) < 0) {
469                err = i;
470                goto ERROR4;
471        }
472        data->sysctl_id = i;
473
474        /* Initialize the LM87 chip */
475        lm87_init_client(new_client);
476        return 0;
477
478/* OK, this is not exactly good programming practice, usually. But it is
479   very code-efficient in this case. */
480
481      ERROR4:
482        i2c_detach_client(new_client);
483      ERROR3:
484      ERROR1:
485        kfree(new_client);
486      ERROR0:
487        return err;
488}
489
490int lm87_detach_client(struct i2c_client *client)
491{
492        int err;
493
494        i2c_deregister_entry(((struct lm87_data *) (client->data))->
495                                 sysctl_id);
496
497        if ((err = i2c_detach_client(client))) {
498                printk
499                    ("lm87.o: Client deregistration failed, client not detached.\n");
500                return err;
501        }
502
503        kfree(client);
504
505        return 0;
506
507}
508
509/* No commands defined yet */
510int lm87_command(struct i2c_client *client, unsigned int cmd, void *arg)
511{
512        return 0;
513}
514
515void lm87_inc_use(struct i2c_client *client)
516{
517#ifdef MODULE
518        MOD_INC_USE_COUNT;
519#endif
520}
521
522void lm87_dec_use(struct i2c_client *client)
523{
524#ifdef MODULE
525        MOD_DEC_USE_COUNT;
526#endif
527}
528
529int lm87_read_value(struct i2c_client *client, u8 reg)
530{
531        return 0xFF & i2c_smbus_read_byte_data(client, reg);
532}
533
534int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
535{
536        return i2c_smbus_write_byte_data(client, reg, value);
537}
538
539/* Called when we have found a new LM87. It should set limits, etc. */
540void lm87_init_client(struct i2c_client *client)
541{
542        struct lm87_data *data = client->data;
543        int vid;
544        u8 v;
545
546        /* Reset all except Watchdog values and last conversion values
547           This sets fan-divs to 2, among others. This makes most other
548           initializations unnecessary */
549        lm87_write_value(client, LM87_REG_CONFIG, 0x80);
550
551        /* Setup Channel Mode register for configuration of monitoring
552         * Default is 00000000b
553         *      bit 0 - Configures Fan 1/AIN 1 input (1 = AIN)
554         *      bit 1 - Configures Fan 2/AIN 2 input (1 = AIN)
555         *      bit 2 - Configures 2.5V&Vccp2/D2 input (1 = 2nd Therm.)
556         *      bit 3 - Configures Vcc for 5V/3.3V reading (0 = 3.3V)
557         *      bit 4 - Configures IRQ0 Enable if = 1
558         *      bit 5 - Configures IRQ1 Enable if = 1
559         *      bit 6 - Configures IRQ2 Enable if = 1
560         *      bit 7 - Configures VID/IRQ input as interrupts if = 1
561         */
562
563/* I know, not clean, but it works. :'p */
564        lm87_write_value(client, LM87_REG_CHANNEL_MODE,
565#ifdef LM87_AIN1
566 0x01
567#else
5680
569#endif
570 | 
571#ifdef LM87_AIN2
572 0x02
573#else
5740
575#endif
576 |
577#ifdef LM87_EXT2
578 0x04
579#else
5800
581#endif
582 | 
583#ifdef LM87_5V_VCC
5840x08
585#else   
5860
587#endif
588        );
589
590        /* Set IN (voltage) initial limits to sane values  +/- 5% */
591        lm87_write_value(client, LM87_REG_IN_MIN(0),182);
592        lm87_write_value(client, LM87_REG_IN_MAX(0),202);
593        lm87_write_value(client, LM87_REG_IN_MIN(2),182);
594        lm87_write_value(client, LM87_REG_IN_MAX(2),202);
595        lm87_write_value(client, LM87_REG_IN_MIN(3),182);
596        lm87_write_value(client, LM87_REG_IN_MAX(3),202);
597        lm87_write_value(client, LM87_REG_IN_MIN(4),182);
598        lm87_write_value(client, LM87_REG_IN_MAX(4),202);
599
600        /* Set CPU core voltage limits relative to vid readings +/- 5% */
601        v = (lm87_read_value(client, LM87_REG_VID_FAN_DIV) & 0x0f)
602                    | ((lm87_read_value(client, LM87_REG_VID4) & 0x01)
603                    << 4 );
604        data->vrm = DEFAULT_VRM;
605        vid = vid_from_reg(v, data->vrm);
606
607        v = vid * 95 * 192 / 270000;
608        lm87_write_value(client, LM87_REG_IN_MIN(1), v);
609        lm87_write_value(client, LM87_REG_IN_MIN(5), v);
610        v = vid * 105 * 192 / 270000;
611        lm87_write_value(client, LM87_REG_IN_MAX(1), v);
612        lm87_write_value(client, LM87_REG_IN_MAX(5), v);
613
614        /* Set Temp initial limits to sane values */
615        lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH,
616                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MAX));
617        lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW,
618                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MIN));
619#ifdef LM87_EXT2
620        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH,
621                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MAX));
622        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW,
623                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MIN));
624#endif
625        lm87_write_value(client, LM87_REG_INT_TEMP_HIGH,
626                            TEMP_LIMIT_TO_REG(LM87_INIT_INT_TEMP_MAX));
627        lm87_write_value(client, LM87_REG_INT_TEMP_LOW,
628                            TEMP_LIMIT_TO_REG(LM87_INIT_INT_TEMP_MIN));
629
630#ifndef LM87_AIN1
631        lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT,
632                            FAN_TO_REG(LM87_INIT_FAN_MIN, 2));
633#endif
634#ifndef LM87_AIN2
635        lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
636                            FAN_TO_REG(LM87_INIT_FAN_MIN, 2));
637#endif
638
639        /* Start monitoring */
640        lm87_write_value(client, LM87_REG_CONFIG, 0x01);
641}
642
643void lm87_update_client(struct i2c_client *client)
644{
645        struct lm87_data *data = client->data;
646        int i;
647
648        down(&data->update_lock);
649
650        if ((jiffies - data->last_updated > HZ) ||  /* 1 sec cache */
651            (jiffies < data->last_updated)      || 
652             !data->valid) {
653                for (i = 0; i <= 5; i++) { 
654                 data->in[i] = 
655                    lm87_read_value(client,LM87_REG_IN(i));
656                 data->in_min[i] = 
657                    lm87_read_value(client,LM87_REG_IN_MIN(i));
658                 data->in_max[i] = 
659                    lm87_read_value(client,LM87_REG_IN_MAX(i));
660                }
661                 data->ain1 = 
662                    lm87_read_value(client,LM87_REG_FAN1_AIN1);
663                 data->ain1_min =
664                    lm87_read_value(client,LM87_REG_AIN1_LOW);
665                 data->ain1_max =
666                    lm87_read_value(client,LM87_REG_FAN1_AIN1_LIMIT);
667                 data->ain2 = 
668                    lm87_read_value(client,LM87_REG_FAN2_AIN2);
669                 data->ain2_min =
670                    lm87_read_value(client,LM87_REG_AIN2_LOW);
671                 data->ain2_max =
672                    lm87_read_value(client,LM87_REG_FAN2_AIN2_LIMIT);
673
674                data->fan =
675                    lm87_read_value(client, LM87_REG_FAN1_AIN1);
676                data->fan_min =
677                    lm87_read_value(client, LM87_REG_FAN1_AIN1_LIMIT);
678                data->fan2 =
679                    lm87_read_value(client, LM87_REG_FAN2_AIN2);
680                data->fan2_min =
681                    lm87_read_value(client, LM87_REG_FAN2_AIN2_LIMIT);
682
683                data->ext2_temp =
684                    lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2);
685                data->ext_temp =
686                    lm87_read_value(client, LM87_REG_EXT_TEMP_1);
687                data->int_temp =
688                    lm87_read_value(client, LM87_REG_INT_TEMP);
689
690                data->ext2_temp_max =
691                    lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH);
692                data->ext2_temp_min =
693                    lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW);
694
695                data->ext_temp_max =
696                    lm87_read_value(client, LM87_REG_EXT_TEMP_1_HIGH);
697                data->ext_temp_min =
698                    lm87_read_value(client, LM87_REG_EXT_TEMP_1_LOW);
699
700                data->int_temp_max =
701                    lm87_read_value(client, LM87_REG_INT_TEMP_HIGH);
702                data->int_temp_min =
703                    lm87_read_value(client, LM87_REG_INT_TEMP_LOW);
704
705                i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
706                data->fan_div = (i >> 4) & 0x03;
707                data->fan2_div = (i >> 6) & 0x03;
708                data->vid = i & 0x0f;
709                data->vid |=
710                    (lm87_read_value(client, LM87_REG_VID4) & 0x01)
711                    << 4;
712                data->alarms =
713                    lm87_read_value(client, LM87_REG_INT1_STAT) +
714                    (lm87_read_value(client, LM87_REG_INT2_STAT) << 8);
715                data->analog_out =
716                    lm87_read_value(client, LM87_REG_ANALOG_OUT);
717                data->last_updated = jiffies;
718                data->valid = 1;
719        }
720        up(&data->update_lock);
721}
722
723
724/* The next few functions are the call-back functions of the /proc/sys and
725   sysctl files. Which function is used is defined in the ctl_table in
726   the extra1 field.
727   Each function must return the magnitude (power of 10 to divide the date
728   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
729   put a maximum of *nrels elements in results reflecting the data of this
730   file, and set *nrels to the number it actually put in it, if operation==
731   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
732   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
733   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
734   large enough (by checking the incoming value of *nrels). This is not very
735   good practice, but as long as you put less than about 5 values in results,
736   you can assume it is large enough. */
737void lm87_in(struct i2c_client *client, int operation, int ctl_name,
738                int *nrels_mag, long *results)
739{
740        long scales[6] = { 250, 270, 
741#ifdef LM87_5V_VCC
742500,
743#else
744330,
745#endif
746                500, 1200, 270 };
747
748        struct lm87_data *data = client->data;
749        int nr = ctl_name - LM87_SYSCTL_IN0;
750
751        if (operation == SENSORS_PROC_REAL_INFO)
752                *nrels_mag = 2;
753        else if (operation == SENSORS_PROC_REAL_READ) {
754                lm87_update_client(client);
755                results[0] =
756                    ((long)data->in_min[nr] * scales[nr]) / 192;
757                results[1] =
758                    ((long)data->in_max[nr] * scales[nr]) / 192;
759                results[2] =
760                    ((long)data->in[nr] * scales[nr]) / 192;
761                *nrels_mag = 3;
762        } else if (operation == SENSORS_PROC_REAL_WRITE) {
763                if (*nrels_mag >= 1) {
764                        data->in_min[nr] =
765                            (results[0] * 192) / scales[nr];
766                        lm87_write_value(client, LM87_REG_IN_MIN(nr),
767                                            data->in_min[nr]);
768                }
769                if (*nrels_mag >= 2) {
770                        data->in_max[nr] =
771                            (results[1] * 192) / scales[nr];
772                        lm87_write_value(client, LM87_REG_IN_MAX(nr),
773                                            data->in_max[nr]);
774                }
775        }
776}
777
778#if defined (LM87_AIN1) || defined (LM87_AIN2)
779void lm87_ain(struct i2c_client *client, int operation, int ctl_name,
780                int *nrels_mag, long *results)
781{
782        struct lm87_data *data = client->data;
783
784        if (operation == SENSORS_PROC_REAL_INFO)
785                *nrels_mag = 0;
786        else if (operation == SENSORS_PROC_REAL_READ) {
787                lm87_update_client(client);
788                if (ctl_name == LM87_SYSCTL_AIN1) {
789                 results[0] = data->ain1_min;
790                 results[1] = data->ain1_max;
791                 results[2] = data->ain1;
792                } else {
793                 results[0] = data->ain2_min;
794                 results[1] = data->ain2_max;
795                 results[2] = data->ain2;
796                }
797                *nrels_mag = 3;
798        } else if (operation == SENSORS_PROC_REAL_WRITE) {
799                if (*nrels_mag >= 1) {
800                 if (ctl_name == LM87_SYSCTL_AIN1) {
801                        data->ain1_min = results[0];
802                        lm87_write_value(client, LM87_REG_AIN1_LOW,
803                                            data->ain1_min);
804                 } else {
805                        data->ain2_min = results[0];
806                        lm87_write_value(client, LM87_REG_AIN2_LOW,
807                                            data->ain2_min);
808                 }
809                }
810                if (*nrels_mag >= 2) {
811                 if (ctl_name == LM87_SYSCTL_AIN1) {
812                        data->ain1_max = results[1];
813                        lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT,
814                                            data->ain1_max);
815                 } else {
816                        data->ain2_max = results[1];
817                        lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
818                                            data->ain2_max);
819                 }
820                }
821        }
822}
823#endif
824
825void lm87_fan(struct i2c_client *client, int operation, int ctl_name,
826                 int *nrels_mag, long *results)
827{
828        struct lm87_data *data = client->data;
829
830        if (operation == SENSORS_PROC_REAL_INFO)
831                *nrels_mag = 0;
832        else if (operation == SENSORS_PROC_REAL_READ) {
833                lm87_update_client(client);
834                if (ctl_name == LM87_SYSCTL_FAN1) {
835                 results[0] = FAN_FROM_REG(data->fan_min,
836                                          DIV_FROM_REG(data->fan_div));
837                 results[1] = FAN_FROM_REG(data->fan, 
838                                         DIV_FROM_REG(data->fan_div));
839                } else {
840                 results[0] = FAN_FROM_REG(data->fan2_min,
841                                          DIV_FROM_REG(data->fan2_div));
842                 results[1] = FAN_FROM_REG(data->fan2, 
843                                         DIV_FROM_REG(data->fan2_div));
844                }
845                *nrels_mag = 2;
846        } else if (operation == SENSORS_PROC_REAL_WRITE) {
847                if (*nrels_mag >= 0) {
848                        if (ctl_name == LM87_SYSCTL_FAN1) {
849                         data->fan_min = FAN_TO_REG(results[0],
850                                                   DIV_FROM_REG
851                                                   (data->fan_div));
852                         lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT,
853                                            data->fan_min);
854                        } else {
855                         data->fan2_min = FAN_TO_REG(results[0],
856                                                   DIV_FROM_REG
857                                                   (data->fan2_div));
858                         lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
859                                            data->fan2_min);
860                        }
861                }
862        }
863}
864
865
866void lm87_temp(struct i2c_client *client, int operation, int ctl_name,
867                  int *nrels_mag, long *results)
868{
869        struct lm87_data *data = client->data;
870
871        if (operation == SENSORS_PROC_REAL_INFO)
872                *nrels_mag = 1;
873        else if (operation == SENSORS_PROC_REAL_READ) 
874        {
875           lm87_update_client(client);
876
877           /* find out which temp. is being requested */
878           if (ctl_name == LM87_SYSCTL_TEMP3) 
879           {
880                results[0] = TEMP_LIMIT_FROM_REG(data->ext2_temp_max);
881                results[1] = TEMP_LIMIT_FROM_REG(data->ext2_temp_min);
882                results[2] = TEMP_FROM_REG(data->ext2_temp);
883           }
884           else if(ctl_name == LM87_SYSCTL_TEMP2)
885           {
886                results[0] = TEMP_LIMIT_FROM_REG(data->ext_temp_max);
887                results[1] = TEMP_LIMIT_FROM_REG(data->ext_temp_min);
888                results[2] = TEMP_FROM_REG(data->ext_temp);
889           }
890           else if(ctl_name == LM87_SYSCTL_TEMP1)
891           {
892                results[0] = TEMP_LIMIT_FROM_REG(data->int_temp_max);
893                results[1] = TEMP_LIMIT_FROM_REG(data->int_temp_min);
894                results[2] = TEMP_FROM_REG(data->int_temp);
895           }
896           *nrels_mag = 3;
897        } else if (operation == SENSORS_PROC_REAL_WRITE) {
898                if (*nrels_mag >= 1) {
899                   if (ctl_name == LM87_SYSCTL_TEMP3) {
900                        data->ext2_temp_max = TEMP_LIMIT_TO_REG(results[0]);
901                        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH,
902                                            data->ext2_temp_max);
903                   }
904                   if (ctl_name == LM87_SYSCTL_TEMP2) {
905                        data->ext_temp_max = TEMP_LIMIT_TO_REG(results[0]);
906                        lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH,
907                                            data->ext_temp_max);
908                   }
909                   if (ctl_name == LM87_SYSCTL_TEMP1) {
910                        data->int_temp_max = TEMP_LIMIT_TO_REG(results[0]);
911                        lm87_write_value(client, LM87_REG_INT_TEMP_HIGH,
912                                            data->int_temp_max);
913                   }
914                }
915                if (*nrels_mag >= 2) {
916                   if (ctl_name == LM87_SYSCTL_TEMP3) {
917                        data->ext2_temp_min = TEMP_LIMIT_TO_REG(results[1]);
918                        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW,
919                                            data->ext2_temp_min);
920                   }
921                   if (ctl_name == LM87_SYSCTL_TEMP2) {
922                        data->ext_temp_min = TEMP_LIMIT_TO_REG(results[1]);
923                        lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW,
924                                            data->ext_temp_min);
925                   }
926                   if (ctl_name == LM87_SYSCTL_TEMP1) {
927                        data->int_temp_min = TEMP_LIMIT_TO_REG(results[1]);
928                        lm87_write_value(client, LM87_REG_INT_TEMP_LOW,
929                                            data->int_temp_min);
930                   }
931                }
932        }
933}
934
935void lm87_alarms(struct i2c_client *client, int operation, int ctl_name,
936                    int *nrels_mag, long *results)
937{
938        struct lm87_data *data = client->data;
939        if (operation == SENSORS_PROC_REAL_INFO)
940                *nrels_mag = 0;
941        else if (operation == SENSORS_PROC_REAL_READ) {
942                lm87_update_client(client);
943                results[0] = ALARMS_FROM_REG(data->alarms);
944                *nrels_mag = 1;
945        }
946}
947
948void lm87_fan_div(struct i2c_client *client, int operation,
949                     int ctl_name, int *nrels_mag, long *results)
950{
951/* This gets a little hairy depending on the hardware config */
952
953        struct lm87_data *data = client->data;
954        int old;
955
956        if (operation == SENSORS_PROC_REAL_INFO)
957                *nrels_mag = 0;
958        else if (operation == SENSORS_PROC_REAL_READ) {
959                lm87_update_client(client);
960#ifndef LM87_AIN1
961                results[0] = DIV_FROM_REG(data->fan_div);
962# ifndef LM87_AIN2
963                results[1] = DIV_FROM_REG(data->fan2_div);
964                *nrels_mag = 2;
965# else
966                *nrels_mag = 1;
967# endif
968#else /* Must be referring to fan 2 */
969                results[0] = DIV_FROM_REG(data->fan2_div);
970                *nrels_mag = 1;
971#endif
972        } else if (operation == SENSORS_PROC_REAL_WRITE) {
973                old = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
974/* Note: it's OK to change fan2 div even if fan2 isn't enabled */
975#ifndef LM87_AIN1
976                if (*nrels_mag >= 2) {
977                        data->fan2_div = DIV_TO_REG(results[1]);
978                        old = (old & 0x3f) | (data->fan2_div << 6);
979                }
980                if (*nrels_mag >= 1) {
981                        data->fan_div = DIV_TO_REG(results[0]);
982                        old = (old & 0xcf) | (data->fan_div << 4);
983                        lm87_write_value(client, LM87_REG_VID_FAN_DIV, old);
984                }
985#else /* Must be referring to fan 2 */
986                if (*nrels_mag >= 1) {
987                        data->fan2_div = DIV_TO_REG(results[0]);
988                        old = (old & 0xcf) | (data->fan2_div << 6);
989                        lm87_write_value(client, LM87_REG_VID_FAN_DIV, old);
990                }
991#endif
992        }
993}
994
995void lm87_analog_out(struct i2c_client *client, int operation,
996                        int ctl_name, int *nrels_mag, long *results)
997{
998        struct lm87_data *data = client->data;
999
1000        if (operation == SENSORS_PROC_REAL_INFO)
1001                *nrels_mag = 0;
1002        else if (operation == SENSORS_PROC_REAL_READ) {
1003                lm87_update_client(client);
1004                results[0] = data->analog_out;
1005                *nrels_mag = 1;
1006        } else if (operation == SENSORS_PROC_REAL_WRITE) {
1007                if (*nrels_mag >= 1) {
1008                        data->analog_out = results[0];
1009                        lm87_write_value(client, LM87_REG_ANALOG_OUT,
1010                                            data->analog_out);
1011                }
1012        }
1013}
1014
1015void lm87_vid(struct i2c_client *client, int operation, int ctl_name,
1016                 int *nrels_mag, long *results)
1017{
1018        struct lm87_data *data = client->data;
1019
1020        if (operation == SENSORS_PROC_REAL_INFO)
1021                *nrels_mag = 3;
1022        else if (operation == SENSORS_PROC_REAL_READ) {
1023                lm87_update_client(client);
1024                results[0] = vid_from_reg(data->vid, data->vrm);
1025                *nrels_mag = 1;
1026        }
1027}
1028
1029void lm87_vrm(struct i2c_client *client, int operation, int ctl_name,
1030                 int *nrels_mag, long *results)
1031{
1032        struct lm87_data *data = client->data;
1033        if (operation == SENSORS_PROC_REAL_INFO)
1034                *nrels_mag = 1;
1035        else if (operation == SENSORS_PROC_REAL_READ) {
1036                results[0] = data->vrm;
1037                *nrels_mag = 1;
1038        } else if (operation == SENSORS_PROC_REAL_WRITE) {
1039                if (*nrels_mag >= 1)
1040                        data->vrm = results[0];
1041        }
1042}
1043
1044int __init sensors_lm87_init(void)
1045{
1046        int res;
1047
1048        printk("lm87.o version %s (%s)\n", LM_VERSION, LM_DATE);
1049        lm87_initialized = 0;
1050
1051        if ((res = i2c_add_driver(&LM87_driver))) {
1052                printk
1053                    ("lm87.o: Driver registration failed, module not inserted.\n");
1054                lm87_cleanup();
1055                return res;
1056        }
1057        lm87_initialized++;
1058        return 0;
1059}
1060
1061int __init lm87_cleanup(void)
1062{
1063        int res;
1064
1065        if (lm87_initialized >= 1) {
1066                if ((res = i2c_del_driver(&LM87_driver))) {
1067                        printk
1068                            ("lm87.o: Driver deregistration failed, module not removed.\n");
1069                        return res;
1070                }
1071                lm87_initialized--;
1072        }
1073        return 0;
1074}
1075
1076EXPORT_NO_SYMBOLS;
1077
1078#ifdef MODULE
1079#ifdef MODULE_LICENSE
1080MODULE_LICENSE("GPL");
1081#endif
1082
1083MODULE_AUTHOR
1084    ("Frodo Looijaard <frodol@dds.nl>,
1085      Philip Edelbrock <phil@netroedge.com>, 
1086      Mark Studebaker <mdsxyz123@yahoo.com>,
1087      and Stephen Rousset <stephen.rousset@rocketlogix.com>");
1088
1089MODULE_DESCRIPTION("LM87 driver");
1090
1091int init_module(void)
1092{
1093        return sensors_lm87_init();
1094}
1095
1096int cleanup_module(void)
1097{
1098        return lm87_cleanup();
1099}
1100
1101#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.