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

Revision 1199, 26.9 KB (checked in by mds, 12 years ago)

fix support for rev B0.

  • 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 - 2001 Frodo Looijaard <frodol@dds.nl>,
6                        Kyösti Mälkki <kmalkki@cc.hut.fi>, and
7                        Mark D. Studebaker <mdsxyz123@yahoo.com>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/*
25    Supports following revisions:
26        Version         PCI ID          PCI Revision
27        1               1039/0008       AF or less
28        2               1039/0008       B0 or greater
29
30   Note: these chips contain a 0008 device which is incompatible with the
31         5595. We recognize these by the presence of the listed
32         "blacklist" PCI ID and refuse to load.
33
34   NOT SUPPORTED        PCI ID          BLACKLIST PCI ID       
35         540            0008            0540
36         550            0008            0550
37        5513            0008            5511
38        5581            0008            5597
39        5582            0008            5597
40        5597            0008            5597
41        5598            0008            5597/5598
42         630            0008            0630
43         730            0008            0730
44*/
45
46#include <linux/version.h>
47#include <linux/module.h>
48#include <linux/slab.h>
49#include <linux/proc_fs.h>
50#include <linux/ioport.h>
51#include <linux/sysctl.h>
52#include <linux/pci.h>
53#include <asm/errno.h>
54#include <asm/io.h>
55#include <linux/types.h>
56#include <linux/i2c.h>
57#include "version.h"
58#include "sensors.h"
59#include <linux/init.h>
60
61
62#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
63    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
64#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
65#endif
66
67#ifndef THIS_MODULE
68#define THIS_MODULE NULL
69#endif
70
71/* If force_addr is set to anything different from 0, we forcibly enable
72   the device at the given address. */
73static int force_addr = 0;
74MODULE_PARM(force_addr, "i");
75MODULE_PARM_DESC(force_addr,
76                 "Initialize the base address of the sensors");
77
78/* Addresses to scan.
79   Note that we can't determine the ISA address until we have initialized
80   our module */
81static unsigned short normal_i2c[] = { SENSORS_I2C_END };
82static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
83static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
84static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
85
86/* Insmod parameters */
87SENSORS_INSMOD_1(sis5595);
88
89#ifndef PCI_DEVICE_ID_SI_540
90#define PCI_DEVICE_ID_SI_540            0x0540
91#endif
92#ifndef PCI_DEVICE_ID_SI_550
93#define PCI_DEVICE_ID_SI_550            0x0550
94#endif
95#ifndef PCI_DEVICE_ID_SI_630
96#define PCI_DEVICE_ID_SI_630            0x0630
97#endif
98#ifndef PCI_DEVICE_ID_SI_730
99#define PCI_DEVICE_ID_SI_730            0x0730
100#endif
101#ifndef PCI_DEVICE_ID_SI_5598
102#define PCI_DEVICE_ID_SI_5598           0x5598
103#endif
104
105static int blacklist[] = {
106                        PCI_DEVICE_ID_SI_540,
107                        PCI_DEVICE_ID_SI_550,
108                        PCI_DEVICE_ID_SI_630,
109                        PCI_DEVICE_ID_SI_730,
110                        PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
111                                                  that ID shows up in other chips so we
112                                                  use the 5511 ID for recognition */
113                        PCI_DEVICE_ID_SI_5597,
114                        PCI_DEVICE_ID_SI_5598,
115                          0 };
116/*
117   SiS southbridge has a LM78-like chip integrated on the same IC.
118   This driver is a customized copy of lm78.c
119*/
120
121/* Many SIS5595 constants specified below */
122
123/* Length of ISA address segment */
124#define SIS5595_EXTENT 8
125/* PCI Config Registers */
126#define SIS5595_REVISION_REG 0x08
127#define SIS5595_BASE_REG 0x68
128#define SIS5595_PIN_REG 0x7A
129#define SIS5595_ENABLE_REG 0x7B
130
131/* Where are the ISA address/data registers relative to the base address */
132#define SIS5595_ADDR_REG_OFFSET 5
133#define SIS5595_DATA_REG_OFFSET 6
134
135/* The SIS5595 registers */
136#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
137#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
138#define SIS5595_REG_IN(nr) (0x20 + (nr))
139
140#define SIS5595_REG_FAN_MIN(nr) (0x3a + (nr))
141#define SIS5595_REG_FAN(nr) (0x27 + (nr))
142
143/* On the first version of the chip, the temp registers are separate.
144   On the second version,
145   TEMP pin is shared with IN4, configured in PCI register 0x7A.
146   The registers are the same as well.
147   OVER and HYST are really MAX and MIN. */
148
149#define REV2MIN 0xb0
150#define SIS5595_REG_TEMP        (( data->revision) >= REV2MIN) ? \
151                                        SIS5595_REG_IN(4) : 0x27
152#define SIS5595_REG_TEMP_OVER   (( data->revision) >= REV2MIN) ? \
153                                        SIS5595_REG_IN_MAX(4) : 0x39
154#define SIS5595_REG_TEMP_HYST   (( data->revision) >= REV2MIN) ? \
155                                        SIS5595_REG_IN_MIN(4) : 0x3a
156
157#define SIS5595_REG_CONFIG 0x40
158#define SIS5595_REG_ALARM1 0x41
159#define SIS5595_REG_ALARM2 0x42
160#define SIS5595_REG_FANDIV 0x47
161
162/* Conversions. Rounding and limit checking is only done on the TO_REG
163   variants. Note that you should be a bit careful with which arguments
164   these macros are called: arguments may be evaluated more than once.
165   Fixing this is just not worth it. */
166
167#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
168#define IN_FROM_REG(val) (((val) *  16) / 10)
169
170extern inline u8 FAN_TO_REG(long rpm, int div)
171{
172        if (rpm == 0)
173                return 255;
174        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
175        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
176                             254);
177}
178
179#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
180
181/* Version 1 datasheet temp=.83*reg + 52.12 */
182#define TEMP_FROM_REG(val) (((((val)>=0x80?(val)-0x100:(val))*83)+5212)/10)
183/* inverse 1.20*val - 62.77 */
184#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?\
185                                ((((val)*12)-6327)/100):\
186                                ((((val)*12)-6227)/100)),0,255))
187
188#define ALARMS_FROM_REG(val) (val)
189
190#define DIV_FROM_REG(val) (1 << (val))
191#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
192
193/* Initial limits. To keep them sane, we use the 'standard' translation as
194   specified in the SIS5595 sheet. Use the config file to set better limits. */
195#define SIS5595_INIT_IN_0 (((1200)  * 10)/38)
196#define SIS5595_INIT_IN_1 (((500)   * 100)/168)
197#define SIS5595_INIT_IN_2 330
198#define SIS5595_INIT_IN_3 250
199#define SIS5595_INIT_IN_4 250
200
201#define SIS5595_INIT_IN_PERCENTAGE 10
202
203#define SIS5595_INIT_IN_MIN_0 \
204        (SIS5595_INIT_IN_0 - SIS5595_INIT_IN_0 * SIS5595_INIT_IN_PERCENTAGE / 100)
205#define SIS5595_INIT_IN_MAX_0 \
206        (SIS5595_INIT_IN_0 + SIS5595_INIT_IN_0 * SIS5595_INIT_IN_PERCENTAGE / 100)
207#define SIS5595_INIT_IN_MIN_1 \
208        (SIS5595_INIT_IN_1 - SIS5595_INIT_IN_1 * SIS5595_INIT_IN_PERCENTAGE / 100)
209#define SIS5595_INIT_IN_MAX_1 \
210        (SIS5595_INIT_IN_1 + SIS5595_INIT_IN_1 * SIS5595_INIT_IN_PERCENTAGE / 100)
211#define SIS5595_INIT_IN_MIN_2 \
212        (SIS5595_INIT_IN_2 - SIS5595_INIT_IN_2 * SIS5595_INIT_IN_PERCENTAGE / 100)
213#define SIS5595_INIT_IN_MAX_2 \
214        (SIS5595_INIT_IN_2 + SIS5595_INIT_IN_2 * SIS5595_INIT_IN_PERCENTAGE / 100)
215#define SIS5595_INIT_IN_MIN_3 \
216        (SIS5595_INIT_IN_3 - SIS5595_INIT_IN_3 * SIS5595_INIT_IN_PERCENTAGE / 100)
217#define SIS5595_INIT_IN_MAX_3 \
218        (SIS5595_INIT_IN_3 + SIS5595_INIT_IN_3 * SIS5595_INIT_IN_PERCENTAGE / 100)
219#define SIS5595_INIT_IN_MIN_4 \
220        (SIS5595_INIT_IN_4 - SIS5595_INIT_IN_4 * SIS5595_INIT_IN_PERCENTAGE / 100)
221#define SIS5595_INIT_IN_MAX_4 \
222        (SIS5595_INIT_IN_4 + SIS5595_INIT_IN_4 * SIS5595_INIT_IN_PERCENTAGE / 100)
223
224#define SIS5595_INIT_FAN_MIN_1 3000
225#define SIS5595_INIT_FAN_MIN_2 3000
226
227#define SIS5595_INIT_TEMP_OVER 600
228#define SIS5595_INIT_TEMP_HYST 100
229
230#ifdef MODULE
231extern int init_module(void);
232extern int cleanup_module(void);
233#endif                          /* MODULE */
234
235/* For the SIS5595, we need to keep some data in memory. That
236   data is pointed to by sis5595_list[NR]->data. The structure itself is
237   dynamically allocated, at the time when the new sis5595 client is
238   allocated. */
239struct sis5595_data {
240        struct semaphore lock;
241        int sysctl_id;
242
243        struct semaphore update_lock;
244        char valid;             /* !=0 if following fields are valid */
245        unsigned long last_updated;     /* In jiffies */
246        char maxins;            /* == 3 if temp enabled, otherwise == 4 */
247        u8 revision;            /* Reg. value */
248
249        u8 in[5];               /* Register value */
250        u8 in_max[5];           /* Register value */
251        u8 in_min[5];           /* Register value */
252        u8 fan[2];              /* Register value */
253        u8 fan_min[2];          /* Register value */
254        u8 temp;                /* Register value */
255        u8 temp_over;           /* Register value  - really max */
256        u8 temp_hyst;           /* Register value  - really min */
257        u8 fan_div[2];          /* Register encoding, shifted right */
258        u16 alarms;             /* Register encoding, combined */
259};
260
261static struct pci_dev *s_bridge;        /* pointer to the (only) sis5595 */
262
263#ifdef MODULE
264static
265#else
266extern
267#endif
268int __init sensors_sis5595_init(void);
269static int __init sis5595_cleanup(void);
270
271static int sis5595_attach_adapter(struct i2c_adapter *adapter);
272static int sis5595_detect(struct i2c_adapter *adapter, int address,
273                          unsigned short flags, int kind);
274static int sis5595_detach_client(struct i2c_client *client);
275static int sis5595_command(struct i2c_client *client, unsigned int cmd,
276                           void *arg);
277static void sis5595_inc_use(struct i2c_client *client);
278static void sis5595_dec_use(struct i2c_client *client);
279
280static int sis5595_read_value(struct i2c_client *client, u8 register);
281static int sis5595_write_value(struct i2c_client *client, u8 register,
282                               u8 value);
283static void sis5595_update_client(struct i2c_client *client);
284static void sis5595_init_client(struct i2c_client *client);
285static int sis5595_find_sis(int *address);
286
287
288static void sis5595_in(struct i2c_client *client, int operation,
289                       int ctl_name, int *nrels_mag, long *results);
290static void sis5595_fan(struct i2c_client *client, int operation,
291                        int ctl_name, int *nrels_mag, long *results);
292static void sis5595_temp(struct i2c_client *client, int operation,
293                         int ctl_name, int *nrels_mag, long *results);
294static void sis5595_alarms(struct i2c_client *client, int operation,
295                           int ctl_name, int *nrels_mag, long *results);
296static void sis5595_fan_div(struct i2c_client *client, int operation,
297                            int ctl_name, int *nrels_mag, long *results);
298
299static int sis5595_id = 0;
300
301/* The driver. I choose to use type i2c_driver, as at is identical to both
302   smbus_driver and isa_driver, and clients could be of either kind */
303static struct i2c_driver sis5595_driver = {
304        /* name */ "SiS 5595",
305        /* id */ I2C_DRIVERID_SIS5595,
306        /* flags */ I2C_DF_NOTIFY,
307        /* attach_adapter */ &sis5595_attach_adapter,
308        /* detach_client */ &sis5595_detach_client,
309        /* command */ &sis5595_command,
310        /* inc_use */ &sis5595_inc_use,
311        /* dec_use */ &sis5595_dec_use
312};
313
314/* Used by sis5595_init/cleanup */
315static int __initdata sis5595_initialized = 0;
316
317/* The /proc/sys entries */
318/* These files are created for each detected SIS5595. This is just a template;
319   though at first sight, you might think we could use a statically
320   allocated list, we need some way to get back to the parent - which
321   is done through one of the 'extra' fields which are initialized
322   when a new copy is allocated. */
323static ctl_table sis5595_dir_table_template[] = {
324        {SIS5595_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
325         &i2c_sysctl_real, NULL, &sis5595_in},
326        {SIS5595_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
327         &i2c_sysctl_real, NULL, &sis5595_in},
328        {SIS5595_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
329         &i2c_sysctl_real, NULL, &sis5595_in},
330        {SIS5595_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
331         &i2c_sysctl_real, NULL, &sis5595_in},
332        {SIS5595_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
333         &i2c_sysctl_real, NULL, &sis5595_in},
334        {SIS5595_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
335         &i2c_sysctl_real, NULL, &sis5595_fan},
336        {SIS5595_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
337         &i2c_sysctl_real, NULL, &sis5595_fan},
338        {SIS5595_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
339         &i2c_sysctl_real, NULL, &sis5595_temp},
340        {SIS5595_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
341         &i2c_sysctl_real, NULL, &sis5595_fan_div},
342        {SIS5595_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
343         &i2c_sysctl_real, NULL, &sis5595_alarms},
344        {0}
345};
346
347/* This is called when the module is loaded */
348int sis5595_attach_adapter(struct i2c_adapter *adapter)
349{
350        return i2c_detect(adapter, &addr_data, sis5595_detect);
351}
352
353/* Locate SiS bridge and correct base address for SIS5595 */
354int sis5595_find_sis(int *address)
355{
356        u16 val;
357        int *i;
358
359        if (!pci_present())
360                return -ENODEV;
361
362        if (!(s_bridge =
363              pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503,
364                             NULL)))
365                return -ENODEV;
366
367        /* Look for imposters */
368        for(i = blacklist; *i != 0; i++) {
369                if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) {
370                        printk("sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i);
371                        return -ENODEV;
372                }
373        }
374
375        if (PCIBIOS_SUCCESSFUL !=
376            pci_read_config_word(s_bridge, SIS5595_BASE_REG, &val))
377                return -ENODEV;
378
379        *address = val & ~(SIS5595_EXTENT - 1);
380        if (*address == 0 && force_addr == 0) {
381                printk("sis5595.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n");
382                return -ENODEV;
383        }
384        if (force_addr)
385                *address = force_addr;  /* so detect will get called */
386
387        return 0;
388}
389
390int sis5595_detect(struct i2c_adapter *adapter, int address,
391                   unsigned short flags, int kind)
392{
393        int i;
394        struct i2c_client *new_client;
395        struct sis5595_data *data;
396        int err = 0;
397        const char *type_name = "sis5595";
398        const char *client_name = "SIS5595 chip";
399        char val;
400        u16 a;
401
402        /* Make sure we are probing the ISA bus!!  */
403        if (!i2c_is_isa_adapter(adapter)) {
404                printk
405                    ("sis5595.o: sis5595_detect called for an I2C bus adapter?!?\n");
406                return 0;
407        }
408
409        if(force_addr)
410                address = force_addr & ~(SIS5595_EXTENT - 1);
411        if (check_region(address, SIS5595_EXTENT)) {
412                printk("sis5595.o: region 0x%x already in use!\n", address);
413                return -ENODEV;
414        }
415        if(force_addr) {
416                printk("sis5595.o: forcing ISA address 0x%04X\n", address);
417                if (PCIBIOS_SUCCESSFUL !=
418                    pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
419                        return -ENODEV;
420                if (PCIBIOS_SUCCESSFUL !=
421                    pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
422                        return -ENODEV;
423                if ((a & ~(SIS5595_EXTENT - 1)) != address) {
424                        /* doesn't work for some chips? */
425                        printk("sis5595.o: force address failed\n");
426                        return -ENODEV;
427                }
428        }
429
430        if (PCIBIOS_SUCCESSFUL !=
431            pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
432                return -ENODEV;
433        if((val & 0x80) == 0) {
434                printk("sis5595.o: enabling sensors\n");
435                if (PCIBIOS_SUCCESSFUL !=
436                    pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
437                                      val | 0x80))
438                        return -ENODEV;
439                if (PCIBIOS_SUCCESSFUL !=
440                    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
441                        return -ENODEV;
442                if((val & 0x80) == 0) { /* doesn't work for some chips! */
443                        printk("sis5595.o: sensors enable failed - not supported?\n");
444                        return -ENODEV;
445                }
446        }
447
448        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
449                                   sizeof(struct sis5595_data),
450                                   GFP_KERNEL))) {
451                return -ENOMEM;
452        }
453
454        data = (struct sis5595_data *) (new_client + 1);
455        new_client->addr = address;
456        init_MUTEX(&data->lock);
457        new_client->data = data;
458        new_client->adapter = adapter;
459        new_client->driver = &sis5595_driver;
460        new_client->flags = 0;
461
462        /* Reserve the ISA region */
463        request_region(address, SIS5595_EXTENT, type_name);
464
465        /* Check revision and pin registers to determine whether 3 or 4 voltages */
466        pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
467        if(data->revision < REV2MIN) {
468                data->maxins = 3;
469        } else {
470                pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
471                if(val & 0x80)
472                        /* 3 voltages, 1 temp */
473                        data->maxins = 3;
474                else
475                        /* 4 voltages, no temps */
476                        data->maxins = 4;
477        }
478
479        /* Fill in the remaining client fields and put it into the global list */
480        strcpy(new_client->name, client_name);
481
482        new_client->id = sis5595_id++;
483        data->valid = 0;
484        init_MUTEX(&data->update_lock);
485
486        /* Tell the I2C layer a new client has arrived */
487        if ((err = i2c_attach_client(new_client)))
488                goto ERROR3;
489
490        /* Register a new directory entry with module sensors */
491        if ((i = i2c_register_entry((struct i2c_client *) new_client,
492                                        type_name,
493                                        sis5595_dir_table_template,
494                                        THIS_MODULE)) < 0) {
495                err = i;
496                goto ERROR4;
497        }
498        data->sysctl_id = i;
499
500        /* Initialize the SIS5595 chip */
501        sis5595_init_client(new_client);
502        return 0;
503
504      ERROR4:
505        i2c_detach_client(new_client);
506      ERROR3:
507        release_region(address, SIS5595_EXTENT);
508        kfree(new_client);
509        return err;
510}
511
512int sis5595_detach_client(struct i2c_client *client)
513{
514        int err;
515
516        i2c_deregister_entry(((struct sis5595_data *) (client->data))->
517                                 sysctl_id);
518
519        if ((err = i2c_detach_client(client))) {
520                printk
521                    ("sis5595.o: Client deregistration failed, client not detached.\n");
522                return err;
523        }
524
525        release_region(client->addr, SIS5595_EXTENT);
526        kfree(client);
527
528        return 0;
529}
530
531/* No commands defined yet */
532int sis5595_command(struct i2c_client *client, unsigned int cmd, void *arg)
533{
534        return 0;
535}
536
537void sis5595_inc_use(struct i2c_client *client)
538{
539#ifdef MODULE
540        MOD_INC_USE_COUNT;
541#endif
542}
543
544void sis5595_dec_use(struct i2c_client *client)
545{
546#ifdef MODULE
547        MOD_DEC_USE_COUNT;
548#endif
549}
550
551
552/* ISA access must be locked explicitly.
553   There are some ugly typecasts here, but the good news is - they should
554   nowhere else be necessary! */
555int sis5595_read_value(struct i2c_client *client, u8 reg)
556{
557        int res;
558
559        down(&(((struct sis5595_data *) (client->data))->lock));
560        outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
561        res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
562        up(&(((struct sis5595_data *) (client->data))->lock));
563        return res;
564}
565
566int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
567{
568        down(&(((struct sis5595_data *) (client->data))->lock));
569        outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
570        outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
571        up(&(((struct sis5595_data *) (client->data))->lock));
572        return 0;
573}
574
575/* Called when we have found a new SIS5595. It should set limits, etc. */
576void sis5595_init_client(struct i2c_client *client)
577{
578        struct sis5595_data *data = client->data;
579
580        /* Reset all except Watchdog values and last conversion values
581           This sets fan-divs to 2, among others */
582        sis5595_write_value(client, SIS5595_REG_CONFIG, 0x80);
583
584        sis5595_write_value(client, SIS5595_REG_IN_MIN(0),
585                            IN_TO_REG(SIS5595_INIT_IN_MIN_0));
586        sis5595_write_value(client, SIS5595_REG_IN_MAX(0),
587                            IN_TO_REG(SIS5595_INIT_IN_MAX_0));
588        sis5595_write_value(client, SIS5595_REG_IN_MIN(1),
589                            IN_TO_REG(SIS5595_INIT_IN_MIN_1));
590        sis5595_write_value(client, SIS5595_REG_IN_MAX(1),
591                            IN_TO_REG(SIS5595_INIT_IN_MAX_1));
592        sis5595_write_value(client, SIS5595_REG_IN_MIN(2),
593                            IN_TO_REG(SIS5595_INIT_IN_MIN_2));
594        sis5595_write_value(client, SIS5595_REG_IN_MAX(2),
595                            IN_TO_REG(SIS5595_INIT_IN_MAX_2));
596        sis5595_write_value(client, SIS5595_REG_IN_MIN(3),
597                            IN_TO_REG(SIS5595_INIT_IN_MIN_3));
598        sis5595_write_value(client, SIS5595_REG_IN_MAX(3),
599                            IN_TO_REG(SIS5595_INIT_IN_MAX_3));
600        sis5595_write_value(client, SIS5595_REG_FAN_MIN(1),
601                            FAN_TO_REG(SIS5595_INIT_FAN_MIN_1, 2));
602        sis5595_write_value(client, SIS5595_REG_FAN_MIN(2),
603                            FAN_TO_REG(SIS5595_INIT_FAN_MIN_2, 2));
604        if(data->maxins == 4) {
605                sis5595_write_value(client, SIS5595_REG_IN_MIN(4),
606                                    IN_TO_REG(SIS5595_INIT_IN_MIN_4));
607                sis5595_write_value(client, SIS5595_REG_IN_MAX(4),
608                                    IN_TO_REG(SIS5595_INIT_IN_MAX_4));
609        } else {
610                sis5595_write_value(client, SIS5595_REG_TEMP_OVER,
611                                    TEMP_TO_REG(SIS5595_INIT_TEMP_OVER));
612                sis5595_write_value(client, SIS5595_REG_TEMP_HYST,
613                                    TEMP_TO_REG(SIS5595_INIT_TEMP_HYST));
614        }
615
616        /* Start monitoring */
617        sis5595_write_value(client, SIS5595_REG_CONFIG,
618                            (sis5595_read_value(client, SIS5595_REG_CONFIG)
619                             & 0xf7) | 0x01);
620
621}
622
623void sis5595_update_client(struct i2c_client *client)
624{
625        struct sis5595_data *data = client->data;
626        int i;
627
628        down(&data->update_lock);
629
630        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
631            (jiffies < data->last_updated) || !data->valid) {
632
633                for (i = 0; i <= data->maxins; i++) {
634                        data->in[i] =
635                            sis5595_read_value(client, SIS5595_REG_IN(i));
636                        data->in_min[i] =
637                            sis5595_read_value(client,
638                                               SIS5595_REG_IN_MIN(i));
639                        data->in_max[i] =
640                            sis5595_read_value(client,
641                                               SIS5595_REG_IN_MAX(i));
642                }
643                for (i = 1; i <= 2; i++) {
644                        data->fan[i - 1] =
645                            sis5595_read_value(client, SIS5595_REG_FAN(i));
646                        data->fan_min[i - 1] =
647                            sis5595_read_value(client,
648                                               SIS5595_REG_FAN_MIN(i));
649                }
650                if(data->maxins == 3) {
651                        data->temp =
652                            sis5595_read_value(client, SIS5595_REG_TEMP);
653                        data->temp_over =
654                            sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
655                        data->temp_hyst =
656                            sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
657                }
658                i = sis5595_read_value(client, SIS5595_REG_FANDIV);
659                data->fan_div[0] = (i >> 4) & 0x03;
660                data->fan_div[1] = i >> 6;
661                data->alarms =
662                    sis5595_read_value(client, SIS5595_REG_ALARM1) |
663                    (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
664                data->last_updated = jiffies;
665                data->valid = 1;
666        }
667
668        up(&data->update_lock);
669}
670
671
672/* The next few functions are the call-back functions of the /proc/sys and
673   sysctl files. Which function is used is defined in the ctl_table in
674   the extra1 field.
675   Each function must return the magnitude (power of 10 to divide the date
676   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
677   put a maximum of *nrels elements in results reflecting the data of this
678   file, and set *nrels to the number it actually put in it, if operation==
679   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
680   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
681   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
682   large enough (by checking the incoming value of *nrels). This is not very
683   good practice, but as long as you put less than about 5 values in results,
684   you can assume it is large enough. */
685
686/* Return 0 for in4 and disallow writes if pin used for temp */
687void sis5595_in(struct i2c_client *client, int operation, int ctl_name,
688                int *nrels_mag, long *results)
689{
690        struct sis5595_data *data = client->data;
691        int nr = ctl_name - SIS5595_SYSCTL_IN0;
692
693        if (operation == SENSORS_PROC_REAL_INFO)
694                *nrels_mag = 2;
695        else if (operation == SENSORS_PROC_REAL_READ) {
696                if(nr <= 3 || data->maxins == 4) {
697                        sis5595_update_client(client);
698                        results[0] = IN_FROM_REG(data->in_min[nr]);
699                        results[1] = IN_FROM_REG(data->in_max[nr]);
700                        results[2] = IN_FROM_REG(data->in[nr]);
701                } else {
702                        results[0] = 0;
703                        results[1] = 0;
704                        results[2] = 0;
705                }
706                *nrels_mag = 3;
707        } else if (operation == SENSORS_PROC_REAL_WRITE) {
708                if(nr <= 3 || data->maxins == 4) {
709                        if (*nrels_mag >= 1) {
710                                data->in_min[nr] = IN_TO_REG(results[0]);
711                                sis5595_write_value(client,
712                                    SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
713                        }
714                        if (*nrels_mag >= 2) {
715                                data->in_max[nr] = IN_TO_REG(results[1]);
716                                sis5595_write_value(client,
717                                    SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
718                        }
719                }
720        }
721}
722
723void sis5595_fan(struct i2c_client *client, int operation, int ctl_name,
724                 int *nrels_mag, long *results)
725{
726        struct sis5595_data *data = client->data;
727        int nr = ctl_name - SIS5595_SYSCTL_FAN1 + 1;
728
729        if (operation == SENSORS_PROC_REAL_INFO)
730                *nrels_mag = 0;
731        else if (operation == SENSORS_PROC_REAL_READ) {
732                sis5595_update_client(client);
733                results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
734                                          DIV_FROM_REG(data->fan_div[nr - 1]));
735                results[1] = FAN_FROM_REG(data->fan[nr - 1],
736                                          DIV_FROM_REG(data->fan_div[nr - 1]));
737                *nrels_mag = 2;
738        } else if (operation == SENSORS_PROC_REAL_WRITE) {
739                if (*nrels_mag >= 1) {
740                        data->fan_min[nr - 1] = FAN_TO_REG(results[0],
741                                                           DIV_FROM_REG
742                                                           (data->
743                                                            fan_div[nr-1]));
744                        sis5595_write_value(client,
745                                            SIS5595_REG_FAN_MIN(nr),
746                                            data->fan_min[nr - 1]);
747                }
748        }
749}
750
751
752/* Return 0 for temp and disallow writes if pin used for in4 */
753void sis5595_temp(struct i2c_client *client, int operation, int ctl_name,
754                  int *nrels_mag, long *results)
755{
756        struct sis5595_data *data = client->data;
757        if (operation == SENSORS_PROC_REAL_INFO)
758                *nrels_mag = 1;
759        else if (operation == SENSORS_PROC_REAL_READ) {
760                if(data->maxins == 3) {
761                        sis5595_update_client(client);
762                        results[0] = TEMP_FROM_REG(data->temp_over);
763                        results[1] = TEMP_FROM_REG(data->temp_hyst);
764                        results[2] = TEMP_FROM_REG(data->temp);
765                } else {
766                        results[0] = 0;
767                        results[1] = 0;
768                        results[2] = 0;
769                }
770                *nrels_mag = 3;
771        } else if (operation == SENSORS_PROC_REAL_WRITE) {
772                if(data->maxins == 3) {
773                        if (*nrels_mag >= 1) {
774                                data->temp_over = TEMP_TO_REG(results[0]);
775                                sis5595_write_value(client,
776                                    SIS5595_REG_TEMP_OVER, data->temp_over);
777                        }
778                        if (*nrels_mag >= 2) {
779                                data->temp_hyst = TEMP_TO_REG(results[1]);
780                                sis5595_write_value(client,
781                                    SIS5595_REG_TEMP_HYST, data->temp_hyst);
782                        }
783                }
784        }
785}
786
787void sis5595_alarms(struct i2c_client *client, int operation, int ctl_name,
788                    int *nrels_mag, long *results)
789{
790        struct sis5595_data *data = client->data;
791        if (operation == SENSORS_PROC_REAL_INFO)
792                *nrels_mag = 0;
793        else if (operation == SENSORS_PROC_REAL_READ) {
794                sis5595_update_client(client);
795                results[0] = ALARMS_FROM_REG(data->alarms);
796                *nrels_mag = 1;
797        }
798}
799
800void sis5595_fan_div(struct i2c_client *client, int operation,
801                     int ctl_name, int *nrels_mag, long *results)
802{
803        struct sis5595_data *data = client->data;
804        int old;
805
806        if (operation == SENSORS_PROC_REAL_INFO)
807                *nrels_mag = 0;
808        else if (operation == SENSORS_PROC_REAL_READ) {
809                sis5595_update_client(client);
810                results[0] = DIV_FROM_REG(data->fan_div[0]);
811                results[1] = DIV_FROM_REG(data->fan_div[1]);
812                *nrels_mag = 2;
813        } else if (operation == SENSORS_PROC_REAL_WRITE) {
814                old = sis5595_read_value(client, SIS5595_REG_FANDIV);
815                if (*nrels_mag >= 2) {
816                        data->fan_div[1] = DIV_TO_REG(results[1]);
817                        old = (old & 0x3f) | (data->fan_div[1] << 6);
818                }
819                if (*nrels_mag >= 1) {
820                        data->fan_div[0] = DIV_TO_REG(results[0]);
821                        old = (old & 0xcf) | (data->fan_div[0] << 4);
822                        sis5595_write_value(client, SIS5595_REG_FANDIV, old);
823                }
824        }
825}
826
827int __init sensors_sis5595_init(void)
828{
829        int res, addr;
830
831        printk("sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE);
832        sis5595_initialized = 0;
833
834        if (sis5595_find_sis(&addr)) {
835                printk("sis5595.o: SIS5595 not detected, module not inserted.\n");
836                return -ENODEV;
837        }
838        normal_isa[0] = addr;
839
840        if ((res = i2c_add_driver(&sis5595_driver))) {
841                printk
842                    ("sis5595.o: Driver registration failed, module not inserted.\n");
843                sis5595_cleanup();
844                return res;
845        }
846        sis5595_initialized++;
847        return 0;
848}
849
850int __init sis5595_cleanup(void)
851{
852        int res;
853
854        if (sis5595_initialized >= 1) {
855                if ((res = i2c_del_driver(&sis5595_driver))) {
856                        printk
857                            ("sis5595.o: Driver deregistration failed, module not removed.\n");
858                        return res;
859                }
860                sis5595_initialized--;
861        }
862        return 0;
863}
864
865EXPORT_NO_SYMBOLS;
866
867#ifdef MODULE
868
869MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
870MODULE_DESCRIPTION("SiS 5595 Sensor device");
871
872int init_module(void)
873{
874        return sensors_sis5595_init();
875}
876
877int cleanup_module(void)
878{
879        return sis5595_cleanup();
880}
881
882#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.