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