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

Revision 28, 30.2 KB (checked in by frodo, 14 years ago)

Simplification of /proc files functions in chip drivers

I moved a large part of the proc and sysctl call-back functions into
sensors.c. The result saved about 100 lines in lm78.c; it now uses only
2 pages according to lsmod, instead of 3! Also, other modules can use
the same functions, saving coding efforts and keeping them small.

I also fixed a fan_div display error.

Expect more code to be moved to sensors.c: I am writing lm75.c, and
most things which are in both modules (and so probably general purpose)
will be moved to sensors.c.

  • 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,1) == 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 */
469    if (! (new_client = kmalloc(sizeof(struct i2c_client) + 
470                                sizeof(struct lm78_data),
471                               GFP_KERNEL))) {
472      err = -ENOMEM;
473      continue;
474    }
475
476    /* Fill the new client structure with data */
477    new_client->data = (struct lm78_data *) (new_client + 1);
478    new_client->addr = address;
479    strcpy(new_client->name,client_name);
480    ((struct lm78_data *) (new_client->data))->type = type;
481    if ((err = lm78_new_client(adapter,new_client)))
482      goto ERROR2;
483
484    /* Tell i2c-core a new client has arrived */
485    if ((err = i2c_attach_client(new_client))) 
486      goto ERROR3;
487
488    /* Register a new directory entry with module sensors */
489    if ((err = sensors_register_entry(new_client,type_name,
490                                      lm78_dir_table_template)) < 0)
491      goto ERROR4;
492    ((struct lm78_data *) (new_client->data))->sysctl_id = err;
493
494    /* Initialize the LM78 chip */
495    lm78_init_client(new_client);
496    continue;
497
498/* OK, this is not exactly good programming practice, usually. But it is
499   very code-efficient in this case. */
500ERROR4:
501    i2c_detach_client(new_client);
502ERROR3:
503    lm78_remove_client((struct i2c_client *) new_client);
504ERROR2:
505    kfree(new_client);
506  }
507  return err;
508}
509
510int lm78_detach_smbus(struct i2c_client *client)
511{
512  int err,i;
513  for (i = 0; i < MAX_LM78_NR; i++)
514    if (client == lm78_list[i])
515      break;
516  if ((i == MAX_LM78_NR)) {
517    printk("lm78.o: Client to detach not found.\n");
518    return -ENOENT;
519  }
520
521  sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
522
523  if ((err = i2c_detach_client(client))) {
524    printk("lm78.o: Client deregistration failed, client not detached.\n");
525    return err;
526  }
527  lm78_remove_client(client);
528  kfree(client);
529  return 0;
530}
531
532
533/* Find a free slot, and initialize most of the fields */
534int lm78_new_client(struct i2c_adapter *adapter,
535                    struct i2c_client *new_client)
536{
537  int i;
538  struct lm78_data *data;
539
540  /* First, seek out an empty slot */
541  for(i = 0; i < MAX_LM78_NR; i++)
542    if (! lm78_list[i])
543      break;
544  if (i == MAX_LM78_NR) {
545    printk("lm78.o: No empty slots left, recompile and heighten "
546           "MAX_LM78_NR!\n");
547    return -ENOMEM;
548  }
549 
550  lm78_list[i] = new_client;
551  new_client->id = i;
552  new_client->adapter = adapter;
553  new_client->driver = &lm78_driver;
554  data = new_client->data;
555  data->valid = 0;
556  data->lock = MUTEX;
557  data->update_lock = MUTEX;
558  return 0;
559}
560
561/* Inverse of lm78_new_client */
562void lm78_remove_client(struct i2c_client *client)
563{
564  int i;
565  for (i = 0; i < MAX_LM78_NR; i++)
566    if (client == lm78_list[i]) 
567      lm78_list[i] = NULL;
568}
569
570/* No commands defined yet */
571int lm78_command(struct i2c_client *client, unsigned int cmd, void *arg)
572{
573  return 0;
574}
575
576/* Nothing here yet */
577void lm78_inc_use (struct i2c_client *client)
578{
579}
580
581/* Nothing here yet */
582void lm78_dec_use (struct i2c_client *client)
583{
584}
585 
586
587/* The SMBus locks itself, but ISA access must be locked explicitely!
588   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
589   would slow down the LM78 access and should not be necessary.
590   There are some ugly typecasts here, but the good new is - they should
591   nowhere else be necessary! */
592int lm78_read_value(struct i2c_client *client, u8 reg)
593{
594  int res;
595  if (i2c_is_isa_client(client)) {
596    down((struct semaphore *) (client->data));
597    outb_p(reg,(((struct isa_client *) client)->isa_addr) + 
598               LM78_ADDR_REG_OFFSET);
599    res = inb_p((((struct isa_client *) client)->isa_addr) + 
600                LM78_DATA_REG_OFFSET);
601    up((struct semaphore *) (client->data));
602    return res;
603  } else
604    return smbus_read_byte_data(client->adapter,client->addr, reg);
605}
606
607/* The SMBus locks itself, but ISA access muse be locked explicitely!
608   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
609   would slow down the LM78 access and should not be necessary.
610   There are some ugly typecasts here, but the good new is - they should
611   nowhere else be necessary! */
612int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
613{
614  if (i2c_is_isa_client(client)) {
615    down((struct semaphore *) (client->data));
616    outb_p(reg,((struct isa_client *) client)->isa_addr + LM78_ADDR_REG_OFFSET);
617    outb_p(value,((struct isa_client *) client)->isa_addr + LM78_DATA_REG_OFFSET);
618    up((struct semaphore *) (client->data));
619    return 0;
620  } else
621    return smbus_write_byte_data(client->adapter, client->addr, reg,value);
622}
623
624/* Called when we have found a new LM78. It should set limits, etc. */
625void lm78_init_client(struct i2c_client *client)
626{
627  int vid;
628
629  /* Reset all except Watchdog values and last conversion values
630     This sets fan-divs to 2, among others */
631  lm78_write_value(client,LM78_REG_CONFIG,0x80);
632
633  vid = lm78_read_value(client,LM78_REG_VID_FANDIV) & 0x0f;
634  if (((struct lm78_data *) (client->data))->type == lm79)
635    vid |= (lm78_read_value(client,LM78_REG_CHIPID) & 0x01) >> 4;
636  else
637    vid |= 0x10;
638  vid = VID_FROM_REG(vid);
639
640  lm78_write_value(client,LM78_REG_IN_MIN(0),IN_TO_REG(LM78_INIT_IN_MIN_0,0));
641  lm78_write_value(client,LM78_REG_IN_MAX(0),IN_TO_REG(LM78_INIT_IN_MAX_0,0));
642  lm78_write_value(client,LM78_REG_IN_MIN(1),IN_TO_REG(LM78_INIT_IN_MIN_1,1));
643  lm78_write_value(client,LM78_REG_IN_MAX(1),IN_TO_REG(LM78_INIT_IN_MAX_1,1));
644  lm78_write_value(client,LM78_REG_IN_MIN(2),IN_TO_REG(LM78_INIT_IN_MIN_2,2));
645  lm78_write_value(client,LM78_REG_IN_MAX(2),IN_TO_REG(LM78_INIT_IN_MAX_2,2));
646  lm78_write_value(client,LM78_REG_IN_MIN(3),IN_TO_REG(LM78_INIT_IN_MIN_3,3));
647  lm78_write_value(client,LM78_REG_IN_MAX(3),IN_TO_REG(LM78_INIT_IN_MAX_3,3));
648  lm78_write_value(client,LM78_REG_IN_MIN(4),IN_TO_REG(LM78_INIT_IN_MIN_4,4));
649  lm78_write_value(client,LM78_REG_IN_MAX(4),IN_TO_REG(LM78_INIT_IN_MAX_4,4));
650  lm78_write_value(client,LM78_REG_IN_MIN(5),IN_TO_REG(LM78_INIT_IN_MIN_5,5));
651  lm78_write_value(client,LM78_REG_IN_MAX(5),IN_TO_REG(LM78_INIT_IN_MAX_5,5));
652  lm78_write_value(client,LM78_REG_IN_MIN(6),IN_TO_REG(LM78_INIT_IN_MIN_6,6));
653  lm78_write_value(client,LM78_REG_IN_MAX(6),IN_TO_REG(LM78_INIT_IN_MAX_6,6));
654  lm78_write_value(client,LM78_REG_FAN_MIN(1),FAN_TO_REG(LM78_INIT_FAN_MIN_1));
655  lm78_write_value(client,LM78_REG_FAN_MIN(2),FAN_TO_REG(LM78_INIT_FAN_MIN_2));
656  lm78_write_value(client,LM78_REG_FAN_MIN(3),FAN_TO_REG(LM78_INIT_FAN_MIN_3));
657  lm78_write_value(client,LM78_REG_TEMP_OVER,TEMP_TO_REG(LM78_INIT_TEMP_OVER));
658  lm78_write_value(client,LM78_REG_TEMP_HYST,TEMP_TO_REG(LM78_INIT_TEMP_HYST));
659
660  /* Start monitoring */
661  lm78_write_value(client,LM78_REG_CONFIG,
662                   (lm78_read_value(client,LM78_REG_CONFIG) & 0xf7) | 0x01);
663 
664}
665
666void lm78_update_client(struct i2c_client *client)
667{
668  struct lm78_data *data = client->data;
669  int i;
670
671  down(&data->update_lock);
672
673  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
674      (jiffies < data->last_updated) || ! data->valid) {
675
676#ifdef DEBUG
677    printk("Starting lm78 update\n");
678#endif
679    for (i = 0; i <= 6; i++) {
680      data->in[i]     = lm78_read_value(client,LM78_REG_IN(i));
681      data->in_min[i] = lm78_read_value(client,LM78_REG_IN_MIN(i));
682      data->in_max[i] = lm78_read_value(client,LM78_REG_IN_MAX(i));
683    }
684    for (i = 1; i <= 3; i++) {
685      data->fan[i-1] = lm78_read_value(client,LM78_REG_FAN(i));
686      data->fan_min[i-1] = lm78_read_value(client,LM78_REG_FAN_MIN(i));
687    }
688    data->temp = lm78_read_value(client,LM78_REG_TEMP);
689    data->temp_over = lm78_read_value(client,LM78_REG_TEMP_OVER);
690    data->temp_hyst = lm78_read_value(client,LM78_REG_TEMP_HYST);
691    i = lm78_read_value(client,LM78_REG_VID_FANDIV);
692    data->vid = i & 0x0f;
693    if (data->type == lm79)
694      data->vid |= (lm78_read_value(client,LM78_REG_CHIPID) & 0x01) >> 4;
695    else
696      data->vid |= 0x10;
697    data->fan_div[0] = (i >> 4) & 0x03;
698    data->fan_div[1] = i >> 6;
699    data->alarms = lm78_read_value(client,LM78_REG_ALARM1) +
700                   (lm78_read_value(client,LM78_REG_ALARM2) >> 8);
701    data->last_updated = jiffies;
702    data->valid = 1;
703  }
704
705  up(&data->update_lock);
706}
707
708
709/* The next few functions are the call-back functions of the /proc/sys and
710   sysctl files. Which function is used is defined in the ctl_table in
711   the extra1 field.
712   Each function must return the magnitude (power of 10 to divide the date
713   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
714   put a maximum of *nrels elements in results reflecting the data of this
715   file, and set *nrels to the number it actually put in it, if operation==
716   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
717   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
718   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
719   large enough (by checking the incoming value of *nrels). This is not very
720   good practice, but as long as you put less than about 5 values in results,
721   you can assume it is large enough. */
722void lm78_in(struct i2c_client *client, int operation, int ctl_name, 
723             int *nrels_mag, long *results)
724{
725  struct lm78_data *data = client->data;
726  int nr = ctl_name - LM78_SYSCTL_IN0;
727
728  if (operation == SENSORS_PROC_REAL_INFO)
729    *nrels_mag = 2;
730  else if (operation == SENSORS_PROC_REAL_READ) {
731    lm78_update_client(client);
732    results[0] = IN_FROM_REG(data->in_min[nr],nr);
733    results[1] = IN_FROM_REG(data->in_max[nr],nr);
734    results[2] = IN_FROM_REG(data->in[nr],nr);
735    *nrels_mag = 3;
736  } else if (operation == SENSORS_PROC_REAL_WRITE) {
737      if (*nrels_mag >= 1) {
738        data->in_min[nr] = IN_TO_REG(results[0],nr);
739        lm78_write_value(client,LM78_REG_IN_MIN(nr),data->in_min[nr]);
740      }
741      if (*nrels_mag >= 2) {
742      data->in_max[nr] = IN_TO_REG(results[1],nr);
743      lm78_write_value(client,LM78_REG_IN_MAX(nr),data->in_max[nr]);
744    }
745  }
746}
747
748void lm78_fan(struct i2c_client *client, int operation, int ctl_name,
749              int *nrels_mag, long *results)
750{
751  struct lm78_data *data = client->data;
752  int nr = ctl_name - LM78_SYSCTL_FAN1 + 1;
753
754  if (operation == SENSORS_PROC_REAL_INFO)
755    *nrels_mag = 0;
756  else if (operation == SENSORS_PROC_REAL_READ) {
757    lm78_update_client(client);
758    results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
759    results[1] = FAN_FROM_REG(data->fan[nr-1]);
760    *nrels_mag = 2;
761  } else if (operation == SENSORS_PROC_REAL_WRITE) {
762    if (*nrels_mag >= 1) {
763      data->fan_min[nr-1] = FAN_TO_REG(results[0]);
764      lm78_write_value(client,LM78_REG_FAN_MIN(nr),data->fan_min[nr-1]);
765    }
766  }
767}
768
769
770void lm78_temp(struct i2c_client *client, int operation, int ctl_name,
771               int *nrels_mag, long *results)
772{
773  struct lm78_data *data = client->data;
774  if (operation == SENSORS_PROC_REAL_INFO)
775    *nrels_mag = 1;
776  else if (operation == SENSORS_PROC_REAL_READ) {
777    lm78_update_client(client);
778    results[0] = TEMP_FROM_REG(data->temp_over);
779    results[1] = TEMP_FROM_REG(data->temp_hyst);
780    results[2] = TEMP_FROM_REG(data->temp);
781    *nrels_mag = 3;
782  } else if (operation == SENSORS_PROC_REAL_WRITE) {
783    if (*nrels_mag >= 1) {
784      data->temp_over = TEMP_TO_REG(results[0]);
785      lm78_write_value(client,LM78_REG_TEMP_OVER,data->temp_over);
786    }
787    if (*nrels_mag >= 2) {
788      data->temp_hyst = TEMP_TO_REG(results[1]);
789      lm78_write_value(client,LM78_REG_TEMP_HYST,data->temp_hyst);
790    }
791  }
792}
793
794void lm78_vid(struct i2c_client *client, int operation, int ctl_name,
795              int *nrels_mag, long *results)
796{
797  struct lm78_data *data = client->data;
798  if (operation == SENSORS_PROC_REAL_INFO)
799    *nrels_mag = 0;
800  else if (operation == SENSORS_PROC_REAL_READ) {
801    lm78_update_client(client);
802    results[0] = VID_FROM_REG(data->vid);
803    *nrels_mag = 1;
804  }
805}
806
807void lm78_alarms(struct i2c_client *client, int operation, int ctl_name,
808                 int *nrels_mag, long *results)
809{
810  struct lm78_data *data = client->data;
811  if (operation == SENSORS_PROC_REAL_INFO)
812    *nrels_mag = 0;
813  else if (operation == SENSORS_PROC_REAL_READ) {
814    lm78_update_client(client);
815    results[0] = ALARMS_FROM_REG(data->alarms);
816    *nrels_mag = 1;
817  }
818}
819
820void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name,
821                  int *nrels_mag, long *results)
822{
823  struct lm78_data *data = client->data;
824  if (operation == SENSORS_PROC_REAL_INFO)
825    *nrels_mag = 0;
826  else if (operation == SENSORS_PROC_REAL_READ) {
827    lm78_update_client(client);
828    results[0] = DIV_FROM_REG(data->fan_div[0]);
829    results[1] = DIV_FROM_REG(data->fan_div[1]);
830    results[2] = 2;
831    *nrels_mag = 3;
832  } else if (operation == SENSORS_PROC_REAL_WRITE) {
833    if (*nrels_mag >= 2)
834      data->fan_div[1] = DIV_TO_REG(results[1]);
835    if (*nrels_mag >= 1) {
836      data->fan_div[0] = DIV_TO_REG(results[0]);
837      lm78_write_value(client,LM78_REG_VID_FANDIV,
838                       (data->fan_div[0] >> 4) | (data->fan_div[1] >> 6));
839    }
840  }
841}
842
843int lm78_init(void)
844{
845  int res;
846
847  printk("lm78.o version %s (%s)\n",LM_VERSION,LM_DATE);
848  lm78_initialized = 0;
849
850  if ((res =i2c_add_driver(&lm78_driver))) {
851    printk("lm78.o: Driver registration failed, module not inserted.\n");
852    lm78_cleanup();
853    return res;
854  }
855  lm78_initialized ++;
856  return 0;
857}
858
859int lm78_cleanup(void)
860{
861  int res;
862
863  if (lm78_initialized >= 1) {
864    if ((res = i2c_del_driver(&lm78_driver))) {
865      printk("lm78.o: Driver deregistration failed, module not removed.\n");
866      return res;
867    }
868  } else
869    lm78_initialized --;
870
871  return 0;
872}
873
874
875#ifdef MODULE
876
877MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
878MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
879
880int init_module(void)
881{
882  return lm78_init();
883}
884
885int cleanup_module(void)
886{
887  return lm78_cleanup();
888}
889
890#endif /* MODULE */
891
Note: See TracBrowser for help on using the browser.