OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [hwmon/] [pc87427.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  pc87427.c - hardware monitoring driver for the
3
 *              National Semiconductor PC87427 Super-I/O chip
4
 *  Copyright (C) 2006 Jean Delvare <khali@linux-fr.org>
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License version 2 as
8
 *  published by the Free Software Foundation.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  Supports the following chips:
16
 *
17
 *  Chip        #vin    #fan    #pwm    #temp   devid
18
 *  PC87427     -       8       -       -       0xF2
19
 *
20
 *  This driver assumes that no more than one chip is present.
21
 *  Only fan inputs are supported so far, although the chip can do much more.
22
 */
23
 
24
#include <linux/module.h>
25
#include <linux/init.h>
26
#include <linux/slab.h>
27
#include <linux/jiffies.h>
28
#include <linux/platform_device.h>
29
#include <linux/hwmon.h>
30
#include <linux/hwmon-sysfs.h>
31
#include <linux/err.h>
32
#include <linux/mutex.h>
33
#include <linux/sysfs.h>
34
#include <linux/ioport.h>
35
#include <asm/io.h>
36
 
37
static struct platform_device *pdev;
38
 
39
#define DRVNAME "pc87427"
40
 
41
/* The lock mutex protects both the I/O accesses (needed because the
42
   device is using banked registers) and the register cache (needed to keep
43
   the data in the registers and the cache in sync at any time). */
44
struct pc87427_data {
45
        struct device *hwmon_dev;
46
        struct mutex lock;
47
        int address[2];
48
        const char *name;
49
 
50
        unsigned long last_updated;     /* in jiffies */
51
        u8 fan_enabled;                 /* bit vector */
52
        u16 fan[8];                     /* register values */
53
        u16 fan_min[8];                 /* register values */
54
        u8 fan_status[8];               /* register values */
55
};
56
 
57
/*
58
 * Super-I/O registers and operations
59
 */
60
 
61
#define SIOREG_LDSEL    0x07    /* Logical device select */
62
#define SIOREG_DEVID    0x20    /* Device ID */
63
#define SIOREG_ACT      0x30    /* Device activation */
64
#define SIOREG_MAP      0x50    /* I/O or memory mapping */
65
#define SIOREG_IOBASE   0x60    /* I/O base address */
66
 
67
static const u8 logdev[2] = { 0x09, 0x14 };
68
static const char *logdev_str[2] = { DRVNAME " FMC", DRVNAME " HMC" };
69
#define LD_FAN          0
70
#define LD_IN           1
71
#define LD_TEMP         1
72
 
73
static inline void superio_outb(int sioaddr, int reg, int val)
74
{
75
        outb(reg, sioaddr);
76
        outb(val, sioaddr + 1);
77
}
78
 
79
static inline int superio_inb(int sioaddr, int reg)
80
{
81
        outb(reg, sioaddr);
82
        return inb(sioaddr + 1);
83
}
84
 
85
static inline void superio_exit(int sioaddr)
86
{
87
        outb(0x02, sioaddr);
88
        outb(0x02, sioaddr + 1);
89
}
90
 
91
/*
92
 * Logical devices
93
 */
94
 
95
#define REGION_LENGTH           32
96
#define PC87427_REG_BANK        0x0f
97
#define BANK_FM(nr)             (nr)
98
#define BANK_FT(nr)             (0x08 + (nr))
99
#define BANK_FC(nr)             (0x10 + (nr) * 2)
100
 
101
/*
102
 * I/O access functions
103
 */
104
 
105
/* ldi is the logical device index */
106
static inline int pc87427_read8(struct pc87427_data *data, u8 ldi, u8 reg)
107
{
108
        return inb(data->address[ldi] + reg);
109
}
110
 
111
/* Must be called with data->lock held, except during init */
112
static inline int pc87427_read8_bank(struct pc87427_data *data, u8 ldi,
113
                                     u8 bank, u8 reg)
114
{
115
        outb(bank, data->address[ldi] + PC87427_REG_BANK);
116
        return inb(data->address[ldi] + reg);
117
}
118
 
119
/* Must be called with data->lock held, except during init */
120
static inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi,
121
                                       u8 bank, u8 reg, u8 value)
122
{
123
        outb(bank, data->address[ldi] + PC87427_REG_BANK);
124
        outb(value, data->address[ldi] + reg);
125
}
126
 
127
/*
128
 * Fan registers and conversions
129
 */
130
 
131
/* fan data registers are 16-bit wide */
132
#define PC87427_REG_FAN                 0x12
133
#define PC87427_REG_FAN_MIN             0x14
134
#define PC87427_REG_FAN_STATUS          0x10
135
 
