aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-i801.c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2007-03-22 14:49:01 -0400
committerJean Delvare <khali@arrakis.delvare>2007-03-22 14:49:01 -0400
commita5aaea37858fb56d624227408d1dde4cb78c9a6c (patch)
treee0470ae1e5c1e4d3114865e15c471f30bc047dea /drivers/i2c/busses/i2c-i801.c
parent58791fd81dabdd0552c63625f231d16c9060ec84 (diff)
i2c-i801: Restore the device state before leaving
Restore the original host configuration on driver unload and on suspend. In particular this returns the SMBus master in I2C mode if it was originally in I2C mode, which should help with suspend/resume if the BIOS expects to find the SMBus master in I2C mode. This fixes bug #6449 (for real this time.) http://bugzilla.kernel.org/show_bug.cgi?id=6449 Signed-off-by: Jean Delvare <khali@linux-fr.org> Tested-by: Tommi Kyntola <tommi.kyntola@ray.fi>
Diffstat (limited to 'drivers/i2c/busses/i2c-i801.c')
-rw-r--r--drivers/i2c/busses/i2c-i801.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 6569a36985bd..a320e7d82c1f 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -97,6 +97,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
97 int command, int hwpec); 97 int command, int hwpec);
98 98
99static unsigned long i801_smba; 99static unsigned long i801_smba;
100static unsigned char i801_original_hstcfg;
100static struct pci_driver i801_driver; 101static struct pci_driver i801_driver;
101static struct pci_dev *I801_dev; 102static struct pci_dev *I801_dev;
102static int isich4; 103static int isich4;
@@ -510,6 +511,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
510 } 511 }
511 512
512 pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); 513 pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
514 i801_original_hstcfg = temp;
513 temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ 515 temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
514 if (!(temp & SMBHSTCFG_HST_EN)) { 516 if (!(temp & SMBHSTCFG_HST_EN)) {
515 dev_info(&dev->dev, "Enabling SMBus device\n"); 517 dev_info(&dev->dev, "Enabling SMBus device\n");
@@ -543,6 +545,7 @@ exit:
543static void __devexit i801_remove(struct pci_dev *dev) 545static void __devexit i801_remove(struct pci_dev *dev)
544{ 546{
545 i2c_del_adapter(&i801_adapter); 547 i2c_del_adapter(&i801_adapter);
548 pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg);
546 pci_release_region(dev, SMBBAR); 549 pci_release_region(dev, SMBBAR);
547 /* 550 /*
548 * do not call pci_disable_device(dev) since it can cause hard hangs on 551 * do not call pci_disable_device(dev) since it can cause hard hangs on
@@ -550,11 +553,33 @@ static void __devexit i801_remove(struct pci_dev *dev)
550 */ 553 */
551} 554}
552 555
556#ifdef CONFIG_PM
557static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
558{
559 pci_save_state(dev);
560 pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg);
561 pci_set_power_state(dev, pci_choose_state(dev, mesg));
562 return 0;
563}
564
565static int i801_resume(struct pci_dev *dev)
566{
567 pci_set_power_state(dev, PCI_D0);
568 pci_restore_state(dev);
569 return pci_enable_device(dev);
570}
571#else
572#define i801_suspend NULL
573#define i801_resume NULL
574#endif
575
553static struct pci_driver i801_driver = { 576static struct pci_driver i801_driver = {
554 .name = "i801_smbus", 577 .name = "i801_smbus",
555 .id_table = i801_ids, 578 .id_table = i801_ids,
556 .probe = i801_probe, 579 .probe = i801_probe,
557 .remove = __devexit_p(i801_remove), 580 .remove = __devexit_p(i801_remove),
581 .suspend = i801_suspend,
582 .resume = i801_resume,
558}; 583};
559 584
560static int __init i2c_i801_init(void) 585static int __init i2c_i801_init(void)