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

Revision 645, 27.7 KB (checked in by frodo, 13 years ago)

Just to make sure, added `#include <linux/version.h>' at several

other places.

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