136
#define FAN_STATUS_STALL                (1 << 3)
137
#define FAN_STATUS_LOSPD                (1 << 1)
138
#define FAN_STATUS_MONEN                (1 << 0)
139
 
140
/* Dedicated function to read all registers related to a given fan input.
141
   This saves us quite a few locks and bank selections.
142
   Must be called with data->lock held.
143
   nr is from 0 to 7 */
144
static void pc87427_readall_fan(struct pc87427_data *data, u8 nr)
145
{
146
        int iobase = data->address[LD_FAN];
147
 
148
        outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
149
        data->fan[nr] = inw(iobase + PC87427_REG_FAN);
150
        data->fan_min[nr] = inw(iobase + PC87427_REG_FAN_MIN);
151
        data->fan_status[nr] = inb(iobase + PC87427_REG_FAN_STATUS);
152
        /* Clear fan alarm bits */
153
        outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS);
154
}
155
 
156
/* The 2 LSB of fan speed registers are used for something different.
157
   The actual 2 LSB of the measurements are not available. */
158
static inline unsigned long fan_from_reg(u16 reg)
159
{
160
        reg &= 0xfffc;
161
        if (reg == 0x0000 || reg == 0xfffc)
162
                return 0;
163
        return 5400000UL / reg;
164
}
165
 
166
/* The 2 LSB of the fan speed limit registers are not significant. */
167
static inline u16 fan_to_reg(unsigned long val)
168
{
169
        if (val < 83UL)
170
                return 0xffff;
171
        if (val >= 1350000UL)
172
                return 0x0004;
173
        return ((1350000UL + val / 2) / val) << 2;
174
}
175
 
176
/*
177
 * Data interface
178
 */
179
 
180
static struct pc87427_data *pc87427_update_device(struct device *dev)
181
{
182
        struct pc87427_data *data = dev_get_drvdata(dev);
183
        int i;
184
 
185
        mutex_lock(&data->lock);
186
        if (!time_after(jiffies, data->last_updated + HZ)
187
         && data->last_updated)
188
                goto done;
189
 
190
        /* Fans */
191
        for (i = 0; i < 8; i++) {
192
                if (!(data->fan_enabled & (1 << i)))
193
                        continue;
194
                pc87427_readall_fan(data, i);
195
        }
196
        data->last_updated = jiffies;
197
 
198
done:
199
        mutex_unlock(&data->lock);
200
        return data;
201
}
202
 
203
static ssize_t show_fan_input(struct device *dev, struct device_attribute
204
                              *devattr, char *buf)
205
{
206
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
207
        struct pc87427_data *data = pc87427_update_device(dev);
208
        int nr = attr->index;
209
 
210
        return sprintf(buf, "%lu\n", fan_from_reg(data->fan[nr]));
211
}
212
 
213
static ssize_t show_fan_min(struct device *dev, struct device_attribute
214
                            *devattr, char *buf)
215
{
216
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
217
        struct pc87427_data *data = pc87427_update_device(dev);
218
        int nr = attr->index;
219
 
220
        return sprintf(buf, "%lu\n", fan_from_reg(data->fan_min[nr]));
221
}
222
 
223
static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
224
                              *devattr, char *buf)
225
{
226
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
227
        struct pc87427_data *data = pc87427_update_device(dev);
228
        int nr = attr->index;
229
 
230
        return sprintf(buf, "%d\n", !!(data->fan_status[nr]
231
                                       & FAN_STATUS_LOSPD));
232
}
233
 
234
static ssize_t show_fan_fault(struct device *dev, struct device_attribute
235
                              *devattr, char *buf)
236
{
237
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
238
        struct pc87427_data *data = pc87427_update_device(dev);
239
        int nr = attr->index;
240
 
241
        return sprintf(buf, "%d\n", !!(data->fan_status[nr]
242
                                       & FAN_STATUS_STALL));
243
}
244
 
245
static ssize_t set_fan_min(struct device *dev, struct device_attribute
246
                           *devattr, const char *buf, size_t count)
247
{
248
        struct pc87427_data *data = dev_get_drvdata(dev);
249
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
250
        int nr = attr->index;
251
        unsigned long val = simple_strtoul(buf, NULL, 10);
252
        int iobase = data->address[LD_FAN];
253
 
254
        mutex_lock(&data->lock);
255
        outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
256
        /* The low speed limit registers are read-only while monitoring
257
           is enabled, so we have to disable monitoring, then change the
258
           limit, and finally enable monitoring again. */
259
        outb(0, iobase + PC87427_REG_FAN_STATUS);
260
        data->fan_min[nr] = fan_to_reg(val);
261
        outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN);
