root/lm-sensors/trunk/kernel/chips/sis5595.c @ 333

Revision 333, 26.5 KB (checked in by mds, 14 years ago)

changed /proc permissions for vid and alarms and
other r/o stuff to 444.

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