root/lm-sensors/trunk/kernel/chips/f71805f.c @ 3169

Revision 3169, 19.9 KB (checked in by khali, 8 years ago)

Initial support for the Fintek F71805F/FG chip.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * f71805f.c - driver for the Fintek F71805F Super-I/O chip integrated
3 *             hardware monitoring features
4 * Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
5 *
6 * The F71805F is a LPC Super-I/O chip made by Fintek. It integrates
7 * complete hardware monitoring features: voltage, fan and temperature
8 * sensors, and manual and automatic fan speed control.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/slab.h>
28#include <linux/ioport.h>
29#include <linux/i2c.h>
30#include <linux/i2c-proc.h>
31#include <asm/io.h>
32#include "version.h"
33
34/* ISA address is read from Super-I/O configuration space */
35static unsigned short normal_i2c[] = { SENSORS_I2C_END };
36static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
37static unsigned int normal_isa[] = { 0, SENSORS_ISA_END };
38static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
39
40SENSORS_INSMOD_1(f71805f);
41
42#define DRVNAME "f71805f"
43
44/*
45 * Super-I/O constants and functions
46 */
47
48static int REG;         /* The register to read from/write to */
49static int VAL;         /* The value to read/write */
50
51#define F71805F_LD_HWM          0x04
52
53#define SIO_REG_LDSEL           0x07    /* Logical device select */
54#define SIO_REG_DEVID           0x20    /* Device ID (2 bytes) */
55#define SIO_REG_DEVREV          0x22    /* Device revision */
56#define SIO_REG_ENABLE          0x30    /* Logical device enable */
57#define SIO_REG_ADDR            0x60    /* Logical device address (2 bytes) */
58
59#define SIO_F71805F_ID          0x0406
60
61static inline int
62superio_inb(int reg)
63{
64        outb(reg, REG);
65        return inb(VAL);
66}
67
68static int
69superio_inw(int reg)
70{
71        int val;
72        outb(reg++, REG);
73        val = inb(VAL) << 8;
74        outb(reg, REG);
75        val |= inb(VAL);
76        return val;
77}
78
79static inline void
80superio_select(int ld)
81{
82        outb(SIO_REG_LDSEL, REG);
83        outb(ld, VAL);
84}
85
86static inline void
87superio_enter(void)
88{
89        outb(0x87, REG);
90        outb(0x87, REG);
91}
92
93static inline void
94superio_exit(void)
95{
96        outb(0xaa, REG);
97}
98
99/*
100 * ISA constants
101 */
102
103#define REGION_LENGTH           2
104#define ADDR_REG_OFFSET         0
105#define DATA_REG_OFFSET         1
106
107/*
108 * Registers
109 */
110
111/* in nr from 0 to 8 (8-bit values) */
112#define F71805F_REG_IN(nr)              (0x10 + (nr))
113#define F71805F_REG_IN_HIGH(nr)         (0x40 + 2 * (nr))
114#define F71805F_REG_IN_LOW(nr)          (0x41 + 2 * (nr))
115/* fan nr from 0 to 2 (12-bit values, two registers) */
116#define F71805F_REG_FAN(nr)             (0x20 + 2 * (nr))
117#define F71805F_REG_FAN_LOW(nr)         (0x28 + 2 * (nr))
118#define F71805F_REG_FAN_CTRL(nr)        (0x60 + 16 * (nr))
119/* temp nr from 0 to 2 (8-bit values) */
120#define F71805F_REG_TEMP(nr)            (0x1B + (nr))
121#define F71805F_REG_TEMP_HIGH(nr)       (0x54 + 2 * (nr))
122#define F71805F_REG_TEMP_HYST(nr)       (0x55 + 2 * (nr))
123#define F71805F_REG_TEMP_MODE           0x01
124
125#define F71805F_REG_START               0x00
126/* status nr from 0 to 2 */
127#define F71805F_REG_STATUS(nr)          (0x36 + (nr))
128
129/*
130 * Data structures and manipulation thereof
131 */
132
133struct f71805f_data {
134        struct i2c_client client;
135        struct semaphore lock;
136        int sysctl_id;
137
138        struct semaphore update_lock;
139        char valid;             /* !=0 if following fields are valid */
140        unsigned long last_updated;     /* In jiffies */
141        unsigned long last_limits;      /* In jiffies */
142
143        /* Register values */
144        u8 in[9];
145        u8 in_high[9];
146        u8 in_low[9];
147        u16 fan[3];
148        u16 fan_low[3];
149        u8 fan_enabled;         /* Read once at init time */
150        u8 temp[3];
151        u8 temp_high[3];
152        u8 temp_hyst[3];
153        u8 temp_mode;
154        u8 alarms[3];
155};
156
157static inline long in_from_reg(u8 reg)
158{
159        return (reg * 8);
160}
161
162/* The 2 least significant bits are not used */
163static inline u8 in_to_reg(long val)
164{
165        if (val <= 0)
166                return 0;
167        if (val >= 2016)
168                return 0xfc;
169        return (((val + 16) / 32) << 2);
170}
171
172/* in0 is downscaled by a factor 2 internally */
173static inline long in0_from_reg(u8 reg)
174{
175        return (reg * 16);
176}
177
178static inline u8 in0_to_reg(long val)
179{
180        if (val <= 0)
181                return 0;
182        if (val >= 4032)
183                return 0xfc;
184        return (((val + 32) / 64) << 2);
185}
186
187/* The 4 most significant bits are not used */
188static inline long fan_from_reg(u16 reg)
189{
190        reg &= 0xfff;
191        if (!reg || reg == 0xfff)
192                return 0;
193        return (1500000 / reg);
194}
195
196static inline u16 fan_to_reg(long rpm)
197{
198        /* If the low limit is set below what the chip can measure,
199           store the largest possible 12-bit value in the registers,
200           so that no alarm will ever trigger. */
201        if (rpm < 367)
202                return 0xfff;
203        return (1500000 / rpm);
204}
205
206static inline u8 temp_to_reg(long val)
207{
208        if (val < 0)
209                val = 0;
210        else if (val > 0xff)
211                val = 0xff;
212        return val;
213}
214
215/*
216 * Driver and client management
217 */
218
219static u8 f71805f_read8(struct i2c_client *client, u8 reg)
220{
221        struct f71805f_data *data = client->data;
222        u8 val;
223
224        down(&data->lock);
225        outb_p(reg, client->addr + ADDR_REG_OFFSET);
226        val = inb_p(client->addr + DATA_REG_OFFSET);
227        up(&data->lock);
228
229        return val;
230}
231
232static void f71805f_write8(struct i2c_client *client, u8 reg, u8 val)
233{
234        struct f71805f_data *data = client->data;
235
236        down(&data->lock);
237        outb_p(reg, client->addr + ADDR_REG_OFFSET);
238        outb_p(val, client->addr + DATA_REG_OFFSET);
239        up(&data->lock);
240}
241
242/* It is important to read the MSB first, because doing so latches the
243   value of the LSB, so we are sure both bytes belong to the same value. */
244static u16 f71805f_read16(struct i2c_client *client, u8 reg)
245{
246        struct f71805f_data *data = client->data;
247        u16 val;
248
249        down(&data->lock);
250        outb_p(reg, client->addr + ADDR_REG_OFFSET);
251        val = inb_p(client->addr + DATA_REG_OFFSET) << 8;
252        outb_p(++reg, client->addr + ADDR_REG_OFFSET);
253        val |= inb_p(client->addr + DATA_REG_OFFSET);
254        up(&data->lock);
255
256        return val;
257}
258
259static void f71805f_write16(struct i2c_client *client, u8 reg, u16 val)
260{
261        struct f71805f_data *data = client->data;
262
263        down(&data->lock);
264        outb_p(reg, client->addr + ADDR_REG_OFFSET);
265        outb_p(val >> 8, client->addr + DATA_REG_OFFSET);
266        outb_p(++reg, client->addr + ADDR_REG_OFFSET);
267        outb_p(val & 0xff, client->addr + DATA_REG_OFFSET);
268        up(&data->lock);
269}
270
271static struct i2c_driver f71805f_driver;
272static ctl_table f71805f_dir_table_template[];
273
274static void f71805f_init_client(struct i2c_client *client)
275{
276        struct f71805f_data *data = client->data;
277        u8 reg;
278        int i;
279
280        reg = f71805f_read8(client, F71805F_REG_START);
281        if ((reg & 0x41) != 0x01) {
282                printk(KERN_DEBUG "%s: Starting monitoring operations\n",
283                       DRVNAME);
284                f71805f_write8(client,
285                               F71805F_REG_START, (reg | 0x01) & ~0x40);
286        }
287
288        /* Fan monitoring can be disabled. If it is, we won't be polling
289           the register values, and instead set the cache to return 0 RPM. */
290        for (i = 0; i < 3; i++) {
291                reg = f71805f_read8(client, F71805F_REG_FAN_CTRL(i));
292                if (!(reg & 0x80))
293                        data->fan_enabled |= (1 << i);
294                else
295                        data->fan[i] = data->fan_low[i] = 0xfff;
296        }
297}
298
299static int f71805f_detect(struct i2c_adapter *adapter, int address,
300                          unsigned short flags, int kind)
301{
302        struct i2c_client *client;
303        struct f71805f_data *data;
304        int err = 0;
305
306        if (!request_region(address, REGION_LENGTH, f71805f_driver.name)) {
307                err = -EBUSY;
308                goto exit;
309        }
310
311        if (!(data = kmalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
312                err = -ENOMEM;
313                goto exit_release;
314        }
315        memset(data, 0, sizeof(struct f71805f_data));
316
317        /* Fill in the client fields */
318        client = &data->client;
319        client->addr = address;
320        client->data = data;
321        client->adapter = adapter;
322        client->driver = &f71805f_driver;
323        strcpy(client->name, "F71805F chip");
324
325        init_MUTEX(&data->lock);
326        init_MUTEX(&data->update_lock);
327
328        /* Tell the i2c core a new client has arrived */
329        if ((err = i2c_attach_client(client)))
330                goto exit_free;
331
332        /* Register a new directory entry in /proc */
333        err = i2c_register_entry(client, "f71805f",
334                                 f71805f_dir_table_template, THIS_MODULE);
335        if (err < 0)
336                goto exit_detach;
337        data->sysctl_id = err;
338
339        /* Initialize the F71805F chip */
340        f71805f_init_client(client);
341        return 0;
342
343exit_detach:
344        i2c_detach_client(client);
345exit_free:
346        kfree(data);
347exit_release:
348        release_region(address, REGION_LENGTH);
349exit:
350        return err;
351}
352
353static int f71805f_attach_adapter(struct i2c_adapter *adapter)
354{
355        return i2c_detect(adapter, &addr_data, f71805f_detect);
356}
357
358static int f71805f_detach_client(struct i2c_client *client)
359{
360        int err;
361        struct f71805f_data *data = client->data;
362
363        i2c_deregister_entry(data->sysctl_id);
364        if ((err = i2c_detach_client(client))) {
365                printk(KERN_ERR "%s: Client deregistration failed, "
366                       "client not detached\n", DRVNAME);
367                return err;
368        }
369
370        release_region(client->addr, REGION_LENGTH);
371        kfree(client->data);
372
373        return 0;
374}
375
376static void f71805f_update_client(struct i2c_client *client)
377{
378        struct f71805f_data *data = client->data;
379        int nr;
380
381        down(&data->update_lock);
382
383        /* Limit registers cache is refreshed after 60 seconds */
384        if ((jiffies - data->last_limits > 60 * HZ)
385         || (jiffies < data->last_limits)
386         || !data->valid) {
387                for (nr = 0; nr < 9; nr++) {
388                        data->in_high[nr] = f71805f_read8(client,
389                                            F71805F_REG_IN_HIGH(nr));
390                        data->in_low[nr] = f71805f_read8(client,
391                                           F71805F_REG_IN_LOW(nr));
392                }
393                for (nr = 0; nr < 3; nr++) {
394                        if (data->fan_enabled & (1 << nr))
395                                data->fan_low[nr] = f71805f_read16(client,
396                                                    F71805F_REG_FAN_LOW(nr));
397                }
398                for (nr = 0; nr < 3; nr++) {
399                        data->temp_high[nr] = f71805f_read8(client,
400                                              F71805F_REG_TEMP_HIGH(nr));
401                        data->temp_hyst[nr] = f71805f_read8(client,
402                                              F71805F_REG_TEMP_HYST(nr));
403                }
404                data->temp_mode = f71805f_read8(client, F71805F_REG_TEMP_MODE);
405
406                data->last_limits = jiffies;
407        }
408
409        /* Measurement registers cache is refreshed after 1 second */
410        if ((jiffies - data->last_updated > HZ)
411         || (jiffies < data->last_updated)
412         || !data->valid) {
413                for (nr = 0; nr < 9; nr++) {
414                        data->in[nr] = f71805f_read8(client,
415                                       F71805F_REG_IN(nr));
416                }
417                for (nr = 0; nr < 3; nr++) {
418                        if (data->fan_enabled & (1 << nr))
419                                data->fan[nr] = f71805f_read16(client,
420                                                F71805F_REG_FAN(nr));
421                }
422                for (nr = 0; nr < 3; nr++) {
423                        data->temp[nr] = f71805f_read8(client,
424                                         F71805F_REG_TEMP(nr));
425                }
426                for (nr = 0; nr < 3; nr++) {
427                        data->alarms[nr] = f71805f_read8(client,
428                                           F71805F_REG_STATUS(nr));
429                }
430
431                data->last_updated = jiffies;
432                data->valid = 1;
433        }
434
435        up(&data->update_lock);
436}
437
438/* -- SENSORS SYSCTL START -- */
439#define F71805F_SYSCTL_IN0              1000
440#define F71805F_SYSCTL_IN1              1001
441#define F71805F_SYSCTL_IN2              1002
442#define F71805F_SYSCTL_IN3              1003
443#define F71805F_SYSCTL_IN4              1004
444#define F71805F_SYSCTL_IN5              1005
445#define F71805F_SYSCTL_IN6              1006
446#define F71805F_SYSCTL_IN7              1007
447#define F71805F_SYSCTL_IN8              1008
448#define F71805F_SYSCTL_FAN1             1101
449#define F71805F_SYSCTL_FAN2             1102
450#define F71805F_SYSCTL_FAN3             1103
451#define F71805F_SYSCTL_TEMP1            1201
452#define F71805F_SYSCTL_TEMP2            1202
453#define F71805F_SYSCTL_TEMP3            1203
454#define F71805F_SYSCTL_SENSOR1          1211
455#define F71805F_SYSCTL_SENSOR2          1212
456#define F71805F_SYSCTL_SENSOR3          1213
457#define F71805F_SYSCTL_ALARMS_IN        1090
458#define F71805F_SYSCTL_ALARMS_FAN       1190
459#define F71805F_SYSCTL_ALARMS_TEMP      1290
460/* -- SENSORS SYSCTL END -- */
461
462static void f71805f_in(struct i2c_client *client, int operation,
463                       int ctl_name, int *nrels_mag, long *results)
464{
465        struct f71805f_data *data = client->data;
466        int nr = ctl_name - F71805F_SYSCTL_IN0;
467
468        if (operation == SENSORS_PROC_REAL_INFO)
469                *nrels_mag = 3;
470        else if (operation == SENSORS_PROC_REAL_READ) {
471                f71805f_update_client(client);
472                results[0] = in_from_reg(data->in_low[nr]);
473                results[1] = in_from_reg(data->in_high[nr]);
474                results[2] = in_from_reg(data->in[nr]);
475                *nrels_mag = 3;
476        } else if (operation == SENSORS_PROC_REAL_WRITE) {
477                if (*nrels_mag < 1)
478                        return;
479
480                down(&data->update_lock);
481                data->in_low[nr] = in_to_reg(results[0]);
482                f71805f_write8(client, F71805F_REG_IN_LOW(nr),
483                               data->in_low[nr]);
484
485                if (*nrels_mag >= 2) {
486                        data->in_high[nr] = in_to_reg(results[1]);
487                        f71805f_write8(client, F71805F_REG_IN_HIGH(nr),
488                                       data->in_high[nr]);
489                }
490                up(&data->update_lock);
491        }
492}
493
494static void f71805f_in0(struct i2c_client *client, int operation,
495                        int ctl_name, int *nrels_mag, long *results)
496{
497        struct f71805f_data *data = client->data;
498
499        if (operation == SENSORS_PROC_REAL_INFO)
500                *nrels_mag = 3;
501        else if (operation == SENSORS_PROC_REAL_READ) {
502                f71805f_update_client(client);
503                results[0] = in0_from_reg(data->in_low[0]);
504                results[1] = in0_from_reg(data->in_high[0]);
505                results[2] = in0_from_reg(data->in[0]);
506                *nrels_mag = 3;
507        } else if (operation == SENSORS_PROC_REAL_WRITE) {
508                if (*nrels_mag < 1)
509                        return;
510
511                down(&data->update_lock);
512                data->in_low[0] = in0_to_reg(results[0]);
513                f71805f_write8(client, F71805F_REG_IN_LOW(0),
514                               data->in_low[0]);
515
516                if (*nrels_mag >= 2) {
517                        data->in_high[0] = in0_to_reg(results[1]);
518                        f71805f_write8(client, F71805F_REG_IN_HIGH(0),
519                                       data->in_high[0]);
520                }
521                up(&data->update_lock);
522        }
523}
524
525static void f71805f_fan(struct i2c_client *client, int operation,
526                        int ctl_name, int *nrels_mag, long *results)
527{
528        struct f71805f_data *data = client->data;
529        int nr = ctl_name - F71805F_SYSCTL_FAN1;
530
531        if (operation == SENSORS_PROC_REAL_INFO)
532                *nrels_mag = 0;
533        else if (operation == SENSORS_PROC_REAL_READ) {
534                f71805f_update_client(client);
535                results[0] = fan_from_reg(data->fan_low[nr]);
536                results[1] = fan_from_reg(data->fan[nr]);
537                *nrels_mag = 2;
538        } else if (operation == SENSORS_PROC_REAL_WRITE) {
539                if (*nrels_mag < 1)
540                        return;
541
542                down(&data->update_lock);
543                data->fan_low[nr] = fan_to_reg(results[0]);
544                f71805f_write16(client, F71805F_REG_FAN_LOW(nr),
545                                data->fan_low[nr]);
546                up(&data->update_lock);
547        }
548}
549
550static void f71805f_temp(struct i2c_client *client, int operation,
551                         int ctl_name, int *nrels_mag, long *results)
552{
553        struct f71805f_data *data = client->data;
554        int nr = ctl_name - F71805F_SYSCTL_TEMP1;
555
556        if (operation == SENSORS_PROC_REAL_INFO)
557                *nrels_mag = 0;
558        else if (operation == SENSORS_PROC_REAL_READ) {
559                f71805f_update_client(client);
560                results[0] = data->temp_high[nr];
561                results[1] = data->temp_hyst[nr];
562                results[2] = data->temp[nr];
563                *nrels_mag = 3;
564        } else if (operation == SENSORS_PROC_REAL_WRITE) {
565                if (*nrels_mag < 1)
566                        return;
567
568                down(&data->update_lock);
569                data->temp_high[nr] = temp_to_reg(results[0]);
570                f71805f_write8(client, F71805F_REG_TEMP_HIGH(nr),
571                               data->temp_high[nr]);
572
573                if (*nrels_mag >= 2) {
574                        data->temp_hyst[nr] = temp_to_reg(results[1]);
575                        f71805f_write8(client, F71805F_REG_TEMP_HYST(nr),
576                                       data->temp_hyst[nr]);
577                }
578                up(&data->update_lock);
579        }
580}
581
582static void f71805f_sensor(struct i2c_client *client, int operation,
583                           int ctl_name, int *nrels_mag, long *results)
584{
585        struct f71805f_data *data = client->data;
586
587        if (operation == SENSORS_PROC_REAL_INFO)
588                *nrels_mag = 0;
589        else if (operation == SENSORS_PROC_REAL_READ) {
590                int nr = ctl_name - F71805F_SYSCTL_SENSOR1;
591
592                f71805f_update_client(client);
593                results[0] = (data->temp_mode & (1 << nr)) ? 3 : 4;
594                *nrels_mag = 1;
595        }
596}
597
598static void f71805f_alarms_in(struct i2c_client *client, int operation,
599                              int ctl_name, int *nrels_mag, long *results)
600{
601        struct f71805f_data *data = client->data;
602
603        if (operation == SENSORS_PROC_REAL_INFO)
604                *nrels_mag = 0;
605        else if (operation == SENSORS_PROC_REAL_READ) {
606                f71805f_update_client(client);
607                results[0] = data->alarms[0]
608                           | ((data->alarms[1] & 0x01) << 8);
609                *nrels_mag = 1;
610        }
611}
612
613static void f71805f_alarms_fan(struct i2c_client *client, int operation,
614                               int ctl_name, int *nrels_mag, long *results)
615{
616        struct f71805f_data *data = client->data;
617
618        if (operation == SENSORS_PROC_REAL_INFO)
619                *nrels_mag = 0;
620        else if (operation == SENSORS_PROC_REAL_READ) {
621                f71805f_update_client(client);
622                results[0] = data->alarms[2] & 0x07;
623                *nrels_mag = 1;
624        }
625}
626
627static void f71805f_alarms_temp(struct i2c_client *client, int operation,
628                                int ctl_name, int *nrels_mag, long *results)
629{
630        struct f71805f_data *data = client->data;
631
632        if (operation == SENSORS_PROC_REAL_INFO)
633                *nrels_mag = 0;
634        else if (operation == SENSORS_PROC_REAL_READ) {
635                f71805f_update_client(client);
636                results[0] = (data->alarms[1] >> 3) & 0x07;
637                *nrels_mag = 1;
638        }
639}
640
641static ctl_table f71805f_dir_table_template[] = {
642        { F71805F_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL,
643          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in0 },
644        { F71805F_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL,
645          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
646        { F71805F_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL,
647          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
648        { F71805F_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL,
649          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
650        { F71805F_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL,
651          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
652        { F71805F_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL,
653          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
654        { F71805F_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL,
655          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
656        { F71805F_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL,
657          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
658        { F71805F_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL,
659          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in },
660        { F71805F_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
661          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan },
662        { F71805F_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
663          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan },
664        { F71805F_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
665          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan },
666        { F71805F_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL,
667          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp },
668        { F71805F_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
669          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp },
670        { F71805F_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
671          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp },
672        { F71805F_SYSCTL_SENSOR1, "sensor1", NULL, 0, 0444, NULL,
673          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor },
674        { F71805F_SYSCTL_SENSOR2, "sensor2", NULL, 0, 0444, NULL,
675          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor },
676        { F71805F_SYSCTL_SENSOR3, "sensor3", NULL, 0, 0444, NULL,
677          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor },
678        { F71805F_SYSCTL_ALARMS_IN, "alarms_in", NULL, 0, 0444, NULL,
679          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_in },
680        { F71805F_SYSCTL_ALARMS_FAN, "alarms_fan", NULL, 0, 0444, NULL,
681          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_fan },
682        { F71805F_SYSCTL_ALARMS_TEMP, "alarms_temp", NULL, 0, 0444, NULL,
683          &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_temp },
684        { 0 }
685};
686
687static struct i2c_driver f71805f_driver = {
688        .name           = "F71805F sensor driver",
689        .flags          = I2C_DF_NOTIFY,
690        .attach_adapter = f71805f_attach_adapter,
691        .detach_client  = f71805f_detach_client,
692};
693
694static int __init f71805f_find(int sioaddr, unsigned int *address)
695{
696        int err = -ENODEV;
697        u16 devid;
698
699        REG = sioaddr;
700        VAL = sioaddr + 1;
701        superio_enter();
702
703        devid = superio_inw(SIO_REG_DEVID);
704        if (devid != SIO_F71805F_ID)
705                goto exit;
706
707        superio_select(F71805F_LD_HWM);
708        if (!(superio_inb(SIO_REG_ENABLE) & 0x01)) {
709                printk(KERN_WARNING "%s: Device not activated, skipping\n",
710                       DRVNAME);
711                goto exit;
712        }
713
714        *address = superio_inw(SIO_REG_ADDR);
715        if (*address == 0) {
716                printk(KERN_WARNING "%s: Base address not set, skipping\n",
717                       DRVNAME);
718                goto exit;
719        }
720
721        err = 0;
722        printk(KERN_INFO "%s: Found F71805F chip at %#x, revision %u\n",
723               DRVNAME, *address, superio_inb(SIO_REG_DEVREV));
724
725exit:
726        superio_exit();
727        return err;
728}
729
730static int __init f71805f_init(void)
731{
732        printk("%s: Driver version %s (%s)\n", DRVNAME, LM_VERSION, LM_DATE);
733
734        if (f71805f_find(0x2e, &normal_isa[0])
735         && f71805f_find(0x4e, &normal_isa[0]))
736                return -ENODEV;
737
738        return i2c_add_driver(&f71805f_driver);
739}
740
741static void __exit f71805f_exit(void)
742{
743        i2c_del_driver(&f71805f_driver);
744}
745
746MODULE_AUTHOR("Jean Delvare <khali@linux-fr>");
747MODULE_LICENSE("GPL");
748MODULE_DESCRIPTION("F71805F hardware monitoring driver");
749
750module_init(f71805f_init);
751module_exit(f71805f_exit);
Note: See TracBrowser for help on using the browser.