aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2010-08-14 15:08:56 -0400
committerJean Delvare <khali@linux-fr.org>2010-08-14 15:08:56 -0400
commit4e7d99e1acddea44be61aee0b934a7ce45d4c3f4 (patch)
tree94b7735b2217b7c0d4dfd4dacce99a6bbfefaf2a /drivers/hwmon
parentc39aedafb242601729bef48db052ebc055ce3ab4 (diff)
hwmon: (pc87427) Handle disabled fan inputs properly
Most fan input pins of the PC87427 can have alternate functions. Update the driver to check the configuration register and only support fan inputs which are really used for fan monitoring. Signed-off-by: Jean Delvare <khali@linux-fr.org> Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers/hwmon')
-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 3170b26d244..a4b1b8b828c 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