root/lm-sensors/trunk/kernel/chips/lm78.c @ 707

Revision 707, 26.7 KB (checked in by frodo, 13 years ago)

`indent -kr -i8' on all kernel sources

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    lm78.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include <linux/version.h>
22#include <linux/module.h>
23#include <linux/malloc.h>
24#include <linux/proc_fs.h>
25#include <linux/ioport.h>
26#include <linux/sysctl.h>
27#include <asm/errno.h>
28#include <asm/io.h>
29#include <linux/types.h>
30#include <linux/i2c.h>
31#include "version.h"
32#include "i2c-isa.h"
33#include "sensors.h"
34#include <linux/init.h>
35
36#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1))
37#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
38#endif
39
40#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
41#define THIS_MODULE NULL
42#endif
43
44/* Addresses to scan */
45static unsigned short normal_i2c[] = { SENSORS_I2C_END };
46static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END };
47static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END };
48static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
49
50/* Insmod parameters */
51SENSORS_INSMOD_3(lm78, lm78j, lm79);
52
53/* Many LM78 constants specified below */
54
55/* Length of ISA address segment */
56#define LM78_EXTENT 8
57
58/* Where are the ISA address/data registers relative to the base address */
59#define LM78_ADDR_REG_OFFSET 5
60#define LM78_DATA_REG_OFFSET 6
61
62/* The LM78 registers */
63#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2)
64#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2)
65#define LM78_REG_IN(nr) (0x20 + (nr))
66
67#define LM78_REG_FAN_MIN(nr) (0x3a + (nr))
68#define LM78_REG_FAN(nr) (0x27 + (nr))
69
70#define LM78_REG_TEMP 0x27
71#define LM78_REG_TEMP_OVER 0x39
72#define LM78_REG_TEMP_HYST 0x3a
73
74#define LM78_REG_ALARM1 0x41
75#define LM78_REG_ALARM2 0x42
76
77#define LM78_REG_VID_FANDIV 0x47
78
79#define LM78_REG_CONFIG 0x40
80#define LM78_REG_CHIPID 0x49
81#define LM78_REG_I2C_ADDR 0x48
82
83
84/* Conversions. Rounding and limit checking is only done on the TO_REG
85   variants. Note that you should be a bit careful with which arguments
86   these macros are called: arguments may be evaluated more than once.
87   Fixing this is just not worth it. */
88#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
89#define IN_FROM_REG(val) (((val) *  16) / 10)
90
91extern inline u8 FAN_TO_REG(long rpm, int div)
92{
93        if (rpm == 0)
94                return 255;
95        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
96        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
97                             254);
98}
99
100#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
101
102#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
103                                                 ((val)+5)/10),0,255))
104#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
105
106#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
107                           205-(val)*5)
108#define ALARMS_FROM_REG(val) (val)
109
110#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
111#define DIV_FROM_REG(val) (1 << (val))
112
113/* Initial limits. To keep them sane, we use the 'standard' translation as
114   specified in the LM78 sheet. Use the config file to set better limits. */
115#define LM78_INIT_IN_0 (vid==350?280:vid)
116#define LM78_INIT_IN_1 (vid==350?280:vid)
117#define LM78_INIT_IN_2 330
118#define LM78_INIT_IN_3 (((500)   * 100)/168)
119#define LM78_INIT_IN_4 (((1200)  * 10)/38)
120#define LM78_INIT_IN_5 (((-1200) * -604)/2100)
121#define LM78_INIT_IN_6 (((-500)  * -604)/909)
122
123#define LM78_INIT_IN_PERCENTAGE 10
124
125#define LM78_INIT_IN_MIN_0 \
126        (LM78_INIT_IN_0 - LM78_INIT_IN_0 * LM78_INIT_IN_PERCENTAGE / 100)
127#define LM78_INIT_IN_MAX_0 \
128        (LM78_INIT_IN_0 + LM78_INIT_IN_0 * LM78_INIT_IN_PERCENTAGE / 100)
129#define LM78_INIT_IN_MIN_1 \
130        (LM78_INIT_IN_1 - LM78_INIT_IN_1 * LM78_INIT_IN_PERCENTAGE / 100)
131#define LM78_INIT_IN_MAX_1 \
132        (LM78_INIT_IN_1 + LM78_INIT_IN_1 * LM78_INIT_IN_PERCENTAGE / 100)
133#define LM78_INIT_IN_MIN_2 \
134        (LM78_INIT_IN_2 - LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100)
135#define LM78_INIT_IN_MAX_2 \
136        (LM78_INIT_IN_2 + LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100)
137#define LM78_INIT_IN_MIN_3 \
138        (LM78_INIT_IN_3 - LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100)
139#define LM78_INIT_IN_MAX_3 \
140        (LM78_INIT_IN_3 + LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100)
141#define LM78_INIT_IN_MIN_4 \
142        (LM78_INIT_IN_4 - LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100)
143#define LM78_INIT_IN_MAX_4 \
144        (LM78_INIT_IN_4 + LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100)
145#define LM78_INIT_IN_MIN_5 \
146        (LM78_INIT_IN_5 - LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100)
147#define LM78_INIT_IN_MAX_5 \
148        (LM78_INIT_IN_5 + LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100)
149#define LM78_INIT_IN_MIN_6 \
150        (LM78_INIT_IN_6 - LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100)
151#define LM78_INIT_IN_MAX_6 \
152        (LM78_INIT_IN_6 + LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100)
153
154#define LM78_INIT_FAN_MIN_1 3000
155#define LM78_INIT_FAN_MIN_2 3000
156#define LM78_INIT_FAN_MIN_3 3000
157
158#define LM78_INIT_TEMP_OVER 600
159#define LM78_INIT_TEMP_HYST 500
160
161#ifdef MODULE
162extern int init_module(void);
163extern int cleanup_module(void);
164#endif                          /* MODULE */
165
166/* There are some complications in a module like this. First off, LM78 chips
167   may be both present on the SMBus and the ISA bus, and we have to handle
168   those cases separately at some places. Second, there might be several
169   LM78 chips available (well, actually, that is probably never done; but
170   it is a clean illustration of how to handle a case like that). Finally,
171   a specific chip may be attached to *both* ISA and SMBus, and we would
172   not like to detect it double. Fortunately, in the case of the LM78 at
173   least, a register tells us what SMBus address we are on, so that helps
174   a bit - except if there could be more than one SMBus. Groan. No solution
175   for this yet. */
176
177/* This module may seem overly long and complicated. In fact, it is not so
178   bad. Quite a lot of bookkeeping is done. A real driver can often cut
179   some corners. */
180
181/* For each registered LM78, we need to keep some data in memory. That
182   data is pointed to by lm78_list[NR]->data. The structure itself is
183   dynamically allocated, at the same time when a new lm78 client is
184   allocated. */
185struct lm78_data {
186        struct semaphore lock;
187        int sysctl_id;
188        enum chips type;
189
190        struct semaphore update_lock;
191        char valid;             /* !=0 if following fields are valid */
192        unsigned long last_updated;     /* In jiffies */
193
194        u8 in[7];               /* Register value */
195        u8 in_max[7];           /* Register value */
196        u8 in_min[7];           /* Register value */
197        u8 fan[3];              /* Register value */
198        u8 fan_min[3];          /* Register value */
199        u8 temp;                /* Register value */
200        u8 temp_over;           /* Register value */
201        u8 temp_hyst;           /* Register value */
202        u8 fan_div[3];          /* Register encoding, shifted right */
203        u8 vid;                 /* Register encoding, combined */
204        u16 alarms;             /* Register encoding, combined */
205};
206
207
208#ifdef MODULE
209static
210#else
211extern
212#endif
213int __init sensors_lm78_init(void);
214static int __init lm78_cleanup(void);
215
216static int lm78_attach_adapter(struct i2c_adapter *adapter);
217static int lm78_detect(struct i2c_adapter *adapter, int address,
218                       unsigned short flags, int kind);
219static int lm78_detach_client(struct i2c_client *client);
220static int lm78_command(struct i2c_client *client, unsigned int cmd,
221                        void *arg);
222static void lm78_inc_use(struct i2c_client *client);
223static void lm78_dec_use(struct i2c_client *client);
224
225static int lm78_read_value(struct i2c_client *client, u8 register);
226static int lm78_write_value(struct i2c_client *client, u8 register,
227                            u8 value);
228static void lm78_update_client(struct i2c_client *client);
229static void lm78_init_client(struct i2c_client *client);
230
231
232static void lm78_in(struct i2c_client *client, int operation, int ctl_name,
233                    int *nrels_mag, long *results);
234static void lm78_fan(struct i2c_client *client, int operation,
235                     int ctl_name, int *nrels_mag, long *results);
236static void lm78_temp(struct i2c_client *client, int operation,
237                      int ctl_name, int *nrels_mag, long *results);
238static void lm78_vid(struct i2c_client *client, int operation,
239                     int ctl_name, int *nrels_mag, long *results);
240static void lm78_alarms(struct i2c_client *client, int operation,
241                        int ctl_name, int *nrels_mag, long *results);
242static void lm78_fan_div(struct i2c_client *client, int operation,
243                         int ctl_name, int *nrels_mag, long *results);
244
245static struct i2c_driver lm78_driver = {
246        /* name */ "LM78(-J) and LM79 sensor driver",
247        /* id */ I2C_DRIVERID_LM78,
248        /* flags */ I2C_DF_NOTIFY,
249        /* attach_adapter */ &lm78_attach_adapter,
250        /* detach_client */ &lm78_detach_client,
251        /* command */ &lm78_command,
252        /* inc_use */ &lm78_inc_use,
253        /* dec_use */ &lm78_dec_use
254};
255
256/* Used by lm78_init/cleanup */
257static int __initdata lm78_initialized = 0;
258
259static int lm78_id = 0;
260
261/* The /proc/sys entries */
262/* These files are created for each detected LM78. This is just a template;
263   though at first sight, you might think we could use a statically
264   allocated list, we need some way to get back to the parent - which
265   is done through one of the 'extra' fields which are initialized
266   when a new copy is allocated. */
267static ctl_table lm78_dir_table_template[] = {
268        {LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
269         &sensors_sysctl_real, NULL, &lm78_in},
270        {LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
271         &sensors_sysctl_real, NULL, &lm78_in},
272        {LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
273         &sensors_sysctl_real, NULL, &lm78_in},
274        {LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
275         &sensors_sysctl_real, NULL, &lm78_in},
276        {LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
277         &sensors_sysctl_real, NULL, &lm78_in},
278        {LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real,
279         &sensors_sysctl_real, NULL, &lm78_in},
280        {LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real,
281         &sensors_sysctl_real, NULL, &lm78_in},
282        {LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
283         &sensors_sysctl_real, NULL, &lm78_fan},
284        {LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
285         &sensors_sysctl_real, NULL, &lm78_fan},
286        {LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real,
287         &sensors_sysctl_real, NULL, &lm78_fan},
288        {LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
289         &sensors_sysctl_real, NULL, &lm78_temp},
290        {LM78_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &sensors_proc_real,
291         &sensors_sysctl_real, NULL, &lm78_vid},
292        {LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real,
293         &sensors_sysctl_real, NULL, &lm78_fan_div},
294        {LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &sensors_proc_real,
295         &sensors_sysctl_real, NULL, &lm78_alarms},
296        {0}
297};
298
299
300/* This function is called when:
301     * lm78_driver is inserted (when this module is loaded), for each
302       available adapter
303     * when a new adapter is inserted (and lm78_driver is still present) */
304int lm78_attach_adapter(struct i2c_adapter *adapter)
305{
306        return sensors_detect(adapter, &addr_data, lm78_detect);
307}
308
309/* This function is called by sensors_detect */
310int lm78_detect(struct i2c_adapter *adapter, int address,
311                unsigned short flags, int kind)
312{
313        int i;
314        struct i2c_client *new_client;
315        struct lm78_data *data;
316        int err = 0;
317        const char *type_name = "";
318        const char *client_name = "";
319        int is_isa = i2c_is_isa_adapter(adapter);
320
321        if (!is_isa
322            && !i2c_check_functionality(adapter,
323                                        I2C_FUNC_SMBUS_BYTE_DATA)) goto
324                    ERROR0;
325
326        if (is_isa) {
327                if (check_region(address, LM78_EXTENT))
328                        goto ERROR0;
329        }
330
331        /* Probe whether there is anything available on this address. Already
332           done for SMBus clients */
333        if (kind < 0) {
334                if (is_isa) {
335
336#define REALLY_SLOW_IO
337                        /* We need the timeouts for at least some LM78-like chips. But only
338                           if we read 'undefined' registers. */
339                        i = inb_p(address + 1);
340                        if (inb_p(address + 2) != i)
341                                goto ERROR0;
342                        if (inb_p(address + 3) != i)
343                                goto ERROR0;
344                        if (inb_p(address + 7) != i)
345                                goto ERROR0;
346#undef REALLY_SLOW_IO
347
348                        /* Let's just hope nothing breaks here */
349                        i = inb_p(address + 5) & 0x7f;
350                        outb_p(~i & 0x7f, address + 5);
351                        if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
352                                outb_p(i, address + 5);
353                                return 0;
354                        }
355                }
356        }
357
358        /* OK. For now, we presume we have a valid client. We now create the
359           client structure, even though we cannot fill it completely yet.
360           But it allows us to access lm78_{read,write}_value. */
361
362        if (!(new_client = kmalloc((sizeof(struct i2c_client)) +
363                                   sizeof(struct lm78_data),
364                                   GFP_KERNEL))) {
365                err = -ENOMEM;
366                goto ERROR0;
367        }
368
369        data = (struct lm78_data *) (new_client + 1);
370        if (is_isa)
371                init_MUTEX(&data->lock);
372        new_client->addr = address;
373        new_client->data = data;
374        new_client->adapter = adapter;
375        new_client->driver = &lm78_driver;
376        new_client->flags = 0;
377
378        /* Now, we do the remaining detection. */
379
380        if (kind < 0) {
381                if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80)
382                        goto ERROR1;
383                if (!is_isa
384                    && (lm78_read_value(new_client, LM78_REG_I2C_ADDR) !=
385                        address)) goto ERROR1;
386        }
387
388        /* Determine the chip type. */
389        if (kind <= 0) {
390                i = lm78_read_value(new_client, LM78_REG_CHIPID);
391                if (i == 0x00)
392                        kind = lm78;
393                else if (i == 0x40)
394                        kind = lm78j;
395                else if ((i & 0xfe) == 0xc0)
396                        kind = lm79;
397                else {
398                        if (kind == 0)
399                                printk
400                                    ("lm78.o: Ignoring 'force' parameter for unknown chip at "
401                                     "adapter %d, address 0x%02x\n",
402                                     i2c_adapter_id(adapter), address);
403                        goto ERROR1;
404                }
405        }
406
407        if (kind == lm78) {
408                type_name = "lm78";
409                client_name = "LM78 chip";
410        } else if (kind == lm78j) {
411                type_name = "lm78-j";
412                client_name = "LM78-J chip";
413        } else if (kind == lm79) {
414                type_name = "lm79";
415                client_name = "LM79 chip";
416        } else {
417#ifdef DEBUG
418                printk("lm78.o: Internal error: unknown kind (%d)?!?",
419                       kind);
420#endif
421                goto ERROR1;
422        }
423
424        /* Reserve the ISA region */
425        if (is_isa)
426                request_region(address, LM78_EXTENT, type_name);
427
428        /* Fill in the remaining client fields and put it into the global list */
429        strcpy(new_client->name, client_name);
430        data->type = kind;
431
432        new_client->id = lm78_id++;
433        data->valid = 0;
434        init_MUTEX(&data->update_lock);
435
436        /* Tell the I2C layer a new client has arrived */
437        if ((err = i2c_attach_client(new_client)))
438                goto ERROR3;
439
440        /* Register a new directory entry with module sensors */
441        if ((i = sensors_register_entry(new_client,
442                                        type_name,
443                                        lm78_dir_table_template,
444                                        THIS_MODULE)) < 0) {
445                err = i;
446                goto ERROR4;
447        }
448        data->sysctl_id = i;
449
450        /* Initialize the LM78 chip */
451        lm78_init_client(new_client);
452        return 0;
453
454/* OK, this is not exactly good programming practice, usually. But it is
455   very code-efficient in this case. */
456
457      ERROR4:
458        i2c_detach_client(new_client);
459      ERROR3:
460        if (is_isa)
461                release_region(address, LM78_EXTENT);
462      ERROR1:
463        kfree(new_client);
464      ERROR0:
465        return err;
466}
467
468int lm78_detach_client(struct i2c_client *client)
469{
470        int err;
471
472        sensors_deregister_entry(((struct lm78_data *) (client->data))->
473                                 sysctl_id);
474
475        if ((err = i2c_detach_client(client))) {
476                printk
477                    ("lm78.o: Client deregistration failed, client not detached.\n");
478                return err;
479        }
480
481        if i2c_is_isa_client
482                (client)
483                    release_region(client->addr, LM78_EXTENT);
484        kfree(client);
485
486        return 0;
487}
488
489/* No commands defined yet */
490int lm78_command(struct i2c_client *client, unsigned int cmd, void *arg)
491{
492        return 0;
493}
494
495/* Nothing here yet */
496void lm78_inc_use(struct i2c_client *client)
497{
498#ifdef MODULE
499        MOD_INC_USE_COUNT;
500#endif
501}
502
503/* Nothing here yet */
504void lm78_dec_use(struct i2c_client *client)
505{
506#ifdef MODULE
507        MOD_DEC_USE_COUNT;
508#endif
509}
510
511
512/* The SMBus locks itself, but ISA access must be locked explicitely!
513   We don't want to lock the whole ISA bus, so we lock each client
514   separately.
515   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
516   would slow down the LM78 access and should not be necessary.
517   There are some ugly typecasts here, but the good new is - they should
518   nowhere else be necessary! */
519int lm78_read_value(struct i2c_client *client, u8 reg)
520{
521        int res;
522        if (i2c_is_isa_client(client)) {
523                down(&(((struct lm78_data *) (client->data))->lock));
524                outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
525                res = inb_p(client->addr + LM78_DATA_REG_OFFSET);
526                up(&(((struct lm78_data *) (client->data))->lock));
527                return res;
528        } else
529                return i2c_smbus_read_byte_data(client, reg);
530}
531
532/* The SMBus locks itself, but ISA access muse be locked explicitely!
533   We don't want to lock the whole ISA bus, so we lock each client
534   separately.
535   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
536   would slow down the LM78 access and should not be necessary.
537   There are some ugly typecasts here, but the good new is - they should
538   nowhere else be necessary! */
539int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
540{
541        if (i2c_is_isa_client(client)) {
542                down(&(((struct lm78_data *) (client->data))->lock));
543                outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
544                outb_p(value, client->addr + LM78_DATA_REG_OFFSET);
545                up(&(((struct lm78_data *) (client->data))->lock));
546                return 0;
547        } else
548                return i2c_smbus_write_byte_data(client, reg, value);
549}
550
551/* Called when we have found a new LM78. It should set limits, etc. */
552void lm78_init_client(struct i2c_client *client)
553{
554        int vid;
555
556        /* Reset all except Watchdog values and last conversion values
557           This sets fan-divs to 2, among others */
558        lm78_write_value(client, LM78_REG_CONFIG, 0x80);
559
560        vid = lm78_read_value(client, LM78_REG_VID_FANDIV) & 0x0f;
561        if (((struct lm78_data *) (client->data))->type == lm79)
562                vid |=
563                    (lm78_read_value(client, LM78_REG_CHIPID) & 0x01) << 4;
564        else
565                vid |= 0x10;
566        vid = VID_FROM_REG(vid);
567
568        lm78_write_value(client, LM78_REG_IN_MIN(0),
569                         IN_TO_REG(LM78_INIT_IN_MIN_0));
570        lm78_write_value(client, LM78_REG_IN_MAX(0),
571                         IN_TO_REG(LM78_INIT_IN_MAX_0));
572        lm78_write_value(client, LM78_REG_IN_MIN(1),
573                         IN_TO_REG(LM78_INIT_IN_MIN_1));
574        lm78_write_value(client, LM78_REG_IN_MAX(1),
575                         IN_TO_REG(LM78_INIT_IN_MAX_1));
576        lm78_write_value(client, LM78_REG_IN_MIN(2),
577                         IN_TO_REG(LM78_INIT_IN_MIN_2));
578        lm78_write_value(client, LM78_REG_IN_MAX(2),
579                         IN_TO_REG(LM78_INIT_IN_MAX_2));
580        lm78_write_value(client, LM78_REG_IN_MIN(3),
581                         IN_TO_REG(LM78_INIT_IN_MIN_3));
582        lm78_write_value(client, LM78_REG_IN_MAX(3),
583                         IN_TO_REG(LM78_INIT_IN_MAX_3));
584        lm78_write_value(client, LM78_REG_IN_MIN(4),
585                         IN_TO_REG(LM78_INIT_IN_MIN_4));
586        lm78_write_value(client, LM78_REG_IN_MAX(4),
587                         IN_TO_REG(LM78_INIT_IN_MAX_4));
588        lm78_write_value(client, LM78_REG_IN_MIN(5),
589                         IN_TO_REG(LM78_INIT_IN_MIN_5));
590        lm78_write_value(client, LM78_REG_IN_MAX(5),
591                         IN_TO_REG(LM78_INIT_IN_MAX_5));
592        lm78_write_value(client, LM78_REG_IN_MIN(6),
593                         IN_TO_REG(LM78_INIT_IN_MIN_6));
594        lm78_write_value(client, LM78_REG_IN_MAX(6),
595                         IN_TO_REG(LM78_INIT_IN_MAX_6));
596        lm78_write_value(client, LM78_REG_FAN_MIN(1),
597                         FAN_TO_REG(LM78_INIT_FAN_MIN_1, 2));
598        lm78_write_value(client, LM78_REG_FAN_MIN(2),
599                         FAN_TO_REG(LM78_INIT_FAN_MIN_2, 2));
600        lm78_write_value(client, LM78_REG_FAN_MIN(3),
601                         FAN_TO_REG(LM78_INIT_FAN_MIN_3, 2));
602        lm78_write_value(client, LM78_REG_TEMP_OVER,
603                         TEMP_TO_REG(LM78_INIT_TEMP_OVER));
604        lm78_write_value(client, LM78_REG_TEMP_HYST,
605                         TEMP_TO_REG(LM78_INIT_TEMP_HYST));
606
607        /* Start monitoring */
608        lm78_write_value(client, LM78_REG_CONFIG,
609                         (lm78_read_value(client, LM78_REG_CONFIG) & 0xf7)
610                         | 0x01);
611
612}
613
614void lm78_update_client(struct i2c_client *client)
615{
616        struct lm78_data *data = client->data;
617        int i;
618
619        down(&data->update_lock);
620
621        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
622            (jiffies < data->last_updated) || !data->valid) {
623
624#ifdef DEBUG
625                printk("Starting lm78 update\n");
626#endif
627                for (i = 0; i <= 6; i++) {
628                        data->in[i] =
629                            lm78_read_value(client, LM78_REG_IN(i));
630                        data->in_min[i] =
631                            lm78_read_value(client, LM78_REG_IN_MIN(i));
632                        data->in_max[i] =
633                            lm78_read_value(client, LM78_REG_IN_MAX(i));
634                }
635                for (i = 1; i <= 3; i++) {
636                        data->fan[i - 1] =
637                            lm78_read_value(client, LM78_REG_FAN(i));
638                        data->fan_min[i - 1] =
639                            lm78_read_value(client, LM78_REG_FAN_MIN(i));
640                }
641                data->temp = lm78_read_value(client, LM78_REG_TEMP);
642                data->temp_over =
643                    lm78_read_value(client, LM78_REG_TEMP_OVER);
644                data->temp_hyst =
645                    lm78_read_value(client, LM78_REG_TEMP_HYST);
646                i = lm78_read_value(client, LM78_REG_VID_FANDIV);
647                data->vid = i & 0x0f;
648                if (data->type == lm79)
649                        data->vid |=
650                            (lm78_read_value(client, LM78_REG_CHIPID) &
651                             0x01) << 4;
652                else
653                        data->vid |= 0x10;
654                data->fan_div[0] = (i >> 4) & 0x03;
655                data->fan_div[1] = i >> 6;
656                data->alarms = lm78_read_value(client, LM78_REG_ALARM1) +
657                    (lm78_read_value(client, LM78_REG_ALARM2) << 8);
658                data->last_updated = jiffies;
659                data->valid = 1;
660
661                data->fan_div[2] = 1;
662        }
663
664        up(&data->update_lock);
665}
666
667
668/* The next few functions are the call-back functions of the /proc/sys and
669   sysctl files. Which function is used is defined in the ctl_table in
670   the extra1 field.
671   Each function must return the magnitude (power of 10 to divide the date
672   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
673   put a maximum of *nrels elements in results reflecting the data of this
674   file, and set *nrels to the number it actually put in it, if operation==
675   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
676   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
677   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
678   large enough (by checking the incoming value of *nrels). This is not very
679   good practice, but as long as you put less than about 5 values in results,
680   you can assume it is large enough. */
681void lm78_in(struct i2c_client *client, int operation, int ctl_name,
682             int *nrels_mag, long *results)
683{
684        struct lm78_data *data = client->data;
685        int nr = ctl_name - LM78_SYSCTL_IN0;
686
687        if (operation == SENSORS_PROC_REAL_INFO)
688                *nrels_mag = 2;
689        else if (operation == SENSORS_PROC_REAL_READ) {
690                lm78_update_client(client);
691                results[0] = IN_FROM_REG(data->in_min[nr]);
692                results[1] = IN_FROM_REG(data->in_max[nr]);
693                results[2] = IN_FROM_REG(data->in[nr]);
694                *nrels_mag = 3;
695        } else if (operation == SENSORS_PROC_REAL_WRITE) {
696                if (*nrels_mag >= 1) {
697                        data->in_min[nr] = IN_TO_REG(results[0]);
698                        lm78_write_value(client, LM78_REG_IN_MIN(nr),
699                                         data->in_min[nr]);
700                }
701                if (*nrels_mag >= 2) {
702                        data->in_max[nr] = IN_TO_REG(results[1]);
703                        lm78_write_value(client, LM78_REG_IN_MAX(nr),
704                                         data->in_max[nr]);
705                }
706        }
707}
708
709void lm78_fan(struct i2c_client *client, int operation, int ctl_name,
710              int *nrels_mag, long *results)
711{
712        struct lm78_data *data = client->data;
713        int nr = ctl_name - LM78_SYSCTL_FAN1 + 1;
714
715        if (operation == SENSORS_PROC_REAL_INFO)
716                *nrels_mag = 0;
717        else if (operation == SENSORS_PROC_REAL_READ) {
718                lm78_update_client(client);
719                results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
720                                          DIV_FROM_REG(data->
721                                                       fan_div[nr - 1]));
722                results[1] =
723                    FAN_FROM_REG(data->fan[nr - 1],
724                                 DIV_FROM_REG(data->fan_div[nr - 1]));
725                *nrels_mag = 2;
726        } else if (operation == SENSORS_PROC_REAL_WRITE) {
727                if (*nrels_mag >= 1) {
728                        data->fan_min[nr - 1] = FAN_TO_REG(results[0],
729                                                           DIV_FROM_REG
730                                                           (data->
731                                                            fan_div[nr -
732                                                                    1]));
733                        lm78_write_value(client, LM78_REG_FAN_MIN(nr),
734                                         data->fan_min[nr - 1]);
735                }
736        }
737}
738
739
740void lm78_temp(struct i2c_client *client, int operation, int ctl_name,
741               int *nrels_mag, long *results)
742{
743        struct lm78_data *data = client->data;
744        if (operation == SENSORS_PROC_REAL_INFO)
745                *nrels_mag = 1;
746        else if (operation == SENSORS_PROC_REAL_READ) {
747                lm78_update_client(client);
748                results[0] = TEMP_FROM_REG(data->temp_over);
749                results[1] = TEMP_FROM_REG(data->temp_hyst);
750                results[2] = TEMP_FROM_REG(data->temp);
751                *nrels_mag = 3;
752        } else if (operation == SENSORS_PROC_REAL_WRITE) {
753                if (*nrels_mag >= 1) {
754                        data->temp_over = TEMP_TO_REG(results[0]);
755                        lm78_write_value(client, LM78_REG_TEMP_OVER,
756                                         data->temp_over);
757                }
758                if (*nrels_mag >= 2) {
759                        data->temp_hyst = TEMP_TO_REG(results[1]);
760                        lm78_write_value(client, LM78_REG_TEMP_HYST,
761                                         data->temp_hyst);
762                }
763        }
764}
765
766void lm78_vid(struct i2c_client *client, int operation, int ctl_name,
767              int *nrels_mag, long *results)
768{
769        struct lm78_data *data = client->data;
770        if (operation == SENSORS_PROC_REAL_INFO)
771                *nrels_mag = 2;
772        else if (operation == SENSORS_PROC_REAL_READ) {
773                lm78_update_client(client);
774                results[0] = VID_FROM_REG(data->vid);
775                *nrels_mag = 1;
776        }
777}
778
779void lm78_alarms(struct i2c_client *client, int operation, int ctl_name,
780                 int *nrels_mag, long *results)
781{
782        struct lm78_data *data = client->data;
783        if (operation == SENSORS_PROC_REAL_INFO)
784                *nrels_mag = 0;
785        else if (operation == SENSORS_PROC_REAL_READ) {
786                lm78_update_client(client);
787                results[0] = ALARMS_FROM_REG(data->alarms);
788                *nrels_mag = 1;
789        }
790}
791
792void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name,
793                  int *nrels_mag, long *results)
794{
795        struct lm78_data *data = client->data;
796        int old;
797
798        if (operation == SENSORS_PROC_REAL_INFO)
799                *nrels_mag = 0;
800        else if (operation == SENSORS_PROC_REAL_READ) {
801                lm78_update_client(client);
802                results[0] = DIV_FROM_REG(data->fan_div[0]);
803                results[1] = DIV_FROM_REG(data->fan_div[1]);
804                results[2] = 2;
805                *nrels_mag = 3;
806        } else if (operation == SENSORS_PROC_REAL_WRITE) {
807                old = lm78_read_value(client, LM78_REG_VID_FANDIV);
808                if (*nrels_mag >= 2) {
809                        data->fan_div[1] = DIV_TO_REG(results[1]);
810                        old = (old & 0x3f) | (data->fan_div[1] << 6);
811                }
812                if (*nrels_mag >= 1) {
813                        data->fan_div[0] = DIV_TO_REG(results[0]);
814                        old = (old & 0xcf) | (data->fan_div[0] << 4);
815                        lm78_write_value(client, LM78_REG_VID_FANDIV, old);
816                }
817        }
818}
819
820int __init sensors_lm78_init(void)
821{
822        int res;
823
824        printk("lm78.o version %s (%s)\n", LM_VERSION, LM_DATE);
825        lm78_initialized = 0;
826
827        if ((res = i2c_add_driver(&lm78_driver))) {
828                printk
829                    ("lm78.o: Driver registration failed, module not inserted.\n");
830                lm78_cleanup();
831                return res;
832        }
833        lm78_initialized++;
834        return 0;
835}
836
837int __init lm78_cleanup(void)
838{
839        int res;
840
841        if (lm78_initialized >= 1) {
842                if ((res = i2c_del_driver(&lm78_driver))) {
843                        printk
844                            ("lm78.o: Driver deregistration failed, module not removed.\n");
845                        return res;
846                }
847                lm78_initialized--;
848        }
849        return 0;
850}
851
852EXPORT_NO_SYMBOLS;
853
854#ifdef MODULE
855
856MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
857MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
858
859int init_module(void)
860{
861        return sensors_lm78_init();
862}
863
864int cleanup_module(void)
865{
866        return lm78_cleanup();
867}
868
869#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.