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

Revision 341, 28.3 KB (checked in by frodo, 14 years ago)

Taught the w83781d module about insmod parameters

Also fixed a small lm78 problem and synchronised the detect script with
the Winbond detection.

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