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

Revision 953, 30.6 KB (checked in by mds, 14 years ago)

(mds) add lm87 support to 'sensors'. Rename SYSCTL_* values to standard

TEMP[1-3], etc. No fan2 support in driver yet.

  • 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/malloc.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 "i2c-isa.h"
37#include "sensors.h"
38#include <linux/init.h>
39
40#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
41    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
42#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
43#endif
44
45#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
46#define THIS_MODULE NULL
47#endif
48
49/* Addresses to scan */
50static unsigned short normal_i2c[] = { SENSORS_I2C_END };
51static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END };
52static unsigned int normal_isa[] = { SENSORS_ISA_END };
53static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
54
55/* Insmod parameters */
56SENSORS_INSMOD_1(lm87);
57
58/* The following is the calculation for the register offset
59 * for the monitored items minimum and maximum locations.
60 */
61#define LM87_REG_IN_MAX(nr) (0x2b + (nr) * 2)
62#define LM87_REG_IN_MIN(nr) (0x2c + (nr) * 2)
63#define LM87_REG_IN(nr) (0x20 + (nr))
64
65#define AIN1     0
66#define VCCP1    1
67#define VCCP2    5
68
69/* Initial limits */
70
71/*
72 * LM87 register definition
73 *
74 */
75
76      /* The LM87 registers */
77#define LM87_INT_TEMP_HI_LIMIT_LOCKABLE  0x13
78#define LM87_EXT_TEMP_HI_LIMIT_LOCKABLE  0x14
79#define LM87_REG_TEST                    0x15
80#define LM87_REG_CHANNEL_MODE            0x16
81#define LM87_REG_INT_TEMP_HI_LIMIT       0x17
82#define LM87_REG_EXT_TEMP_HI_LIMIT       0x18
83#define LM87_REG_ANALOG_OUT              0x19
84
85      /* These are all read-only */
86#define LM87_REG_2_5V_EXT_TEMP_2         0x20  /* front ambient for us */
87#define LM87_REG_VCCP1                   0x21  /* CPU core voltage */
88#define LM87_REG_3_3V                    0x22 
89#define LM87_REG_5V                      0x23
90#define LM87_REG_12V                     0x24
91#define LM87_REG_VCCP2                   0x25
92#define LM87_REG_EXT_TEMP_1              0x26  /* CPU temp for us */
93#define LM87_REG_INT_TEMP                0x27  /* LM87 temp. */
94#define LM87_REG_FAN1_AIN1               0x28  /* this is AIN: 2.5V monitored */
95#define LM87_REG_FAN2_AIN2               0x29
96
97/* These are read/write */
98#define LM87_REG_2_5V_EXT_TEMP_2_HIGH    0x2B 
99#define LM87_REG_2_5V_EXT_TEMP_2_LOW     0x2C 
100#define LM87_REG_VCCP1_HIGH              0x2D 
101#define LM87_REG_VCCP1_LOW               0x2E 
102#define LM87_REG_3_3V_HIGH               0x2F
103#define LM87_REG_3_3V_LOW                0x30
104#define LM87_REG_5V_HIGH                 0x31
105#define LM87_REG_5V_LOW                  0x32
106#define LM87_REG_12V_HIGH                0x33
107#define LM87_REG_12V_LOW                 0x34
108#define LM87_REG_VCCP2_HIGH              0x35
109#define LM87_REG_VCCP2_LOW               0x36
110#define LM87_REG_EXT_TEMP_1_HIGH         0x37   
111#define LM87_REG_EXT_TEMP_1_LOW          0x38 
112#define LM87_REG_INT_TEMP_HIGH           0x39 
113#define LM87_REG_INT_TEMP_LOW            0x3A 
114#define LM87_REG_FAN1_AIN1_LIMIT         0x3B  /* 2.5V high limit */
115#define LM87_REG_FAN2_AIN2_LIMIT         0x3C
116#define LM87_REG_COMPANY_ID              0x3E
117#define LM87_REG_DIE_REV                 0x3F
118
119#define LM87_REG_CONFIG                  0x40
120#define LM87_REG_INT1_STAT               0x41
121#define LM87_REG_INT2_STAT               0x42
122#define LM87_REG_INT1_MASK               0x43
123#define LM87_REG_INT2_MASK               0x44
124#define LM87_REG_CHASSIS_CLEAR           0x46
125#define LM87_REG_VID_FAN_DIV             0x47
126#define LM87_REG_VID4                    0x49
127#define LM87_REG_CONFIG_2                0x4A
128#define LM87_REG_INTRPT_STATUS_1_MIRROR  0x4C
129#define LM87_REG_INTRPT_STATUS_2_MIRROR  0x4D
130#define LM87_REG_SMBALERT_NUM_ENABLE     0x80
131
132
133
134/* Conversions. Rounding and limit checking is only done on the TO_REG
135   variants. Note that you should be a bit careful with which arguments
136   these macros are called: arguments may be evaluated more than once.
137   Fixing this is just not worth it. */
138#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255))
139#define IN_FROM_REG(val,nr) (val)
140
141extern inline u8 FAN_TO_REG(long rpm, int div)
142{
143        if (rpm == 0)
144                return 255;
145        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
146        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
147                             254);
148}
149
150#define FAN_FROM_REG(val,div) ((val)==0?-1:\
151                               (val)==255?0:1350000/((div)*(val)))
152
153#define TEMP_FROM_REG(temp)  (temp * 10)
154
155#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
156
157#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
158                                                      ((val)+5)/10),0,255)
159#if 0
160#define TEMP_FROM_REG(temp) \
161   ((temp)<256?((((temp)&0x1fe) >> 1) * 10)      + ((temp) & 1) * 5:  \
162               ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5)  \
163
164#define TEMP_LIMIT_FROM_REG(val) (val)
165
166#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val),0,255)
167#endif
168
169
170#define ALARMS_FROM_REG(val) (val)
171
172#define DIV_FROM_REG(val) (1 << (val))
173#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1)))
174
175#if 0
176#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
177                           205-(val)*5)
178#endif
179
180#define LM87_INIT_IN_0 190
181#define LM87_INIT_IN_1 190
182#define LM87_INIT_IN_2 190
183#define LM87_INIT_IN_3 190
184#define LM87_INIT_IN_4 190
185#define LM87_INIT_IN_5 190
186
187#define LM87_INIT_IN_PERCENTAGE 10
188
189/*********  2.5V monitoring limits **********/
190#define LM87_INIT_IN_MIN_0 \
191        (LM87_INIT_IN_0 - ((LM87_INIT_IN_0 * LM87_INIT_IN_PERCENTAGE) / 100))
192#define LM87_INIT_IN_MAX_0 \
193        (LM87_INIT_IN_0 + ((LM87_INIT_IN_0 * LM87_INIT_IN_PERCENTAGE) / 100))
194
195/*********  Vccp1 monitoring limits **********/
196#define LM87_INIT_IN_MIN_1 \
197        (LM87_INIT_IN_1 - ((LM87_INIT_IN_1 * LM87_INIT_IN_PERCENTAGE) / 100))
198#define LM87_INIT_IN_MAX_1 \
199        (LM87_INIT_IN_1 + ((LM87_INIT_IN_1 * LM87_INIT_IN_PERCENTAGE) / 100))
200
201/*********  3.3V monitoring limits **********/
202#define LM87_INIT_IN_MIN_2 \
203        (LM87_INIT_IN_2 - ((LM87_INIT_IN_2 * LM87_INIT_IN_PERCENTAGE) / 100))
204#define LM87_INIT_IN_MAX_2 \
205        (LM87_INIT_IN_2 + ((LM87_INIT_IN_2 * LM87_INIT_IN_PERCENTAGE) / 100))
206
207/*********  5V monitoring limits **********/
208#define LM87_INIT_IN_MIN_3 \
209        (LM87_INIT_IN_3 - ((LM87_INIT_IN_3 * LM87_INIT_IN_PERCENTAGE) / 100))
210#define LM87_INIT_IN_MAX_3 \
211        (LM87_INIT_IN_3 + ((LM87_INIT_IN_3 * LM87_INIT_IN_PERCENTAGE) / 100))
212
213/*********  12V monitoring limits **********/
214#define LM87_INIT_IN_MIN_4 \
215        (LM87_INIT_IN_4 - ((LM87_INIT_IN_4 * LM87_INIT_IN_PERCENTAGE) / 100))
216#define LM87_INIT_IN_MAX_4 \
217        (LM87_INIT_IN_4 + ((LM87_INIT_IN_4 * LM87_INIT_IN_PERCENTAGE) / 100))
218
219/*********  Vccp2 monitoring limits **********/
220#define LM87_INIT_IN_MIN_5 \
221        (LM87_INIT_IN_5 - ((LM87_INIT_IN_5 * LM87_INIT_IN_PERCENTAGE) / 100))
222#define LM87_INIT_IN_MAX_5 \
223        (LM87_INIT_IN_5 + ((LM87_INIT_IN_5 * LM87_INIT_IN_PERCENTAGE) / 100))
224
225#define LM87_INIT_FAN_MIN 3000
226
227#define LM87_INIT_EXT_TEMP_MAX 600
228#define LM87_INIT_EXT_TEMP_MIN 50
229#define LM87_INIT_INT_TEMP_MAX 600
230#define LM87_INIT_INT_TEMP_MIN 50
231
232#ifdef MODULE
233extern int init_module(void);
234extern int cleanup_module(void);
235#endif                          /* MODULE */
236
237/* For each registered LM87, we need to keep some data in memory. That
238   data is pointed to by LM87_list[NR]->data. The structure itself is
239   dynamically allocated, at the same time when a new LM87 client is
240   allocated. */
241struct lm87_data {
242        int sysctl_id;
243        enum chips type;
244
245        struct semaphore update_lock;
246        char valid;             /* !=0 if following fields are valid */
247        unsigned long last_updated;     /* In jiffies */
248
249        u8  in[6];              /* Register value */
250        u8  in_max[6];          /* Register value */
251        u8  in_min[6];          /* Register value */
252        u8  fan;                /* Register value */
253        u8  fan_min;            /* Register value */
254        u8  fan_div;            /* Register encoding, shifted right */
255        int front_amb_temp;     /* Temp, shifted right */
256        int cpu_temp;           /* Temp, shifted right */
257        int int_temp;           /* Temp, shifted right */
258        u8  cpu_temp_max;       /* Register value */
259        u8  cpu_temp_min;       /* Register value */
260        u8  front_amb_temp_max; /* Register value */
261        u8  front_amb_temp_min; /* Register value */
262        u8  int_temp_max;       /* Register value */
263        u8  int_temp_min;       /* Register value */
264        u16 alarms;             /* Register encoding, combined */
265        u8  analog_out;         /* Register value */
266        u8  vid;                /* Register value combined */
267};
268
269
270#ifdef MODULE
271static
272#else
273extern
274#endif
275int __init sensors_lm87_init(void);
276static int __init lm87_cleanup(void);
277
278static int lm87_attach_adapter(struct i2c_adapter *adapter);
279static int lm87_detect(struct i2c_adapter *adapter, int address,
280                          unsigned short flags, int kind);
281static int lm87_detach_client(struct i2c_client *client);
282static int lm87_command(struct i2c_client *client, unsigned int cmd,
283                           void *arg);
284static void lm87_inc_use(struct i2c_client *client);
285static void lm87_dec_use(struct i2c_client *client);
286
287static int lm87_read_value(struct i2c_client *client, u8 register);
288static int lm87_write_value(struct i2c_client *client, u8 register,
289                               u8 value);
290static void lm87_update_client(struct i2c_client *client);
291static void lm87_init_client(struct i2c_client *client);
292
293
294static void lm87_in(struct i2c_client *client, int operation,
295                       int ctl_name, int *nrels_mag, long *results);
296static void lm87_fan(struct i2c_client *client, int operation,
297                        int ctl_name, int *nrels_mag, long *results);
298static void lm87_temp(struct i2c_client *client, int operation,
299                         int ctl_name, int *nrels_mag, long *results);
300static void lm87_alarms(struct i2c_client *client, int operation,
301                           int ctl_name, int *nrels_mag, long *results);
302static void lm87_fan_div(struct i2c_client *client, int operation,
303                            int ctl_name, int *nrels_mag, long *results);
304static void lm87_analog_out(struct i2c_client *client, int operation,
305                               int ctl_name, int *nrels_mag,
306                               long *results);
307static void lm87_vid(struct i2c_client *client, int operation,
308                        int ctl_name, int *nrels_mag, long *results);
309
310/* I choose here for semi-static LM87 allocation. Complete dynamic
311   allocation could also be used; the code needed for this would probably
312   take more memory than the datastructure takes now. */
313static int lm87_id = 0;
314
315static struct i2c_driver lm87_driver = {
316        /* name */          "LM87 sensor driver",
317        /* id */             I2C_DRIVERID_LM87,
318        /* flags */          I2C_DF_NOTIFY,
319        /* attach_adapter */ &lm87_attach_adapter,
320        /* detach_client */  &lm87_detach_client,
321        /* command */        &lm87_command,
322        /* inc_use */        &lm87_inc_use,
323        /* dec_use */        &lm87_dec_use
324};
325
326/* Used by lm87_init/cleanup */
327static int __initdata lm87_initialized = 0;
328
329/* The /proc/sys entries */
330/* These files are created for each detected LM87. This is just a template;
331   though at first sight, you might think we could use a statically
332   allocated list, we need some way to get back to the parent - which
333   is done through one of the 'extra' fields which are initialized
334   when a new copy is allocated. */
335
336static ctl_table lm87_dir_table_template[] = {
337        {LM87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
338          &sensors_sysctl_real, NULL, &lm87_in},
339        {LM87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
340          &sensors_sysctl_real, NULL, &lm87_in},
341        {LM87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
342          &sensors_sysctl_real, NULL, &lm87_in},
343        {LM87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
344          &sensors_sysctl_real, NULL, &lm87_in},
345        {LM87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
346          &sensors_sysctl_real, NULL, &lm87_in},
347        {LM87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real,
348          &sensors_sysctl_real, NULL, &lm87_in},
349        {LM87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
350          &sensors_sysctl_real, NULL, &lm87_fan},
351        {LM87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
352          &sensors_sysctl_real, NULL, &lm87_fan},
353        {LM87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &sensors_proc_real,
354          &sensors_sysctl_real, NULL, &lm87_temp},
355        {LM87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &sensors_proc_real,
356          &sensors_sysctl_real, NULL, &lm87_temp},
357        {LM87_SYSCTL_TEMP3, "temp3", NULL,
358          0, 0644, NULL, &sensors_proc_real,
359          &sensors_sysctl_real, NULL, &lm87_temp},
360        {LM87_SYSCTL_FAN_DIV, "fan_div", NULL,
361          0, 0644, NULL, &sensors_proc_real,
362          &sensors_sysctl_real, NULL, &lm87_fan_div},
363        {LM87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &sensors_proc_real,
364          &sensors_sysctl_real, NULL, &lm87_alarms},
365        {LM87_SYSCTL_ANALOG_OUT, "analog_out", NULL,
366          0, 0644, NULL, &sensors_proc_real,
367          &sensors_sysctl_real, NULL, &lm87_analog_out},
368        {LM87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &sensors_proc_real,
369          &sensors_sysctl_real, NULL, &lm87_vid},
370        {0}
371};
372
373int lm87_attach_adapter(struct i2c_adapter *adapter)
374{
375   int error;
376   struct i2c_client_address_data  lm87_client_data;
377
378   lm87_client_data.normal_i2c       = addr_data.normal_i2c;
379   lm87_client_data.normal_i2c_range = addr_data.normal_i2c_range;
380   lm87_client_data.probe            = addr_data.probe;
381   lm87_client_data.probe_range      = addr_data.probe_range;
382   lm87_client_data.ignore           = addr_data.ignore;
383   lm87_client_data.ignore_range     = addr_data.ignore_range;
384   lm87_client_data.force            = addr_data.forces->force;
385
386        error = i2c_probe(adapter, &lm87_client_data, lm87_detect);
387        sensors_detect(adapter, &addr_data, lm87_detect);
388
389        return error;
390}
391
392static int lm87_detect(struct i2c_adapter *adapter, int address,
393                          unsigned short flags, int kind)
394{
395        int i;
396        struct i2c_client *new_client;
397        struct lm87_data *data;
398        int err = 0;
399        const char *type_name = "";
400        const char *client_name = "";
401
402        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
403                goto ERROR0;
404
405        /* OK. For now, we presume we have a valid client. We now create the
406           client structure, even though we cannot fill it completely yet.
407           But it allows us to access LM87_{read,write}_value. */
408
409        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
410                                   sizeof(struct lm87_data),
411                                   GFP_KERNEL))) {
412                err = -ENOMEM;
413                goto ERROR0;
414        }
415
416        data = (struct lm87_data *) (new_client + 1);
417        new_client->addr = address;
418        new_client->data = data;
419        new_client->adapter = adapter;
420        new_client->driver = &lm87_driver;
421        new_client->flags = 0;
422
423        /* Now, we do the remaining detection. */
424
425        if (kind < 0) {
426            if ((lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) != 0x00)
427               goto ERROR1;
428        }
429
430        /* Fill in the remaining client fields and put into the global list */
431        type_name = "lm87";
432        client_name = "LM87 chip";
433        strcpy(new_client->name, client_name);
434        data->type = kind;
435
436        new_client->id = lm87_id++;
437        data->valid = 0;
438        init_MUTEX(&data->update_lock);
439
440        /* Tell the I2C layer a new client has arrived */
441        if ((err = i2c_attach_client(new_client)))
442                goto ERROR3;
443
444        /* Register a new directory entry with module sensors */
445        if ((i = sensors_register_entry(new_client,
446                                        type_name,
447                                        lm87_dir_table_template,
448                                        THIS_MODULE)) < 0) {
449                err = i;
450                goto ERROR4;
451        }
452        data->sysctl_id = i;
453
454        /* Initialize the LM87 chip */
455        lm87_init_client(new_client);
456        return 0;
457
458/* OK, this is not exactly good programming practice, usually. But it is
459   very code-efficient in this case. */
460
461      ERROR4:
462        i2c_detach_client(new_client);
463      ERROR3:
464      ERROR1:
465        kfree(new_client);
466      ERROR0:
467        return err;
468}
469
470int lm87_detach_client(struct i2c_client *client)
471{
472        int err;
473
474        sensors_deregister_entry(((struct lm87_data *) (client->data))->
475                                 sysctl_id);
476
477        if ((err = i2c_detach_client(client))) {
478                printk
479            ("lm87.o: Client deregistration failed, client not detached.\n");
480                return err;
481        }
482
483        kfree(client);
484
485        return 0;
486
487}
488
489/* No commands defined yet */
490int lm87_command(struct i2c_client *client, unsigned int cmd, void *arg)
491{
492        return 0;
493}
494
495void lm87_inc_use(struct i2c_client *client)
496{
497#ifdef MODULE
498        MOD_INC_USE_COUNT;
499#endif
500}
501
502void lm87_dec_use(struct i2c_client *client)
503{
504#ifdef MODULE
505        MOD_DEC_USE_COUNT;
506#endif
507}
508
509int lm87_read_value(struct i2c_client *client, u8 reg)
510{
511        return 0xFF & i2c_smbus_read_byte_data(client, reg);
512}
513
514int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
515{
516        return i2c_smbus_write_byte_data(client, reg, value);
517}
518
519/* Called when we have found a new LM87. It should set limits, etc. */
520void lm87_init_client(struct i2c_client *client)
521{
522        /* Reset all except Watchdog values and last conversion values
523           This sets fan-divs to 2, among others. This makes most other
524           initializations unnecessary */
525        lm87_write_value(client, LM87_REG_CONFIG, 0x80);
526
527        /* Setup Channel Mode register for configuration of monitoring
528         *      bit 0 - Configures Fan 1/AIN 1 input (1 = AIN)
529         *      bit 2 - Configures 2.5V/D2 input     (1 = 2nd Therm.)
530         */
531        lm87_write_value(client, LM87_REG_CHANNEL_MODE, 0x05);
532
533
534        lm87_write_value(client, LM87_REG_IN_MIN(1),
535                            IN_TO_REG(LM87_INIT_IN_MIN_1, 1));
536        lm87_write_value(client, LM87_REG_IN_MAX(1),
537                            IN_TO_REG(LM87_INIT_IN_MAX_1, 1));
538        lm87_write_value(client, LM87_REG_IN_MIN(2),
539                            IN_TO_REG(LM87_INIT_IN_MIN_2, 2));
540        lm87_write_value(client, LM87_REG_IN_MAX(2),
541                            IN_TO_REG(LM87_INIT_IN_MAX_2, 2));
542        lm87_write_value(client, LM87_REG_IN_MIN(3),
543                            IN_TO_REG(LM87_INIT_IN_MIN_3, 3));
544        lm87_write_value(client, LM87_REG_IN_MAX(3),
545                            IN_TO_REG(LM87_INIT_IN_MAX_3, 3));
546        lm87_write_value(client, LM87_REG_IN_MIN(4),
547                            IN_TO_REG(LM87_INIT_IN_MIN_4, 4));
548        lm87_write_value(client, LM87_REG_IN_MAX(4),
549                            IN_TO_REG(LM87_INIT_IN_MAX_4, 4));
550        lm87_write_value(client, LM87_REG_IN_MIN(5),
551                            IN_TO_REG(LM87_INIT_IN_MIN_5, 5));
552        lm87_write_value(client, LM87_REG_IN_MAX(5),
553                            IN_TO_REG(LM87_INIT_IN_MAX_5, 5));
554
555        lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH,
556                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MAX));
557        lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW,
558                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MIN));
559        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH,
560                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MAX));
561        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW,
562                            TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MIN));
563        lm87_write_value(client, LM87_REG_INT_TEMP_HIGH,
564                            TEMP_LIMIT_TO_REG(LM87_INIT_INT_TEMP_MAX));
565        lm87_write_value(client, LM87_REG_INT_TEMP_LOW,
566                            TEMP_LIMIT_TO_REG(LM87_INIT_INT_TEMP_MIN));
567
568        lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT,
569                            IN_TO_REG(LM87_INIT_IN_MAX_0, 0));
570
571        lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
572                            FAN_TO_REG(LM87_INIT_FAN_MIN, 2));
573
574        /* Start monitoring */
575        lm87_write_value(client, LM87_REG_CONFIG, 0x01);
576}
577
578void lm87_update_client(struct i2c_client *client)
579{
580        struct lm87_data *data = client->data;
581        u8 i;
582
583        down(&data->update_lock);
584
585        if ((jiffies - data->last_updated > HZ) ||  /* 1 sec cache */
586            (jiffies < data->last_updated)      || 
587             !data->valid) {
588
589#ifdef DEBUG
590                printk("Starting LM87 update\n");
591#endif
592                for (i = 0; i <= 5; i++) { 
593                    /* Since we are using AIN 1 as our 2.5V monitoring, need to
594                     * accomodate with a hardcode
595                     * register address and we only get
596                     * to look at one threshold.
597                     */
598                    if (i == 0) {
599                        data->in[i] = 
600                            lm87_read_value(client, LM87_REG_FAN1_AIN1);
601                        data->in_min[i] = 0;
602                        data->in_max[i] = 
603                            lm87_read_value(client, LM87_REG_FAN1_AIN1_LIMIT);
604                    }
605                    else {
606                        data->in[i] = 
607                            lm87_read_value(client, LM87_REG_IN(i));
608                        data->in_min[i] = 
609                            lm87_read_value(client,
610                                               LM87_REG_IN_MIN(i));
611                        data->in_max[i] = 
612                            lm87_read_value(client,
613                                               LM87_REG_IN_MAX(i));
614                    }
615                }
616
617                data->fan =
618                    lm87_read_value(client, LM87_REG_FAN2_AIN2);
619                data->fan_min =
620                    lm87_read_value(client, LM87_REG_FAN2_AIN2_LIMIT);
621
622                data->front_amb_temp =
623                    lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2);
624                data->cpu_temp =
625                    lm87_read_value(client, LM87_REG_EXT_TEMP_1);
626                data->int_temp =
627                    lm87_read_value(client, LM87_REG_INT_TEMP);
628
629                data->front_amb_temp_max =
630                    lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH);
631                data->front_amb_temp_min =
632                    lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW);
633
634                data->cpu_temp_max =
635                    lm87_read_value(client, LM87_REG_EXT_TEMP_1_HIGH);
636                data->cpu_temp_min =
637                    lm87_read_value(client, LM87_REG_EXT_TEMP_1_LOW);
638
639                data->int_temp_max =
640                    lm87_read_value(client, LM87_REG_INT_TEMP_HIGH);
641                data->int_temp_min =
642                    lm87_read_value(client, LM87_REG_INT_TEMP_LOW);
643
644                i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
645                data->fan_div = (i >> 4) & 0x03;
646                data->vid = i & 0x0f;
647                data->vid |=
648                    (lm87_read_value(client, LM87_REG_VID4) & 0x01)
649                    << 4;
650
651                data->alarms =
652                    lm87_read_value(client,
653                                       LM87_REG_INT1_STAT) +
654                    (lm87_read_value(client, LM87_REG_INT2_STAT) <<
655                     8);
656                data->analog_out =
657                    lm87_read_value(client, LM87_REG_ANALOG_OUT);
658                data->last_updated = jiffies;
659                data->valid = 1;
660        }
661
662        up(&data->update_lock);
663}
664
665
666/* The next few functions are the call-back functions of the /proc/sys and
667   sysctl files. Which function is used is defined in the ctl_table in
668   the extra1 field.
669   Each function must return the magnitude (power of 10 to divide the date
670   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
671   put a maximum of *nrels elements in results reflecting the data of this
672   file, and set *nrels to the number it actually put in it, if operation==
673   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
674   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
675   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
676   large enough (by checking the incoming value of *nrels). This is not very
677   good practice, but as long as you put less than about 5 values in results,
678   you can assume it is large enough. */
679void lm87_in(struct i2c_client *client, int operation, int ctl_name,
680                int *nrels_mag, long *results)
681{
682
683        /************************************************************
684         * These values represent 2.5V, Vccp1, 3.3V, 5V, 12V & Vccp2
685         *   The 2.5V is 50% sampled for our application, so check
686         *   against 1.25V value.
687         ************************************************************/
688        int scales[6] = { 260, 200, 344, 520, 1250, 260 };
689
690        struct lm87_data *data = client->data;
691        int nr = ctl_name - LM87_SYSCTL_IN0;
692
693        if (operation == SENSORS_PROC_REAL_INFO)
694                *nrels_mag = 2;
695        else if (operation == SENSORS_PROC_REAL_READ) {
696                lm87_update_client(client);
697
698                results[0] =
699                    IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192;
700                results[1] =
701                    IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192;
702 
703                if (nr == AIN1) {
704                   results[2] = ((data->in[nr] * 10) * 98) / 1000;
705                }
706                else if (nr == VCCP1 || nr == VCCP2) {
707                   results[2] = ((data->in[nr] * 10) * 141) / 1000;
708                }
709                else {
710                   results[2] =
711                       IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192;
712                }
713
714                *nrels_mag = 3;
715        } else if (operation == SENSORS_PROC_REAL_WRITE) {
716                if (*nrels_mag >= 1) {
717                        data->in_min[nr] =
718                            IN_TO_REG((results[0] * 192) / scales[nr], nr);
719                        lm87_write_value(client, LM87_REG_IN_MIN(nr),
720                                            data->in_min[nr]);
721                }
722                if (*nrels_mag >= 2) {
723                        data->in_max[nr] =
724                            IN_TO_REG((results[1] * 192) / scales[nr], nr);
725                        lm87_write_value(client, LM87_REG_IN_MAX(nr),
726                                            data->in_max[nr]);
727                }
728        }
729}
730
731void lm87_fan(struct i2c_client *client, int operation, int ctl_name,
732                 int *nrels_mag, long *results)
733{
734        struct lm87_data *data = client->data;
735/*
736  need to fix this function to handle both fans
737        int nr = ctl_name - LM87_SYSCTL_FAN + 1;
738*/
739
740        if (operation == SENSORS_PROC_REAL_INFO)
741                *nrels_mag = 0;
742        else if (operation == SENSORS_PROC_REAL_READ) {
743                lm87_update_client(client);
744                results[0] = FAN_FROM_REG(data->fan_min,
745                                          DIV_FROM_REG(data->fan_div));
746                results[1] = FAN_FROM_REG(data->fan, 
747                                         DIV_FROM_REG(data->fan_div));
748                *nrels_mag = 2;
749        } else if (operation == SENSORS_PROC_REAL_WRITE) {
750                if (*nrels_mag >= 0) {
751                        data->fan_min = FAN_TO_REG(results[0],
752                                                   DIV_FROM_REG
753                                                   (data->fan_div));
754                        lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
755                                            data->fan_min);
756                }
757        }
758}
759
760
761void lm87_temp(struct i2c_client *client, int operation, int ctl_name,
762                  int *nrels_mag, long *results)
763{
764        struct lm87_data *data = client->data;
765
766        if (operation == SENSORS_PROC_REAL_INFO)
767                *nrels_mag = 1;
768        else if (operation == SENSORS_PROC_REAL_READ) 
769        {
770           lm87_update_client(client);
771
772           /* find out which temp. is being requested */
773           if (ctl_name == LM87_SYSCTL_TEMP3) 
774           {
775                results[0] = TEMP_LIMIT_FROM_REG(data->front_amb_temp_max);
776                results[1] = TEMP_LIMIT_FROM_REG(data->front_amb_temp_min);
777                results[2] = TEMP_FROM_REG(data->front_amb_temp);
778           }
779           else if(ctl_name == LM87_SYSCTL_TEMP2)
780           {
781                results[0] = TEMP_LIMIT_FROM_REG(data->cpu_temp_max);
782                results[1] = TEMP_LIMIT_FROM_REG(data->cpu_temp_min);
783                results[2] = TEMP_FROM_REG(data->cpu_temp);
784           }
785           else if(ctl_name == LM87_SYSCTL_TEMP1)
786           {
787                results[0] = TEMP_LIMIT_FROM_REG(data->int_temp_max);
788                results[1] = TEMP_LIMIT_FROM_REG(data->int_temp_min);
789                results[2] = TEMP_FROM_REG(data->int_temp);
790           }
791           *nrels_mag = 3;
792        } else if (operation == SENSORS_PROC_REAL_WRITE) {
793                if (*nrels_mag >= 1) {
794                   if (ctl_name == LM87_SYSCTL_TEMP3) {
795                        data->front_amb_temp_max =
796                                             TEMP_LIMIT_TO_REG(results[0]);
797                        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH,
798                                            data->front_amb_temp_max);
799                   }
800                   if (ctl_name == LM87_SYSCTL_TEMP2) {
801                        data->cpu_temp_max = TEMP_LIMIT_TO_REG(results[0]);
802                        lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH,
803                                            data->int_temp_max);
804                   }
805                   if (ctl_name == LM87_SYSCTL_TEMP1) {
806                        data->int_temp_max = TEMP_LIMIT_TO_REG(results[0]);
807                        lm87_write_value(client, LM87_REG_INT_TEMP_HIGH,
808                                            data->int_temp_max);
809                   }
810                }
811                if (*nrels_mag >= 2) {
812                   if (ctl_name == LM87_SYSCTL_TEMP3) {
813                        data->front_amb_temp_min =
814                                          TEMP_LIMIT_TO_REG(results[0]);
815                        lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW,
816                                            data->front_amb_temp_min);
817                   }
818                   if (ctl_name == LM87_SYSCTL_TEMP2) {
819                        data->cpu_temp_min = TEMP_LIMIT_TO_REG(results[0]);
820                        lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW,
821                                            data->int_temp_min);
822                   }
823                   if (ctl_name == LM87_SYSCTL_TEMP1) {
824                        data->int_temp_min = TEMP_LIMIT_TO_REG(results[1]);
825                        lm87_write_value(client, LM87_REG_INT_TEMP_LOW,
826                                            data->int_temp_min);
827                   }
828                }
829        }
830}
831
832void lm87_alarms(struct i2c_client *client, int operation, int ctl_name,
833                    int *nrels_mag, long *results)
834{
835        struct lm87_data *data = client->data;
836        if (operation == SENSORS_PROC_REAL_INFO)
837                *nrels_mag = 0;
838        else if (operation == SENSORS_PROC_REAL_READ) {
839                lm87_update_client(client);
840                results[0] = ALARMS_FROM_REG(data->alarms);
841                *nrels_mag = 1;
842        }
843}
844
845void lm87_fan_div(struct i2c_client *client, int operation,
846                     int ctl_name, int *nrels_mag, long *results)
847{
848        struct lm87_data *data = client->data;
849        int old;
850
851        if (operation == SENSORS_PROC_REAL_INFO)
852                *nrels_mag = 0;
853        else if (operation == SENSORS_PROC_REAL_READ) {
854                lm87_update_client(client);
855                results[0] = DIV_FROM_REG(data->fan_div);
856                *nrels_mag = 1;
857        } else if (operation == SENSORS_PROC_REAL_WRITE) {
858                old = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
859                if (*nrels_mag >= 2) {
860                        data->fan_div = DIV_TO_REG(results[1]);
861                        old = (old & 0x3f) | (data->fan_div << 6);
862                }
863                if (*nrels_mag >= 1) {
864                        data->fan_div = DIV_TO_REG(results[0]);
865                        old = (old & 0xcf) | (data->fan_div << 4);
866                        lm87_write_value(client, LM87_REG_VID_FAN_DIV, old);
867                }
868        }
869}
870
871void lm87_analog_out(struct i2c_client *client, int operation,
872                        int ctl_name, int *nrels_mag, long *results)
873{
874        struct lm87_data *data = client->data;
875
876        if (operation == SENSORS_PROC_REAL_INFO)
877                *nrels_mag = 0;
878        else if (operation == SENSORS_PROC_REAL_READ) {
879                lm87_update_client(client);
880                results[0] = data->analog_out;
881                *nrels_mag = 1;
882        } else if (operation == SENSORS_PROC_REAL_WRITE) {
883                if (*nrels_mag >= 1) {
884                        data->analog_out = results[0];
885                        lm87_write_value(client, LM87_REG_ANALOG_OUT,
886                                            data->analog_out);
887                }
888        }
889}
890
891void lm87_vid(struct i2c_client *client, int operation, int ctl_name,
892                 int *nrels_mag, long *results)
893{
894        struct lm87_data *data = client->data;
895
896
897        if (operation == SENSORS_PROC_REAL_INFO)
898                *nrels_mag = 2;
899        else if (operation == SENSORS_PROC_REAL_READ) {
900
901                lm87_update_client(client);
902                if ((data->vid == 0x1f) || (data->vid == 0x0f)) {
903                   results[0] = 0;
904                }
905                else if (data->vid > 0x0f) {
906                   results[0] = (1275 -
907                        (((data->vid - 0x10) * 1000) * 0.025))/10;
908                }
909                else {
910                   results[0] = 200 - ((data->vid * 100) * 0.05);
911                }
912                 
913              *nrels_mag = 1;
914        }
915}
916
917int __init sensors_lm87_init(void)
918{
919        int res;
920
921        printk("lm87.o version %s (%s)\n", LM_VERSION, LM_DATE);
922        lm87_initialized = 0;
923
924        if ((res = i2c_add_driver(&lm87_driver))) {
925                printk
926                ("lm87.o: Driver registration failed, module not inserted.\n");
927                lm87_cleanup();
928                return res;
929        }
930        lm87_initialized++;
931        return 0;
932}
933
934int __init lm87_cleanup(void)
935{
936        int res;
937
938        if (lm87_initialized >= 1) {
939                if ((res = i2c_del_driver(&lm87_driver))) {
940                        printk
941               ("lm87.o: Driver deregistration failed, module not removed.\n");
942                        return res;
943                }
944                lm87_initialized--;
945        }
946        return 0;
947}
948
949EXPORT_NO_SYMBOLS;
950
951#ifdef MODULE
952
953MODULE_AUTHOR
954    ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>,
955      and Stephen Rousset <stephen.rousset@rocketlogix.com>");
956
957MODULE_DESCRIPTION("lm87 driver");
958
959int init_module(void)
960{
961        return sensors_lm87_init();
962}
963
964int cleanup_module(void)
965{
966        return lm87_cleanup();
967}
968
969#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.