aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hwmon/pc87427.c67
1 files changed, 58 insertions, 9 deletions
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 3170b26d2443..a4b1b8b828c5 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * pc87427.c - hardware monitoring driver for the 2 * pc87427.c - hardware monitoring driver for the
3 * National Semiconductor PC87427 Super-I/O chip 3 * National Semiconductor PC87427 Super-I/O chip
4 * Copyright (C) 2006 Jean Delvare <khali@linux-fr.org> 4 * Copyright (C) 2006, 2008 Jean Delvare <khali@linux-fr.org>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 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 7 * it under the terms of the GNU General Public License version 2 as
@@ -59,12 +59,21 @@ struct pc87427_data {
59 u8 fan_status[8]; /* register values */ 59 u8 fan_status[8]; /* register values */
60}; 60};
61 61
62struct pc87427_sio_data {
63 u8 has_fanin;
64};
65
62/* 66/*
63 * Super-I/O registers and operations 67 * Super-I/O registers and operations
64 */ 68 */
65 69
66#define SIOREG_LDSEL 0x07 /* Logical device select */ 70#define SIOREG_LDSEL 0x07 /* Logical device select */
67#define SIOREG_DEVID 0x20 /* Device ID */ 71#define SIOREG_DEVID 0x20 /* Device ID */
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 */
68#define SIOREG_ACT 0x30 /* Device activation */ 77#define SIOREG_ACT 0x30 /* Device activation */
69#define SIOREG_MAP 0x50 /* I/O or memory mapping */ 78#define SIOREG_MAP 0x50 /* I/O or memory mapping */
70#define SIOREG_IOBASE 0x60 /* I/O base address */ 79#define SIOREG_IOBASE 0x60 /* I/O base address */
@@ -393,6 +402,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
393 402
394static void __devinit pc87427_init_device(struct device *dev) 403static void __devinit pc87427_init_device(struct device *dev)
395{ 404{
405 struct pc87427_sio_data *sio_data = dev->platform_data;
396 struct pc87427_data *data = dev_get_drvdata(dev); 406 struct pc87427_data *data = dev_get_drvdata(dev);
397 int i; 407 int i;
398 u8 reg; 408 u8 reg;
@@ -404,6 +414,8 @@ static void __devinit pc87427_init_device(struct device *dev)
404 414
405 /* Check which fans are enabled */ 415 /* Check which fans are enabled */
406 for (i = 0; i < 8; i++) { 416 for (i = 0; i < 8; i++) {
417 if (!(sio_data->has_fanin & (1 << i))) /* Not wired */
418 continue;
407 reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i), 419 reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i),
408 PC87427_REG_FAN_STATUS); 420 PC87427_REG_FAN_STATUS);
409 if (reg & FAN_STATUS_MONEN) 421 if (reg & FAN_STATUS_MONEN)
@@ -411,12 +423,15 @@ static void __devinit pc87427_init_device(struct device *dev)
411 } 423 }
412 424
413 if (!data->fan_enabled) { 425 if (!data->fan_enabled) {
414 dev_dbg(dev, "Enabling all fan inputs\n"); 426 dev_dbg(dev, "Enabling monitoring of all fans\n");
415 for (i = 0; i < 8; i++) 427 for (i = 0; i < 8; i++) {
428 if (!(sio_data->has_fanin & (1 << i))) /* Not wired */
429 continue;
416 pc87427_write8_bank(data, LD_FAN, BANK_FM(i), 430 pc87427_write8_bank(data, LD_FAN, BANK_FM(i),
417 PC87427_REG_FAN_STATUS, 431 PC87427_REG_FAN_STATUS,
418 FAN_STATUS_MONEN); 432 FAN_STATUS_MONEN);
419 data->fan_enabled = 0xff; 433 }
434 data->fan_enabled = sio_data->has_fanin;
420 } 435 }
421} 436}
422 437
@@ -515,7 +530,8 @@ static struct platform_driver pc87427_driver = {
515 .remove = __devexit_p(pc87427_remove), 530 .remove = __devexit_p(pc87427_remove),
516}; 531};
517 532
518static int __init pc87427_device_add(unsigned short address) 533static int __init pc87427_device_add(unsigned short address,
534 const struct pc87427_sio_data *sio_data)
519{ 535{
520 struct resource res = { 536 struct resource res = {
521 .start = address, 537 .start = address,
@@ -543,6 +559,13 @@ static int __init pc87427_device_add(unsigned short address)
543 goto exit_device_put; 559 goto exit_device_put;
544 } 560 }
545 561
562 err = platform_device_add_data(pdev, sio_data,
563 sizeof(struct pc87427_sio_data));
564 if (err) {
565 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
566 goto exit_device_put;
567 }
568
546 err = platform_device_add(pdev); 569 err = platform_device_add(pdev);
547 if (err) { 570 if (err) {
548 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", 571 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
@@ -558,9 +581,11 @@ exit:
558 return err; 581 return err;
559} 582}
560 583
561static int __init pc87427_find(int sioaddr, unsigned short *address) 584static int __init pc87427_find(int sioaddr, unsigned short *address,
585 struct pc87427_sio_data *sio_data)
562{ 586{
563 u16 val; 587 u16 val;
588 u8 cfg, cfg_b;
564 int i, err = 0; 589 int i, err = 0;
565 590
566 /* Identify device */ 591 /* Identify device */
@@ -599,6 +624,29 @@ static int __init pc87427_find(int sioaddr, unsigned short *address)
599 address[i] = val; 624 address[i] = val;
600 } 625 }
601 626
627 /* Check which fan inputs are wired */
628 sio_data->has_fanin = (1 << 2) | (1 << 3); /* FANIN2, FANIN3 */
629
630 cfg = superio_inb(sioaddr, SIOREG_CF2);
631 if (!(cfg & (1 << 3)))
632 sio_data->has_fanin |= (1 << 0); /* FANIN0 */
633 if (!(cfg & (1 << 2)))
634 sio_data->has_fanin |= (1 << 4); /* FANIN4 */
635
636 cfg = superio_inb(sioaddr, SIOREG_CFD);
637 if (!(cfg & (1 << 0)))
638 sio_data->has_fanin |= (1 << 1); /* FANIN1 */
639
640 cfg = superio_inb(sioaddr, SIOREG_CF4);
641 if (!(cfg & (1 << 0)))
642 sio_data->has_fanin |= (1 << 7); /* FANIN7 */
643 cfg_b = superio_inb(sioaddr, SIOREG_CFB);
644 if (!(cfg & (1 << 1)) && (cfg_b & (1 << 3)))
645 sio_data->has_fanin |= (1 << 5); /* FANIN5 */
646 cfg = superio_inb(sioaddr, SIOREG_CF3);
647 if ((cfg & (1 << 3)) && !(cfg_b & (1 << 5)))
648 sio_data->has_fanin |= (1 << 6); /* FANIN6 */
649
602exit: 650exit:
603 superio_exit(sioaddr); 651 superio_exit(sioaddr);
604 return err; 652 return err;
@@ -608,9 +656,10 @@ static int __init pc87427_init(void)
608{ 656{
609 int err; 657 int err;
610 unsigned short address[2]; 658 unsigned short address[2];
659 struct pc87427_sio_data sio_data;
611 660
612 if (pc87427_find(0x2e, address) 661 if (pc87427_find(0x2e, address, &sio_data)
613 && pc87427_find(0x4e, address)) 662 && pc87427_find(0x4e, address, &sio_data))
614 return -ENODEV; 663 return -ENODEV;
615 664
616 /* For now the driver only handles fans so we only care about the 665 /* For now the driver only handles fans so we only care about the
@@ -623,7 +672,7 @@ static int __init pc87427_init(void)
623 goto exit; 672 goto exit;
624 673
625 /* Sets global pdev as a side effect */ 674 /* Sets global pdev as a side effect */
626 err = pc87427_device_add(address[0]); 675 err = pc87427_device_add(address[0], &sio_data);
627 if (err) 676 if (err)
628 goto exit_driver; 677 goto exit_driver;
629 678