X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fi2c%2Fbusses%2Fi2c-nforce2.c;h=081fdf3393f447a63d47bcafb34f8e953e09b114;hb=61045dbe9d8d81b1bae4dc1e9482d389ca99edc1;hp=c359eabe85fb2cdf023e276caaed9eb86f076e35;hpb=d49584c4a37c7228e7778bcb60f79e7a08472fa8;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index c359eab..081fdf3 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -50,6 +50,7 @@ #include #include #include +#include #include MODULE_LICENSE("GPL"); @@ -109,8 +110,34 @@ struct nforce2_smbus { /* Misc definitions */ #define MAX_TIMEOUT 100 +/* We disable the second SMBus channel on these boards */ +static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = { + { + .ident = "DFI Lanparty NF4 Expert", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"), + DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"), + }, + }, + { } +}; + static struct pci_driver nforce2_driver; +/* For multiplexing support, we need a global reference to the 1st + SMBus channel */ +#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE +struct i2c_adapter *nforce2_smbus; +EXPORT_SYMBOL_GPL(nforce2_smbus); + +static void nforce2_set_reference(struct i2c_adapter *adap) +{ + nforce2_smbus = adap; +} +#else +static inline void nforce2_set_reference(struct i2c_adapter *adap) { } +#endif + static void nforce2_abort(struct i2c_adapter *adap) { struct nforce2_smbus *smbus = adap->algo_data; @@ -145,16 +172,16 @@ static int nforce2_check_status(struct i2c_adapter *adap) dev_dbg(&adap->dev, "SMBus Timeout!\n"); if (smbus->can_abort) nforce2_abort(adap); - return -1; + return -ETIMEDOUT; } if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp); - return -1; + return -EIO; } return 0; } -/* Return -1 on error */ +/* Return negative errno on error */ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) @@ -162,7 +189,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, struct nforce2_smbus *smbus = adap->algo_data; unsigned char protocol, pec; u8 len; - int i; + int i, status; protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE; @@ -206,7 +233,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, "Transaction failed " "(requested block size: %d)\n", len); - return -1; + return -EINVAL; } outb_p(len, NVIDIA_SMB_BCNT); for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) @@ -218,14 +245,15 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, default: dev_err(&adap->dev, "Unsupported transaction %d\n", size); - return -1; + return -EOPNOTSUPP; } outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); outb_p(protocol, NVIDIA_SMB_PRTCL); - if (nforce2_check_status(adap)) - return -1; + status = nforce2_check_status(adap); + if (status) + return status; if (read_write == I2C_SMBUS_WRITE) return 0; @@ -247,7 +275,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, dev_err(&adap->dev, "Transaction failed " "(received block size: 0x%02x)\n", len); - return -1; + return -EPROTO; } for (i = 0; i < len; i++) data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); @@ -264,6 +292,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter) /* other functionality might be possible, but is not tested */ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PEC | (((struct nforce2_smbus*)adapter->algo_data)->blockops ? I2C_FUNC_SMBUS_BLOCK_DATA : 0); } @@ -307,7 +336,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, != PCIBIOS_SUCCESSFUL) { dev_err(&dev->dev, "Error reading PCI config for %s\n", name); - return -1; + return -EIO; } smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; @@ -317,7 +346,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name); - return -1; + return -EBUSY; } smbus->adapter.owner = THIS_MODULE; smbus->adapter.id = I2C_HW_SMBUS_NFORCE2; @@ -332,7 +361,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, if (error) { dev_err(&smbus->adapter.dev, "Failed to register adapter.\n"); release_region(smbus->base, smbus->size); - return -1; + return error; } dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base); return 0; @@ -350,6 +379,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ pci_set_drvdata(dev, smbuses); switch(dev->device) { + case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: smbuses[0].blockops = 1; @@ -365,10 +395,17 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ smbuses[0].base = 0; /* to have a check value */ } /* SMBus adapter 2 */ - res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); - if (res2 < 0) { - dev_err(&dev->dev, "Error probing SMB2.\n"); - smbuses[1].base = 0; /* to have a check value */ + if (dmi_check_system(nforce2_dmi_blacklist2)) { + dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n"); + res2 = -EPERM; + smbuses[1].base = 0; + } else { + res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], + "SMB2"); + if (res2 < 0) { + dev_err(&dev->dev, "Error probing SMB2.\n"); + smbuses[1].base = 0; /* to have a check value */ + } } if ((res1 < 0) && (res2 < 0)) { /* we did not find even one of the SMBuses, so we give up */ @@ -376,6 +413,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ return -ENODEV; } + nforce2_set_reference(&smbuses[0].adapter); return 0; } @@ -384,6 +422,7 @@ static void __devexit nforce2_remove(struct pci_dev *dev) { struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev); + nforce2_set_reference(NULL); if (smbuses[0].base) { i2c_del_adapter(&smbuses[0].adapter); release_region(smbuses[0].base, smbuses[0].size);