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

Revision 53, 30.6 KB (checked in by frodo, 14 years ago)

Some small rounding and initializing bugs solved.

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