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

Revision 2867, 22.4 KB (checked in by khali, 8 years ago)

Drop unused client id.

  • 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         645            0008            0645
44         730            0008            0730
45         735            0008            0735
46*/
47
48#include <linux/module.h>
49#include <linux/slab.h>
50#include <linux/ioport.h>
51#include <linux/pci.h>
52#include <linux/i2c.h>
53#include <linux/i2c-proc.h>
54#include <linux/init.h>
55#include <asm/io.h>
56#include "version.h"
57
58MODULE_LICENSE("GPL");
59
60/* If force_addr is set to anything different from 0, we forcibly enable
61   the device at the given address. */
62static int force_addr = 0;
63MODULE_PARM(force_addr, "i");
64MODULE_PARM_DESC(force_addr,
65                 "Initialize the base address of the sensors");
66
67/* Addresses to scan.
68   Note that we can't determine the ISA address until we have initialized
69   our module */
70static unsigned short normal_i2c[] = { SENSORS_I2C_END };
71static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
72static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
73static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
74
75/* Insmod parameters */
76SENSORS_INSMOD_1(sis5595);
77
78static int blacklist[] = {
79                        PCI_DEVICE_ID_SI_540,
80                        PCI_DEVICE_ID_SI_550,
81                        PCI_DEVICE_ID_SI_630,
82                        PCI_DEVICE_ID_SI_730,
83                        PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
84                                                  that ID shows up in other chips so we
85                                                  use the 5511 ID for recognition */
86                        PCI_DEVICE_ID_SI_5597,
87                        PCI_DEVICE_ID_SI_5598,
88                        0x645,
89                        0x735,
90                          0 };
91/*
92   SiS southbridge has a LM78-like chip integrated on the same IC.
93   This driver is a customized copy of lm78.c
94*/
95
96/* Many SIS5595 constants specified below */
97
98/* Length of ISA address segment */
99#define SIS5595_EXTENT 8
100/* PCI Config Registers */
101#define SIS5595_REVISION_REG 0x08
102#define SIS5595_BASE_REG 0x68
103#define SIS5595_PIN_REG 0x7A
104#define SIS5595_ENABLE_REG 0x7B
105
106/* Where are the ISA address/data registers relative to the base address */
107#define SIS5595_ADDR_REG_OFFSET 5
108#define SIS5595_DATA_REG_OFFSET 6
109
110/* The SIS5595 registers */
111#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
112#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
113#define SIS5595_REG_IN(nr) (0x20 + (nr))
114
115#define SIS5595_REG_FAN_MIN(nr) (0x3a + (nr))
116#define SIS5595_REG_FAN(nr) (0x27 + (nr))
117
118/* On the first version of the chip, the temp registers are separate.
119   On the second version,
120   TEMP pin is shared with IN4, configured in PCI register 0x7A.
121   The registers are the same as well.
122   OVER and HYST are really MAX and MIN. */
123
124#define REV2MIN 0xb0
125#define SIS5595_REG_TEMP        (( data->revision) >= REV2MIN) ? \
126                                        SIS5595_REG_IN(4) : 0x27
127#define SIS5595_REG_TEMP_OVER   (( data->revision) >= REV2MIN) ? \
128                                        SIS5595_REG_IN_MAX(4) : 0x39
129#define SIS5595_REG_TEMP_HYST   (( data->revision) >= REV2MIN) ? \
130                                        SIS5595_REG_IN_MIN(4) : 0x3a
131
132#define SIS5595_REG_CONFIG 0x40
133#define SIS5595_REG_ALARM1 0x41
134#define SIS5595_REG_ALARM2 0x42
135#define SIS5595_REG_FANDIV 0x47
136
137/* Conversions. Limit checking is only done on the TO_REG
138   variants. Note that you should be a bit careful with which arguments
139   these macros are called: arguments may be evaluated more than once.
140   Fixing this is just not worth it. */
141
142#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
143#define IN_FROM_REG(val) (((val) *  16 + 5) / 10)
144
145static inline u8 FAN_TO_REG(long rpm, int div)
146{
147        if (rpm == 0)
148                return 255;
149        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
150        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
151                             254);
152}
153
154#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
155
156/* Version 1 datasheet temp=.83*reg + 52.12 */
157#define TEMP_FROM_REG(val) (((((val)>=0x80?(val)-0x100:(val))*83)+5212)/10)
158/* inverse 1.20*val - 62.77 */
159#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?\
160                                ((((val)*12)-6327)/100):\
161                                ((((val)*12)-6227)/100)),0,255))
162
163#define ALARMS_FROM_REG(val) (val)
164
165#define DIV_FROM_REG(val) (1 << (val))
166#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
167
168/* For the SIS5595, we need to keep some data in memory. That
169   data is pointed to by sis5595_list[NR]->data. The structure itself is
170   dynamically allocated, at the time when the new sis5595 client is
171   allocated. */
172struct sis5595_data {
173        struct i2c_client client;
174        struct semaphore lock;
175        int sysctl_id;
176
177        struct semaphore update_lock;
178        char valid;             /* !=0 if following fields are valid */
179        unsigned long last_updated;     /* In jiffies */
180        char maxins;            /* == 3 if temp enabled, otherwise == 4 */
181        u8 revision;            /* Reg. value */
182
183        u8 in[5];               /* Register value */
184        u8 in_max[5];           /* Register value */
185        u8 in_min[5];           /* Register value */
186        u8 fan[2];              /* Register value */
187        u8 fan_min[2];          /* Register value */
188        u8 temp;                /* Register value */
189        u8 temp_over;           /* Register value  - really max */
190        u8 temp_hyst;           /* Register value  - really min */
191        u8 fan_div[2];          /* Register encoding, shifted right */
192        u16 alarms;             /* Register encoding, combined */
193};
194
195static struct pci_dev *s_bridge;        /* pointer to the (only) sis5595 */
196
197static int sis5595_attach_adapter(struct i2c_adapter *adapter);
198static int sis5595_detect(struct i2c_adapter *adapter, int address,
199                          unsigned short flags, int kind);
200static int sis5595_detach_client(struct i2c_client *client);
201
202static int sis5595_read_value(struct i2c_client *client, u8 register);
203static int sis5595_write_value(struct i2c_client *client, u8 register,
204                               u8 value);
205static void sis5595_update_client(struct i2c_client *client);
206static void sis5595_init_client(struct i2c_client *client);
207static int sis5595_find_sis(int *address);
208
209
210static void sis5595_in(struct i2c_client *client, int operation,
211                       int ctl_name, int *nrels_mag, long *results);
212static void sis5595_fan(struct i2c_client *client, int operation,
213                        int ctl_name, int *nrels_mag, long *results);
214static void sis5595_temp(struct i2c_client *client, int operation,
215                         int ctl_name, int *nrels_mag, long *results);
216static void sis5595_alarms(struct i2c_client *client, int operation,
217                           int ctl_name, int *nrels_mag, long *results);
218static void sis5595_fan_div(struct i2c_client *client, int operation,
219                            int ctl_name, int *nrels_mag, long *results);
220
221/* The driver. I choose to use type i2c_driver, as at is identical to both
222   smbus_driver and isa_driver, and clients could be of either kind */
223static struct i2c_driver sis5595_driver = {
224        .name           = "SiS 5595",
225        .id             = I2C_DRIVERID_SIS5595,
226        .flags          = I2C_DF_NOTIFY,
227        .attach_adapter = sis5595_attach_adapter,
228        .detach_client  = sis5595_detach_client,
229};
230
231/* The /proc/sys entries */
232
233/* -- SENSORS SYSCTL START -- */
234#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */
235#define SIS5595_SYSCTL_IN1 1001
236#define SIS5595_SYSCTL_IN2 1002
237#define SIS5595_SYSCTL_IN3 1003
238#define SIS5595_SYSCTL_IN4 1004
239#define SIS5595_SYSCTL_FAN1 1101        /* Rotations/min */
240#define SIS5595_SYSCTL_FAN2 1102
241#define SIS5595_SYSCTL_TEMP 1200        /* Degrees Celcius * 10 */
242#define SIS5595_SYSCTL_FAN_DIV 2000     /* 1, 2, 4 or 8 */
243#define SIS5595_SYSCTL_ALARMS 2001      /* bitvector */
244
245#define SIS5595_ALARM_IN0 0x01
246#define SIS5595_ALARM_IN1 0x02
247#define SIS5595_ALARM_IN2 0x04
248#define SIS5595_ALARM_IN3 0x08
249#define SIS5595_ALARM_BTI 0x20
250#define SIS5595_ALARM_FAN1 0x40
251#define SIS5595_ALARM_FAN2 0x80
252#define SIS5595_ALARM_IN4  0x8000
253#define SIS5595_ALARM_TEMP 0x8000
254
255/* -- SENSORS SYSCTL END -- */
256
257/* These files are created for each detected SIS5595. This is just a template;
258   though at first sight, you might think we could use a statically
259   allocated list, we need some way to get back to the parent - which
260   is done through one of the 'extra' fields which are initialized
261   when a new copy is allocated. */
262static ctl_table sis5595_dir_table_template[] = {
263        {SIS5595_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
264         &i2c_sysctl_real, NULL, &sis5595_in},
265        {SIS5595_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
266         &i2c_sysctl_real, NULL, &sis5595_in},
267        {SIS5595_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
268         &i2c_sysctl_real, NULL, &sis5595_in},
269        {SIS5595_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
270         &i2c_sysctl_real, NULL, &sis5595_in},
271        {SIS5595_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
272         &i2c_sysctl_real, NULL, &sis5595_in},
273        {SIS5595_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
274         &i2c_sysctl_real, NULL, &sis5595_fan},
275        {SIS5595_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
276         &i2c_sysctl_real, NULL, &sis5595_fan},
277        {SIS5595_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
278         &i2c_sysctl_real, NULL, &sis5595_temp},
279        {SIS5595_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
280         &i2c_sysctl_real, NULL, &sis5595_fan_div},
281        {SIS5595_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
282         &i2c_sysctl_real, NULL, &sis5595_alarms},
283        {0}
284};
285
286/* This is called when the module is loaded */
287static int sis5595_attach_adapter(struct i2c_adapter *adapter)
288{
289        return i2c_detect(adapter, &addr_data, sis5595_detect);
290}
291
292/* Locate SiS bridge and correct base address for SIS5595 */
293static int sis5595_find_sis(int *address)
294{
295        u16 val;
296        int *i;
297
298        if (!pci_present())
299                return -ENODEV;
300
301        if (!(s_bridge =
302              pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503,
303                             NULL)))
304                return -ENODEV;
305
306        /* Look for imposters */
307        for(i = blacklist; *i != 0; i++) {
308                if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) {
309                        printk("sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i);
310                        return -ENODEV;
311                }
312        }
313
314        if (PCIBIOS_SUCCESSFUL !=
315            pci_read_config_word(s_bridge, SIS5595_BASE_REG, &val))
316                return -ENODEV;
317
318        *address = val & ~(SIS5595_EXTENT - 1);
319        if (*address == 0 && force_addr == 0) {
320                printk("sis5595.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n");
321                return -ENODEV;
322        }
323        if (force_addr)
324                *address = force_addr;  /* so detect will get called */
325
326        return 0;
327}
328
329int sis5595_detect(struct i2c_adapter *adapter, int address,
330                   unsigned short flags, int kind)
331{
332        int i;
333        struct i2c_client *new_client;
334        struct sis5595_data *data;
335        int err = 0;
336        const char *type_name = "sis5595";
337        const char *client_name = "SIS5595 chip";
338        char val;
339        u16 a;
340
341        /* Make sure we are probing the ISA bus!!  */
342        if (!i2c_is_isa_adapter(adapter)) {
343                printk
344                    ("sis5595.o: sis5595_detect called for an I2C bus adapter?!?\n");
345                return 0;
346        }
347
348        if(force_addr)
349                address = force_addr & ~(SIS5595_EXTENT - 1);
350        if (check_region(address, SIS5595_EXTENT)) {
351                printk("sis5595.o: region 0x%x already in use!\n", address);
352                return -ENODEV;
353        }
354        if(force_addr) {
355                printk("sis5595.o: forcing ISA address 0x%04X\n", address);
356                if (PCIBIOS_SUCCESSFUL !=
357                    pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
358                        return -ENODEV;
359                if (PCIBIOS_SUCCESSFUL !=
360                    pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
361                        return -ENODEV;
362                if ((a & ~(SIS5595_EXTENT - 1)) != address) {
363                        /* doesn't work for some chips? */
364                        printk("sis5595.o: force address failed\n");
365                        return -ENODEV;
366                }
367        }
368
369        if (PCIBIOS_SUCCESSFUL !=
370            pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
371                return -ENODEV;
372        if((val & 0x80) == 0) {
373                printk("sis5595.o: enabling sensors\n");
374                if (PCIBIOS_SUCCESSFUL !=
375                    pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
376                                      val | 0x80))
377                        return -ENODEV;
378                if (PCIBIOS_SUCCESSFUL !=
379                    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
380                        return -ENODEV;
381                if((val & 0x80) == 0) { /* doesn't work for some chips! */
382                        printk("sis5595.o: sensors enable failed - not supported?\n");
383                        return -ENODEV;
384                }
385        }
386
387        if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
388                return -ENOMEM;
389        }
390
391        new_client = &data->client;
392        new_client->addr = address;
393        init_MUTEX(&data->lock);
394        new_client->data = data;
395        new_client->adapter = adapter;
396        new_client->driver = &sis5595_driver;
397        new_client->flags = 0;
398
399        /* Reserve the ISA region */
400        request_region(address, SIS5595_EXTENT, type_name);
401
402        /* Check revision and pin registers to determine whether 3 or 4 voltages */
403        pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
404        if(data->revision < REV2MIN) {
405                data->maxins = 3;
406        } else {
407                pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
408                if(val & 0x80)
409                        /* 3 voltages, 1 temp */
410                        data->maxins = 3;
411                else
412                        /* 4 voltages, no temps */
413                        data->maxins = 4;
414        }
415
416        /* Fill in the remaining client fields and put it into the global list */
417        strcpy(new_client->name, client_name);
418        data->valid = 0;
419        init_MUTEX(&data->update_lock);
420
421        /* Tell the I2C layer a new client has arrived */
422        if ((err = i2c_attach_client(new_client)))
423                goto ERROR3;
424
425        /* Register a new directory entry with module sensors */
426        if ((i = i2c_register_entry((struct i2c_client *) new_client,
427                                        type_name,
428                                        sis5595_dir_table_template,
429                                        THIS_MODULE)) < 0) {
430                err = i;
431                goto ERROR4;
432        }
433        data->sysctl_id = i;
434
435        /* Initialize the SIS5595 chip */
436        sis5595_init_client(new_client);
437        return 0;
438
439      ERROR4:
440        i2c_detach_client(new_client);
441      ERROR3:
442        release_region(address, SIS5595_EXTENT);
443        kfree(data);
444        return err;
445}
446
447static int sis5595_detach_client(struct i2c_client *client)
448{
449        int err;
450
451        i2c_deregister_entry(((struct sis5595_data *) (client->data))->
452                                 sysctl_id);
453
454        if ((err = i2c_detach_client(client))) {
455                printk
456                    ("sis5595.o: Client deregistration failed, client not detached.\n");
457                return err;
458        }
459
460        release_region(client->addr, SIS5595_EXTENT);
461        kfree(client->data);
462
463        return 0;
464}
465
466
467/* ISA access must be locked explicitly.
468   There are some ugly typecasts here, but the good news is - they should
469   nowhere else be necessary! */
470static int sis5595_read_value(struct i2c_client *client, u8 reg)
471{
472        int res;
473
474        down(&(((struct sis5595_data *) (client->data))->lock));
475        outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
476        res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
477        up(&(((struct sis5595_data *) (client->data))->lock));
478        return res;
479}
480
481static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
482{
483        down(&(((struct sis5595_data *) (client->data))->lock));
484        outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
485        outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
486        up(&(((struct sis5595_data *) (client->data))->lock));
487        return 0;
488}
489
490/* Called when we have found a new SIS5595. */
491static void sis5595_init_client(struct i2c_client *client)
492{
493        u8 reg;
494
495        /* Start monitoring */
496        reg = i2c_smbus_read_byte_data(client, SIS5595_REG_CONFIG);
497        sis5595_write_value(client, SIS5595_REG_CONFIG, (reg|0x01)&0x7F);
498}
499
500static void sis5595_update_client(struct i2c_client *client)
501{
502        struct sis5595_data *data = client->data;
503        int i;
504
505        down(&data->update_lock);
506
507        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
508            (jiffies < data->last_updated) || !data->valid) {
509
510                for (i = 0; i <= data->maxins; i++) {
511                        data->in[i] =
512                            sis5595_read_value(client, SIS5595_REG_IN(i));
513                        data->in_min[i] =
514                            sis5595_read_value(client,
515                                               SIS5595_REG_IN_MIN(i));
516                        data->in_max[i] =
517                            sis5595_read_value(client,
518                                               SIS5595_REG_IN_MAX(i));
519                }
520                for (i = 1; i <= 2; i++) {
521                        data->fan[i - 1] =
522                            sis5595_read_value(client, SIS5595_REG_FAN(i));
523                        data->fan_min[i - 1] =
524                            sis5595_read_value(client,
525                                               SIS5595_REG_FAN_MIN(i));
526                }
527                if(data->maxins == 3) {
528                        data->temp =
529                            sis5595_read_value(client, SIS5595_REG_TEMP);
530                        data->temp_over =
531                            sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
532                        data->temp_hyst =
533                            sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
534                }
535                i = sis5595_read_value(client, SIS5595_REG_FANDIV);
536                data->fan_div[0] = (i >> 4) & 0x03;
537                data->fan_div[1] = i >> 6;
538                data->alarms =
539                    sis5595_read_value(client, SIS5595_REG_ALARM1) |
540                    (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
541                data->last_updated = jiffies;
542                data->valid = 1;
543        }
544
545        up(&data->update_lock);
546}
547
548
549/* The next few functions are the call-back functions of the /proc/sys and
550   sysctl files. Which function is used is defined in the ctl_table in
551   the extra1 field.
552   Each function must return the magnitude (power of 10 to divide the date
553   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
554   put a maximum of *nrels elements in results reflecting the data of this
555   file, and set *nrels to the number it actually put in it, if operation==
556   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
557   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
558   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
559   large enough (by checking the incoming value of *nrels). This is not very
560   good practice, but as long as you put less than about 5 values in results,
561   you can assume it is large enough. */
562
563/* Return 0 for in4 and disallow writes if pin used for temp */
564void sis5595_in(struct i2c_client *client, int operation, int ctl_name,
565                int *nrels_mag, long *results)
566{
567        struct sis5595_data *data = client->data;
568        int nr = ctl_name - SIS5595_SYSCTL_IN0;
569
570        if (operation == SENSORS_PROC_REAL_INFO)
571                *nrels_mag = 2;
572        else if (operation == SENSORS_PROC_REAL_READ) {
573                if(nr <= 3 || data->maxins == 4) {
574                        sis5595_update_client(client);
575                        results[0] = IN_FROM_REG(data->in_min[nr]);
576                        results[1] = IN_FROM_REG(data->in_max[nr]);
577                        results[2] = IN_FROM_REG(data->in[nr]);
578                } else {
579                        results[0] = 0;
580                        results[1] = 0;
581                        results[2] = 0;
582                }
583                *nrels_mag = 3;
584        } else if (operation == SENSORS_PROC_REAL_WRITE) {
585                if(nr <= 3 || data->maxins == 4) {
586                        if (*nrels_mag >= 1) {
587                                data->in_min[nr] = IN_TO_REG(results[0]);
588                                sis5595_write_value(client,
589                                    SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
590                        }
591                        if (*nrels_mag >= 2) {
592                                data->in_max[nr] = IN_TO_REG(results[1]);
593                                sis5595_write_value(client,
594                                    SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
595                        }
596                }
597        }
598}
599
600void sis5595_fan(struct i2c_client *client, int operation, int ctl_name,
601                 int *nrels_mag, long *results)
602{
603        struct sis5595_data *data = client->data;
604        int nr = ctl_name - SIS5595_SYSCTL_FAN1 + 1;
605
606        if (operation == SENSORS_PROC_REAL_INFO)
607                *nrels_mag = 0;
608        else if (operation == SENSORS_PROC_REAL_READ) {
609                sis5595_update_client(client);
610                results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
611                                          DIV_FROM_REG(data->fan_div[nr - 1]));
612                results[1] = FAN_FROM_REG(data->fan[nr - 1],
613                                          DIV_FROM_REG(data->fan_div[nr - 1]));
614                *nrels_mag = 2;
615        } else if (operation == SENSORS_PROC_REAL_WRITE) {
616                if (*nrels_mag >= 1) {
617                        data->fan_min[nr - 1] = FAN_TO_REG(results[0],
618                                                           DIV_FROM_REG
619                                                           (data->
620                                                            fan_div[nr-1]));
621                        sis5595_write_value(client,
622                                            SIS5595_REG_FAN_MIN(nr),
623                                            data->fan_min[nr - 1]);
624                }
625        }
626}
627
628
629/* Return 0 for temp and disallow writes if pin used for in4 */
630void sis5595_temp(struct i2c_client *client, int operation, int ctl_name,
631                  int *nrels_mag, long *results)
632{
633        struct sis5595_data *data = client->data;
634        if (operation == SENSORS_PROC_REAL_INFO)
635                *nrels_mag = 1;
636        else if (operation == SENSORS_PROC_REAL_READ) {
637                if(data->maxins == 3) {
638                        sis5595_update_client(client);
639                        results[0] = TEMP_FROM_REG(data->temp_over);
640                        results[1] = TEMP_FROM_REG(data->temp_hyst);
641                        results[2] = TEMP_FROM_REG(data->temp);
642                } else {
643                        results[0] = 0;
644                        results[1] = 0;
645                        results[2] = 0;
646                }
647                *nrels_mag = 3;
648        } else if (operation == SENSORS_PROC_REAL_WRITE) {
649                if(data->maxins == 3) {
650                        if (*nrels_mag >= 1) {
651                                data->temp_over = TEMP_TO_REG(results[0]);
652                                sis5595_write_value(client,
653                                    SIS5595_REG_TEMP_OVER, data->temp_over);
654                        }
655                        if (*nrels_mag >= 2) {
656                                data->temp_hyst = TEMP_TO_REG(results[1]);
657                                sis5595_write_value(client,
658                                    SIS5595_REG_TEMP_HYST, data->temp_hyst);
659                        }
660                }
661        }
662}
663
664void sis5595_alarms(struct i2c_client *client, int operation, int ctl_name,
665                    int *nrels_mag, long *results)
666{
667        struct sis5595_data *data = client->data;
668        if (operation == SENSORS_PROC_REAL_INFO)
669                *nrels_mag = 0;
670        else if (operation == SENSORS_PROC_REAL_READ) {
671                sis5595_update_client(client);
672                results[0] = ALARMS_FROM_REG(data->alarms);
673                *nrels_mag = 1;
674        }
675}
676
677void sis5595_fan_div(struct i2c_client *client, int operation,
678                     int ctl_name, int *nrels_mag, long *results)
679{
680        struct sis5595_data *data = client->data;
681        int old;
682
683        if (operation == SENSORS_PROC_REAL_INFO)
684                *nrels_mag = 0;
685        else if (operation == SENSORS_PROC_REAL_READ) {
686                sis5595_update_client(client);
687                results[0] = DIV_FROM_REG(data->fan_div[0]);
688                results[1] = DIV_FROM_REG(data->fan_div[1]);
689                *nrels_mag = 2;
690        } else if (operation == SENSORS_PROC_REAL_WRITE) {
691                old = sis5595_read_value(client, SIS5595_REG_FANDIV);
692                if (*nrels_mag >= 2) {
693                        data->fan_div[1] = DIV_TO_REG(results[1]);
694                        old = (old & 0x3f) | (data->fan_div[1] << 6);
695                }
696                if (*nrels_mag >= 1) {
697                        data->fan_div[0] = DIV_TO_REG(results[0]);
698                        old = (old & 0xcf) | (data->fan_div[0] << 4);
699                        sis5595_write_value(client, SIS5595_REG_FANDIV, old);
700                }
701        }
702}
703
704static int __init sm_sis5595_init(void)
705{
706        int addr;
707
708        printk("sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE);
709
710        if (sis5595_find_sis(&addr)) {
711                printk("sis5595.o: SIS5595 not detected, module not inserted.\n");
712                return -ENODEV;
713        }
714        normal_isa[0] = addr;
715
716        return i2c_add_driver(&sis5595_driver);
717}
718
719static void __exit sm_sis5595_exit(void)
720{
721        i2c_del_driver(&sis5595_driver);
722}
723
724
725
726MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
727MODULE_DESCRIPTION("SiS 5595 Sensor device");
728
729module_init(sm_sis5595_init);
730module_exit(sm_sis5595_exit);
Note: See TracBrowser for help on using the browser.