262
        outb(FAN_STATUS_MONEN, iobase + PC87427_REG_FAN_STATUS);
263
        mutex_unlock(&data->lock);
264
 
265
        return count;
266
}
267
 
268
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
269
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
270
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
271
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
272
static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan_input, NULL, 4);
273
static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan_input, NULL, 5);
274
static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan_input, NULL, 6);
275
static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan_input, NULL, 7);
276
 
277
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
278
                          show_fan_min, set_fan_min, 0);
279
static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
280
                          show_fan_min, set_fan_min, 1);
281
static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
282
                          show_fan_min, set_fan_min, 2);
283
static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
284
                          show_fan_min, set_fan_min, 3);
285
static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
286
                          show_fan_min, set_fan_min, 4);
287
static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
288
                          show_fan_min, set_fan_min, 5);
289
static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
290
                          show_fan_min, set_fan_min, 6);
291
static SENSOR_DEVICE_ATTR(fan8_min, S_IWUSR | S_IRUGO,
292
                          show_fan_min, set_fan_min, 7);
293
 
294
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0);
295
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1);
296
static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2);
297
static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3);
298
static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_fan_alarm, NULL, 4);
299
static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_fan_alarm, NULL, 5);
300
static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_fan_alarm, NULL, 6);
301
static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_fan_alarm, NULL, 7);
302
 
303
static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0);
304
static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1);
305
static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2);
306
static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3);
307
static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, show_fan_fault, NULL, 4);
308
static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, show_fan_fault, NULL, 5);
309
static SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, show_fan_fault, NULL, 6);
310
static SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, show_fan_fault, NULL, 7);
311
 
312
static struct attribute *pc87427_attributes_fan[8][5] = {
313
        {
314
                &sensor_dev_attr_fan1_input.dev_attr.attr,
315
                &sensor_dev_attr_fan1_min.dev_attr.attr,
316
                &sensor_dev_attr_fan1_alarm.dev_attr.attr,
317
                &sensor_dev_attr_fan1_fault.dev_attr.attr,
318
                NULL
319
        }, {
320
                &sensor_dev_attr_fan2_input.dev_attr.attr,
321
                &sensor_dev_attr_fan2_min.dev_attr.attr,
322
                &sensor_dev_attr_fan2_alarm.dev_attr.attr,
323
                &sensor_dev_attr_fan2_fault.dev_attr.attr,
324
                NULL
325
        }, {
326
                &sensor_dev_attr_fan3_input.dev_attr.attr,
327
                &sensor_dev_attr_fan3_min.dev_attr.attr,
328
                &sensor_dev_attr_fan3_alarm.dev_attr.attr,
329
                &sensor_dev_attr_fan3_fault.dev_attr.attr,
330
                NULL
331
        }, {
332
                &sensor_dev_attr_fan4_input.dev_attr.attr,
333
                &sensor_dev_attr_fan4_min.dev_attr.attr,
334
                &sensor_dev_attr_fan4_alarm.dev_attr.attr,
335
                &sensor_dev_attr_fan4_fault.dev_attr.attr,
336
                NULL
337
        }, {
338
                &sensor_dev_attr_fan5_input.dev_attr.attr,
339
                &sensor_dev_attr_fan5_min.dev_attr.attr,
340
                &sensor_dev_attr_fan5_alarm.dev_attr.attr,
341
                &sensor_dev_attr_fan5_fault.dev_attr.attr,
342
                NULL
343
        }, {
344
                &sensor_dev_attr_fan6_input.dev_attr.attr,
345
                &sensor_dev_attr_fan6_min.dev_attr.attr,
346
                &sensor_dev_attr_fan6_alarm.dev_attr.attr,
347
                &sensor_dev_attr_fan6_fault.dev_attr.attr,
348
                NULL
349
        }, {
350
                &sensor_dev_attr_fan7_input.dev_attr.attr,
351
                &sensor_dev_attr_fan7_min.dev_attr.attr,
352
                &sensor_dev_attr_fan7_alarm.dev_attr.attr,
353
                &sensor_dev_attr_fan7_fault.dev_attr.attr,
354
                NULL
355
        }, {
356
                &sensor_dev_attr_fan8_input.dev_attr.attr,
357
                &sensor_dev_attr_fan8_min.dev_attr.attr,
358
                &sensor_dev_attr_fan8_alarm.dev_attr.attr,
359
                &sensor_dev_attr_fan8_fault.dev_attr.attr,
360
                NULL
361
        }
362
};
363
 
