diff options
| -rw-r--r-- | drivers/hwmon/pc87427.c | 67 |
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 | ||
| 62 | struct 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 | ||
| 394 | static void __devinit pc87427_init_device(struct device *dev) | 403 | static 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 | ||
| 518 | static int __init pc87427_device_add(unsigned short address) | 533 | static 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 | ||
| 561 | static int __init pc87427_find(int sioaddr, unsigned short *address) | 584 | static 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 | |||
| 602 | exit: | 650 | exit: |
| 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 | ||
