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

Revision 207, 31.5 KB (checked in by frodo, 14 years ago)

Adrian's copyright patch applied

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