364
static const struct attribute_group pc87427_group_fan[8] = {
365
        { .attrs = pc87427_attributes_fan[0] },
366
        { .attrs = pc87427_attributes_fan[1] },
367
        { .attrs = pc87427_attributes_fan[2] },
368
        { .attrs = pc87427_attributes_fan[3] },
369
        { .attrs = pc87427_attributes_fan[4] },
370
        { .attrs = pc87427_attributes_fan[5] },
371
        { .attrs = pc87427_attributes_fan[6] },
372
        { .attrs = pc87427_attributes_fan[7] },
373
};
374
 
375
static ssize_t show_name(struct device *dev, struct device_attribute
376
                         *devattr, char *buf)
377
{
378
        struct pc87427_data *data = dev_get_drvdata(dev);
379
 
380
        return sprintf(buf, "%s\n", data->name);
381
}
382
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
383
 
384
 
385
/*
386
 * Device detection, attach and detach
387
 */
388
 
389
static void __devinit pc87427_init_device(struct device *dev)
390
{
391
        struct pc87427_data *data = dev_get_drvdata(dev);
392
        int i;
393
        u8 reg;
394
 
395
        /* The FMC module should be ready */
396
        reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK);
397
        if (!(reg & 0x80))
398
                dev_warn(dev, "FMC module not ready!\n");
399
 
400
        /* Check which fans are enabled */
401
        for (i = 0; i < 8; i++) {
402
                reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i),
403
                                         PC87427_REG_FAN_STATUS);
404
                if (reg & FAN_STATUS_MONEN)
405
                        data->fan_enabled |= (1 << i);
406
        }
407
 
408
        if (!data->fan_enabled) {
409
                dev_dbg(dev, "Enabling all fan inputs\n");
410
                for (i = 0; i < 8; i++)
411
                        pc87427_write8_bank(data, LD_FAN, BANK_FM(i),
412
                                            PC87427_REG_FAN_STATUS,
413
                                            FAN_STATUS_MONEN);
414
                data->fan_enabled = 0xff;
415
        }
416
}
417
 
418
static int __devinit pc87427_probe(struct platform_device *pdev)
419
{
420
        struct pc87427_data *data;
421
        struct resource *res;
422
        int i, err;
423
 
424
        if (!(data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL))) {
425
                err = -ENOMEM;
426
                printk(KERN_ERR DRVNAME ": Out of memory\n");
427
                goto exit;
428
        }
429
 
430
        /* This will need to be revisited when we add support for
431
           temperature and voltage monitoring. */
432
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
433
        if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
434
                err = -EBUSY;
435
                dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
436
                        (unsigned long)res->start, (unsigned long)res->end);
437
                goto exit_kfree;
438
        }
439
        data->address[0] = res->start;
440
 
441
        mutex_init(&data->lock);
442
        data->name = "pc87427";
443
        platform_set_drvdata(pdev, data);
444
        pc87427_init_device(&pdev->dev);
445
 
446
        /* Register sysfs hooks */
447
        if ((err = device_create_file(&pdev->dev, &dev_attr_name)))
448
                goto exit_release_region;
449
        for (i = 0; i < 8; i++) {
450
                if (!(data->fan_enabled & (1 << i)))
451
                        continue;
452
                if ((err = sysfs_create_group(&pdev->dev.kobj,
453
                                              &pc87427_group_fan[i])))
454
                        goto exit_remove_files;
455
        }
456
 
457
        data->hwmon_dev = hwmon_device_register(&pdev->dev);
458
        if (IS_ERR(data->hwmon_dev)) {
459
                err = PTR_ERR(data->hwmon_dev);
460
                dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
461
                goto exit_remove_files;
462
        }
463
 
464
        return 0;
465
 
466
exit_remove_files:
467
        for (i = 0; i < 8; i++) {
468
                if (!(data->fan_enabled & (1 << i)))
469
                        continue;
470
                sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
471
        }
472
exit_release_region:
473
        release_region(res->start, res->end - res->start + 1);
474
exit_kfree:
475
        platform_set_drvdata(pdev, NULL);
476
        kfree(data);
477
exit:
478
        return err;
479
}
480
 
