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

Revision 75, 31.1 KB (checked in by frodo, 14 years ago)

Another very, very small bug removed.

  • 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(-J) and LM79 sensor 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 if (err == 0x02) {
350      printk("lm78.o: Warning: Winbond W83781D detected (treated as a LM79)\n");
351      type = lm79;
352      type_name = "lm79";
353      client_name = "LM79 chip";
354    } else {
355#ifdef DEBUG
356      printk("lm78.o: warning: probed non-lm78 chip?!? (%x)\n",err);
357#endif
358      continue;
359    }
360
361    request_region(address, LM78_EXTENT, type_name);
362
363    /* Allocate space for a new client structure */
364    if (! (new_client = kmalloc(sizeof(struct isa_client) + 
365                                sizeof(struct lm78_data),
366                               GFP_KERNEL)))
367    {
368      err=-ENOMEM;
369      goto ERROR1;
370    } 
371
372    /* Fill the new client structure with data */
373    new_client->data = (struct lm78_data *) (new_client + 1);
374    new_client->addr = 0;
375    strcpy(new_client->name,client_name);
376    ((struct lm78_data *) (new_client->data))->type = type;
377    new_client->isa_addr = address;
378    if ((err = lm78_new_client((struct i2c_adapter *) adapter,
379                               (struct i2c_client *) new_client)))
380      goto ERROR2;
381
382    /* Tell i2c-core a new client has arrived */
383    if ((err = isa_attach_client(new_client)))
384      goto ERROR3;
385   
386    /* Register a new directory entry with module sensors */
387    if ((err = sensors_register_entry((struct i2c_client *) new_client,
388                                      type_name,
389                                      lm78_dir_table_template)) < 0)
390      goto ERROR4;
391    ((struct lm78_data *) (new_client->data)) -> sysctl_id = err;
392
393    /* Initialize the LM78 chip */
394    lm78_init_client((struct i2c_client *) new_client);
395    continue;
396
397/* OK, this is not exactly good programming practice, usually. But it is
398   very code-efficient in this case. */
399
400ERROR4:
401    isa_detach_client(new_client);
402ERROR3:
403    lm78_remove_client((struct i2c_client *) new_client);
404ERROR2:
405    kfree(new_client);
406ERROR1:
407    release_region(address, LM78_EXTENT);
408  }
409  return err;
410
411}
412
413/* Deregister and remove a LM78 client */
414int lm78_detach_isa(struct isa_client *client)
415{
416  int err,i;
417  for (i = 0; i < MAX_LM78_NR; i++)
418    if ((client == (struct isa_client *) (lm78_list[i])))
419      break;
420  if (i == MAX_LM78_NR) {
421    printk("lm78.o: Client to detach not found.\n");
422    return -ENOENT;
423  }
424
425  sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
426
427  if ((err = isa_detach_client(client))) {
428    printk("lm78.o: Client deregistration failed, client not detached.\n");
429    return err;
430  }
431  lm78_remove_client((struct i2c_client *) client);
432  release_region(client->isa_addr,LM78_EXTENT);
433  kfree(client);
434  return 0;
435}
436
437int lm78_detect_smbus(struct i2c_adapter *adapter)
438{
439  int address,err;
440  struct i2c_client *new_client;
441  enum lm78_type type;
442  const char *type_name,*client_name;
443
444  /* OK, this is no detection. I know. It will do for now, though.  */
445  err = 0;
446  for (address = 0x20; (! err) && (address <= 0x2f); address ++) {
447
448    /* Later on, we will keep a list of registered addresses for each
449       adapter, and check whether they are used here */
450
451    if (smbus_read_byte_data(adapter,address,LM78_REG_CONFIG) < 0) 
452      continue;
453
454    /* Real detection code goes here */
455
456    /* Determine exact type */
457    err = smbus_read_byte_data(adapter,address,LM78_REG_CHIPID) & 0xfe;
458    if (err == 0x00) {
459      type = lm78;
460      type_name = "lm78";
461      client_name = "LM78 chip";
462    } else if (err == 0x40) {
463      type = lm78j;
464      type_name = "lm78-j";
465      client_name = "LM78-J chip";
466    } else if (err == 0xc0) {
467      type = lm79;
468      type_name = "lm79";
469      client_name = "LM79 chip";
470    } else if (err == 0x02) {
471      printk("lm78.o: Warning: Winbond W83781D detected (treated as a LM79)\n");
472      type = lm79;
473      type_name = "lm79";
474      client_name = "LM79 chip";
475    } else {
476#ifdef DEBUG
477      printk("lm78.o: warning: probed non-lm78 chip?!? (%x)\n",err);
478#endif
479      continue;
480    }
481
482
483    /* Allocate space for a new client structure. To counter memory
484       ragmentation somewhat, we only do one kmalloc. */
485    if (! (new_client = kmalloc(sizeof(struct i2c_client) + 
486                                sizeof(struct lm78_data),
487                               GFP_KERNEL))) {
488      err = -ENOMEM;
489      continue;
490    }
491
492    /* Fill the new client structure with data */
493    new_client->data = (struct lm78_data *) (new_client + 1);
494    new_client->addr = address;
495    strcpy(new_client->name,client_name);
496    ((struct lm78_data *) (new_client->data))->type = type;
497    if ((err = lm78_new_client(adapter,new_client)))
498      goto ERROR2;
499
500    /* Tell i2c-core a new client has arrived */
501    if ((err = i2c_attach_client(new_client))) 
502      goto ERROR3;
503
504    /* Register a new directory entry with module sensors */
505    if ((err = sensors_register_entry(new_client,type_name,
506                                      lm78_dir_table_template)) < 0)
507      goto ERROR4;
508    ((struct lm78_data *) (new_client->data))->sysctl_id = err;
509
510    /* Initialize the LM78 chip */
511    lm78_init_client(new_client);
512    continue;
513
514/* OK, this is not exactly good programming practice, usually. But it is
515   very code-efficient in this case. */
516ERROR4:
517    i2c_detach_client(new_client);
518ERROR3:
519    lm78_remove_client((struct i2c_client *) new_client);
520ERROR2:
521    kfree(new_client);
522  }
523  return err;
524}
525
526int lm78_detach_smbus(struct i2c_client *client)
527{
528  int err,i;
529  for (i = 0; i < MAX_LM78_NR; i++)
530    if (client == lm78_list[i])
531      break;
532  if ((i == MAX_LM78_NR)) {
533    printk("lm78.o: Client to detach not found.\n");
534    return -ENOENT;
535  }
536
537  sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
538
539  if ((err = i2c_detach_client(client))) {
540    printk("lm78.o: Client deregistration failed, client not detached.\n");
541    return err;
542  }
543  lm78_remove_client(client);
544  kfree(client);
545  return 0;
546}
547
548
549/* Find a free slot, and initialize most of the fields */
550int lm78_new_client(struct i2c_adapter *adapter,
551                    struct i2c_client *new_client)
552{
553  int i;
554  struct lm78_data *data;
555
556  /* First, seek out an empty slot */
557  for(i = 0; i < MAX_LM78_NR; i++)
558    if (! lm78_list[i])
559      break;
560  if (i == MAX_LM78_NR) {
561    printk("lm78.o: No empty slots left, recompile and heighten "
562           "MAX_LM78_NR!\n");
563    return -ENOMEM;
564  }
565 
566  lm78_list[i] = new_client;
567  new_client->id = i;
568  new_client->adapter = adapter;
569  new_client->driver = &lm78_driver;
570  data = new_client->data;
571  data->valid = 0;
572  data->lock = MUTEX;
573  data->update_lock = MUTEX;
574  return 0;
575}
576
577/* Inverse of lm78_new_client */
578void lm78_remove_client(struct i2c_client *client)
579{
580  int i;
581  for (i = 0; i < MAX_LM78_NR; i++)
582    if (client == lm78_list[i]) 
583      lm78_list[i] = NULL;
584}
585
586/* No commands defined yet */
587int lm78_command(struct i2c_client *client, unsigned int cmd, void *arg)
588{
589  return 0;
590}
591
592/* Nothing here yet */
593void lm78_inc_use (struct i2c_client *client)
594{
595#ifdef MODULE
596  MOD_INC_USE_COUNT;
597#endif
598}
599
600/* Nothing here yet */
601void lm78_dec_use (struct i2c_client *client)
602{
603#ifdef MODULE
604  MOD_DEC_USE_COUNT;
605#endif
606}
607 
608
609/* The SMBus locks itself, but ISA access must be locked explicitely!
610   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
611   would slow down the LM78 access and should not be necessary.
612   There are some ugly typecasts here, but the good new is - they should
613   nowhere else be necessary! */
614int lm78_read_value(struct i2c_client *client, u8 reg)
615{
616  int res;
617  if (i2c_is_isa_client(client)) {
618    down((struct semaphore *) (client->data));
619    outb_p(reg,(((struct isa_client *) client)->isa_addr) + 
620               LM78_ADDR_REG_OFFSET);
621    res = inb_p((((struct isa_client *) client)->isa_addr) + 
622                LM78_DATA_REG_OFFSET);
623    up((struct semaphore *) (client->data));
624    return res;
625  } else
626    return smbus_read_byte_data(client->adapter,client->addr, reg);
627}
628
629/* The SMBus locks itself, but ISA access muse be locked explicitely!
630   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
631   would slow down the LM78 access and should not be necessary.
632   There are some ugly typecasts here, but the good new is - they should
633   nowhere else be necessary! */
634int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
635{
636  if (i2c_is_isa_client(client)) {
637    down((struct semaphore *) (client->data));
638    outb_p(reg,((struct isa_client *) client)->isa_addr + LM78_ADDR_REG_OFFSET);
639    outb_p(value,((struct isa_client *) client)->isa_addr + LM78_DATA_REG_OFFSET);
640    up((struct semaphore *) (client->data));
641    return 0;
642  } else
643    return smbus_write_byte_data(client->adapter, client->addr, reg,value);
644}
645
646/* Called when we have found a new LM78. It should set limits, etc. */
647void lm78_init_client(struct i2c_client *client)
648{
649  int vid;
650
651  /* Reset all except Watchdog values and last conversion values
652     This sets fan-divs to 2, among others */
653  lm78_write_value(client,LM78_REG_CONFIG,0x80);
654
655  vid = lm78_read_value(client,LM78_REG_VID_FANDIV) & 0x0f;
656  if (((struct lm78_data *) (client->data))->type == lm79)
657    vid |= (lm78_read_value(client,LM78_REG_CHIPID) & 0x01) >> 4;
658  else
659    vid |= 0x10;
660  vid = VID_FROM_REG(vid);
661
662  lm78_write_value(client,LM78_REG_IN_MIN(0),IN_TO_REG(LM78_INIT_IN_MIN_0,0));
663  lm78_write_value(client,LM78_REG_IN_MAX(0),IN_TO_REG(LM78_INIT_IN_MAX_0,0));
664  lm78_write_value(client,LM78_REG_IN_MIN(1),IN_TO_REG(LM78_INIT_IN_MIN_1,1));
665  lm78_write_value(client,LM78_REG_IN_MAX(1),IN_TO_REG(LM78_INIT_IN_MAX_1,1));
666  lm78_write_value(client,LM78_REG_IN_MIN(2),IN_TO_REG(LM78_INIT_IN_MIN_2,2));
667  lm78_write_value(client,LM78_REG_IN_MAX(2),IN_TO_REG(LM78_INIT_IN_MAX_2,2));
668  lm78_write_value(client,LM78_REG_IN_MIN(3),IN_TO_REG(LM78_INIT_IN_MIN_3,3));
669  lm78_write_value(client,LM78_REG_IN_MAX(3),IN_TO_REG(LM78_INIT_IN_MAX_3,3));
670  lm78_write_value(client,LM78_REG_IN_MIN(4),IN_TO_REG(LM78_INIT_IN_MIN_4,4));
671  lm78_write_value(client,LM78_REG_IN_MAX(4),IN_TO_REG(LM78_INIT_IN_MAX_4,4));
672  lm78_write_value(client,LM78_REG_IN_MIN(5),IN_TO_REG(LM78_INIT_IN_MIN_5,5));
673  lm78_write_value(client,LM78_REG_IN_MAX(5),IN_TO_REG(LM78_INIT_IN_MAX_5,5));
674  lm78_write_value(client,LM78_REG_IN_MIN(6),IN_TO_REG(LM78_INIT_IN_MIN_6,6));
675  lm78_write_value(client,LM78_REG_IN_MAX(6),IN_TO_REG(LM78_INIT_IN_MAX_6,6));
676  lm78_write_value(client,LM78_REG_FAN_MIN(1),FAN_TO_REG(LM78_INIT_FAN_MIN_1));
677  lm78_write_value(client,LM78_REG_FAN_MIN(2),FAN_TO_REG(LM78_INIT_FAN_MIN_2));
678  lm78_write_value(client,LM78_REG_FAN_MIN(3),FAN_TO_REG(LM78_INIT_FAN_MIN_3));
679  lm78_write_value(client,LM78_REG_TEMP_OVER,TEMP_TO_REG(LM78_INIT_TEMP_OVER));
680  lm78_write_value(client,LM78_REG_TEMP_HYST,TEMP_TO_REG(LM78_INIT_TEMP_HYST));
681
682  /* Start monitoring */
683  lm78_write_value(client,LM78_REG_CONFIG,
684                   (lm78_read_value(client,LM78_REG_CONFIG) & 0xf7) | 0x01);
685 
686}
687
688void lm78_update_client(struct i2c_client *client)
689{
690  struct lm78_data *data = client->data;
691  int i;
692
693  down(&data->update_lock);
694
695  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
696      (jiffies < data->last_updated) || ! data->valid) {
697
698#ifdef DEBUG
699    printk("Starting lm78 update\n");
700#endif
701    for (i = 0; i <= 6; i++) {
702      data->in[i]     = lm78_read_value(client,LM78_REG_IN(i));
703      data->in_min[i] = lm78_read_value(client,LM78_REG_IN_MIN(i));
704      data->in_max[i] = lm78_read_value(client,LM78_REG_IN_MAX(i));
705    }
706    for (i = 1; i <= 3; i++) {
707      data->fan[i-1] = lm78_read_value(client,LM78_REG_FAN(i));
708      data->fan_min[i-1] = lm78_read_value(client,LM78_REG_FAN_MIN(i));
709    }
710    data->temp = lm78_read_value(client,LM78_REG_TEMP);
711    data->temp_over = lm78_read_value(client,LM78_REG_TEMP_OVER);
712    data->temp_hyst = lm78_read_value(client,LM78_REG_TEMP_HYST);
713    i = lm78_read_value(client,LM78_REG_VID_FANDIV);
714    data->vid = i & 0x0f;
715    if (data->type == lm79)
716      data->vid |= (lm78_read_value(client,LM78_REG_CHIPID) & 0x01) >> 4;
717    else
718      data->vid |= 0x10;
719    data->fan_div[0] = (i >> 4) & 0x03;
720    data->fan_div[1] = i >> 6;
721    data->alarms = lm78_read_value(client,LM78_REG_ALARM1) +
722                   (lm78_read_value(client,LM78_REG_ALARM2) >> 8);
723    data->last_updated = jiffies;
724    data->valid = 1;
725  }
726
727  up(&data->update_lock);
728}
729
730
731/* The next few functions are the call-back functions of the /proc/sys and
732   sysctl files. Which function is used is defined in the ctl_table in
733   the extra1 field.
734   Each function must return the magnitude (power of 10 to divide the date
735   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
736   put a maximum of *nrels elements in results reflecting the data of this
737   file, and set *nrels to the number it actually put in it, if operation==
738   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
739   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
740   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
741   large enough (by checking the incoming value of *nrels). This is not very
742   good practice, but as long as you put less than about 5 values in results,
743   you can assume it is large enough. */
744void lm78_in(struct i2c_client *client, int operation, int ctl_name, 
745             int *nrels_mag, long *results)
746{
747  struct lm78_data *data = client->data;
748  int nr = ctl_name - LM78_SYSCTL_IN0;
749
750  if (operation == SENSORS_PROC_REAL_INFO)
751    *nrels_mag = 2;
752  else if (operation == SENSORS_PROC_REAL_READ) {
753    lm78_update_client(client);
754    results[0] = IN_FROM_REG(data->in_min[nr],nr);
755    results[1] = IN_FROM_REG(data->in_max[nr],nr);
756    results[2] = IN_FROM_REG(data->in[nr],nr);
757    *nrels_mag = 3;
758  } else if (operation == SENSORS_PROC_REAL_WRITE) {
759      if (*nrels_mag >= 1) {
760        data->in_min[nr] = IN_TO_REG(results[0],nr);
761        lm78_write_value(client,LM78_REG_IN_MIN(nr),data->in_min[nr]);
762      }
763      if (*nrels_mag >= 2) {
764        data->in_max[nr] = IN_TO_REG(results[1],nr);
765        lm78_write_value(client,LM78_REG_IN_MAX(nr),data->in_max[nr]);
766      }
767  }
768}
769
770void lm78_fan(struct i2c_client *client, int operation, int ctl_name,
771              int *nrels_mag, long *results)
772{
773  struct lm78_data *data = client->data;
774  int nr = ctl_name - LM78_SYSCTL_FAN1 + 1;
775
776  if (operation == SENSORS_PROC_REAL_INFO)
777    *nrels_mag = 0;
778  else if (operation == SENSORS_PROC_REAL_READ) {
779    lm78_update_client(client);
780    results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
781    results[1] = FAN_FROM_REG(data->fan[nr-1]);
782    *nrels_mag = 2;
783  } else if (operation == SENSORS_PROC_REAL_WRITE) {
784    if (*nrels_mag >= 1) {
785      data->fan_min[nr-1] = FAN_TO_REG(results[0]);
786      lm78_write_value(client,LM78_REG_FAN_MIN(nr),data->fan_min[nr-1]);
787    }
788  }
789}
790
791
792void lm78_temp(struct i2c_client *client, int operation, int ctl_name,
793               int *nrels_mag, long *results)
794{
795  struct lm78_data *data = client->data;
796  if (operation == SENSORS_PROC_REAL_INFO)
797    *nrels_mag = 1;
798  else if (operation == SENSORS_PROC_REAL_READ) {
799    lm78_update_client(client);
800    results[0] = TEMP_FROM_REG(data->temp_over);
801    results[1] = TEMP_FROM_REG(data->temp_hyst);
802    results[2] = TEMP_FROM_REG(data->temp);
803    *nrels_mag = 3;
804  } else if (operation == SENSORS_PROC_REAL_WRITE) {
805    if (*nrels_mag >= 1) {
806      data->temp_over = TEMP_TO_REG(results[0]);
807      lm78_write_value(client,LM78_REG_TEMP_OVER,data->temp_over);
808    }
809    if (*nrels_mag >= 2) {
810      data->temp_hyst = TEMP_TO_REG(results[1]);
811      lm78_write_value(client,LM78_REG_TEMP_HYST,data->temp_hyst);
812    }
813  }
814}
815
816void lm78_vid(struct i2c_client *client, int operation, int ctl_name,
817              int *nrels_mag, long *results)
818{
819  struct lm78_data *data = client->data;
820  if (operation == SENSORS_PROC_REAL_INFO)
821    *nrels_mag = 2;
822  else if (operation == SENSORS_PROC_REAL_READ) {
823    lm78_update_client(client);
824    results[0] = VID_FROM_REG(data->vid);
825    *nrels_mag = 1;
826  }
827}
828
829void lm78_alarms(struct i2c_client *client, int operation, int ctl_name,
830                 int *nrels_mag, long *results)
831{
832  struct lm78_data *data = client->data;
833  if (operation == SENSORS_PROC_REAL_INFO)
834    *nrels_mag = 0;
835  else if (operation == SENSORS_PROC_REAL_READ) {
836    lm78_update_client(client);
837    results[0] = ALARMS_FROM_REG(data->alarms);
838    *nrels_mag = 1;
839  }
840}
841
842void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name,
843                  int *nrels_mag, long *results)
844{
845  struct lm78_data *data = client->data;
846  int old;
847
848  if (operation == SENSORS_PROC_REAL_INFO)
849    *nrels_mag = 0;
850  else if (operation == SENSORS_PROC_REAL_READ) {
851    lm78_update_client(client);
852    results[0] = DIV_FROM_REG(data->fan_div[0]);
853    results[1] = DIV_FROM_REG(data->fan_div[1]);
854    results[2] = 2;
855    *nrels_mag = 3;
856  } else if (operation == SENSORS_PROC_REAL_WRITE) {
857    old = lm78_read_value(client,LM78_REG_VID_FANDIV);
858    if (*nrels_mag >= 2) {
859      data->fan_div[1] = DIV_TO_REG(results[1]);
860      old = (old & 0x3f) | (data->fan_div[1] << 6);
861    }
862    if (*nrels_mag >= 1) {
863      data->fan_div[0] = DIV_TO_REG(results[0]);
864      old = (old & 0xcf) | (data->fan_div[0] << 4);
865      lm78_write_value(client,LM78_REG_VID_FANDIV,old);
866    }
867  }
868}
869
870int lm78_init(void)
871{
872  int res;
873
874  printk("lm78.o version %s (%s)\n",LM_VERSION,LM_DATE);
875  lm78_initialized = 0;
876
877  if ((res =i2c_add_driver(&lm78_driver))) {
878    printk("lm78.o: Driver registration failed, module not inserted.\n");
879    lm78_cleanup();
880    return res;
881  }
882  lm78_initialized ++;
883  return 0;
884}
885
886int lm78_cleanup(void)
887{
888  int res;
889
890  if (lm78_initialized >= 1) {
891    if ((res = i2c_del_driver(&lm78_driver))) {
892      printk("lm78.o: Driver deregistration failed, module not removed.\n");
893      return res;
894    }
895    lm78_initialized --;
896  }
897  return 0;
898}
899
900
901#ifdef MODULE
902
903MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
904MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
905
906int init_module(void)
907{
908  return lm78_init();
909}
910
911int cleanup_module(void)
912{
913  return lm78_cleanup();
914}
915
916#endif /* MODULE */
917
Note: See TracBrowser for help on using the browser.