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

Revision 29, 30.3 KB (checked in by frodo, 16 years ago)

LM75 driver finished

Well, it should work. But until we have implemented the remaining parts of
piix4.o, we won't be able to test it. Anybody?

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