481
static int __devexit pc87427_remove(struct platform_device *pdev)
482
{
483
        struct pc87427_data *data = platform_get_drvdata(pdev);
484
        struct resource *res;
485
        int i;
486
 
487
        hwmon_device_unregister(data->hwmon_dev);
488
        device_remove_file(&pdev->dev, &dev_attr_name);
489
        for (i = 0; i < 8; i++) {
490
                if (!(data->fan_enabled & (1 << i)))
491
                        continue;
492
                sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
493
        }
494
        platform_set_drvdata(pdev, NULL);
495
        kfree(data);
496
 
497
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
498
        release_region(res->start, res->end - res->start + 1);
499
 
500
        return 0;
501
}
502
 
503
 
504
static struct platform_driver pc87427_driver = {
505
        .driver = {
506
                .owner  = THIS_MODULE,
507
                .name   = DRVNAME,
508
        },
509
        .probe          = pc87427_probe,
510
        .remove         = __devexit_p(pc87427_remove),
511
};
512
 
513
static int __init pc87427_device_add(unsigned short address)
514
{
515
        struct resource res = {
516
                .start  = address,
517
                .end    = address + REGION_LENGTH - 1,
518
                .name   = logdev_str[0],
519
                .flags  = IORESOURCE_IO,
520
        };
521
        int err;
522
 
523
        pdev = platform_device_alloc(DRVNAME, address);
524
        if (!pdev) {
525
                err = -ENOMEM;
526
                printk(KERN_ERR DRVNAME ": Device allocation failed\n");
527
                goto exit;
528
        }
529
 
530
        err = platform_device_add_resources(pdev, &res, 1);
531
        if (err) {
532
                printk(KERN_ERR DRVNAME ": Device resource addition failed "
533
                       "(%d)\n", err);
534
                goto exit_device_put;
535
        }
536
 
537
        err = platform_device_add(pdev);
538
        if (err) {
539
                printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
540
                       err);
541
                goto exit_device_put;
542
        }
543
 
544
        return 0;
545
 
546
exit_device_put:
547
        platform_device_put(pdev);
548
exit:
549
        return err;
550
}
551
 
552
static int __init pc87427_find(int sioaddr, unsigned short *address)
553
{
554
        u16 val;
555
        int i, err = 0;
556
 
557
        /* Identify device */
558
        val = superio_inb(sioaddr, SIOREG_DEVID);
559
        if (val != 0xf2) {      /* PC87427 */
560
                err = -ENODEV;
561
                goto exit;
562
        }
563
 
564
        for (i = 0; i < 2; i++) {
565
                address[i] = 0;
566
                /* Select logical device */
567
                superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]);
568
 
569
                val = superio_inb(sioaddr, SIOREG_ACT);
570
                if (!(val & 0x01)) {
571
                        printk(KERN_INFO DRVNAME ": Logical device 0x%02x "
572
                               "not activated\n", logdev[i]);
573
                        continue;
574
                }
575
 
576
                val = superio_inb(sioaddr, SIOREG_MAP);
577
                if (val & 0x01) {
578
                        printk(KERN_WARNING DRVNAME ": Logical device 0x%02x "
579
                               "is memory-mapped, can't use\n", logdev[i]);
580
                        continue;
581
                }
582
 
583
                val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
584
                    | superio_inb(sioaddr, SIOREG_IOBASE + 1);
585
                if (!val) {
586
                        printk(KERN_INFO DRVNAME ": I/O base address not set "
587
                               "for logical device 0x%02x\n", logdev[i]);
588
                        continue;
589
                }
590
                address[i] = val;
591
        }
592
 
593
exit:
594
        superio_exit(sioaddr);
595
        return err;
596
}
597
 
598
static int __init pc87427_init(void)
599
{
600
        int err;
601
        unsigned short address[2];
602
 
603
        if (pc87427_find(0x2e, address)
604
         && pc87427_find(0x4e, address))
605
                return -ENODEV;
606
 
607
        /* For now the driver only handles fans so we only care about the
608
           first address. */
609
        if (!address[0])
610
                return -ENODEV;
611
 
612
        err = platform_driver_register(&pc87427_driver);
613
        if (err)
614
                goto exit;
615
 
616
        /* Sets global pdev as a side effect */
617
        err = pc87427_device_add(address[0]);
618
        if (err)
619
                goto exit_driver;
620
 
621
        return 0;
622
 
623
exit_driver:
624
        platform_driver_unregister(&pc87427_driver);
625
exit:
626
        return err;
627
}
628
 
629
static void __exit pc87427_exit(void)
630
{
631
        platform_device_unregister(pdev);
632
        platform_driver_unregister(&pc87427_driver);
633
}
634
 
635
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
636
MODULE_DESCRIPTION("PC87427 hardware monitoring driver");
637
MODULE_LICENSE("GPL");
638
 
639
module_init(pc87427_init);
640
module_exit(pc87427_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.