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