diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-nforce2.c')
-rw-r--r-- | drivers/i2c/busses/i2c-nforce2.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 43c9f8df9509..3b19bc41a60b 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/i2c.h> | 51 | #include <linux/i2c.h> |
52 | #include <linux/delay.h> | 52 | #include <linux/delay.h> |
53 | #include <linux/dmi.h> | 53 | #include <linux/dmi.h> |
54 | #include <linux/acpi.h> | ||
54 | #include <asm/io.h> | 55 | #include <asm/io.h> |
55 | 56 | ||
56 | MODULE_LICENSE("GPL"); | 57 | MODULE_LICENSE("GPL"); |
@@ -124,6 +125,20 @@ static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = { | |||
124 | 125 | ||
125 | static struct pci_driver nforce2_driver; | 126 | static struct pci_driver nforce2_driver; |
126 | 127 | ||
128 | /* For multiplexing support, we need a global reference to the 1st | ||
129 | SMBus channel */ | ||
130 | #if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE | ||
131 | struct i2c_adapter *nforce2_smbus; | ||
132 | EXPORT_SYMBOL_GPL(nforce2_smbus); | ||
133 | |||
134 | static void nforce2_set_reference(struct i2c_adapter *adap) | ||
135 | { | ||
136 | nforce2_smbus = adap; | ||
137 | } | ||
138 | #else | ||
139 | static inline void nforce2_set_reference(struct i2c_adapter *adap) { } | ||
140 | #endif | ||
141 | |||
127 | static void nforce2_abort(struct i2c_adapter *adap) | 142 | static void nforce2_abort(struct i2c_adapter *adap) |
128 | { | 143 | { |
129 | struct nforce2_smbus *smbus = adap->algo_data; | 144 | struct nforce2_smbus *smbus = adap->algo_data; |
@@ -158,16 +173,16 @@ static int nforce2_check_status(struct i2c_adapter *adap) | |||
158 | dev_dbg(&adap->dev, "SMBus Timeout!\n"); | 173 | dev_dbg(&adap->dev, "SMBus Timeout!\n"); |
159 | if (smbus->can_abort) | 174 | if (smbus->can_abort) |
160 | nforce2_abort(adap); | 175 | nforce2_abort(adap); |
161 | return -1; | 176 | return -ETIMEDOUT; |
162 | } | 177 | } |
163 | if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { | 178 | if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { |
164 | dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp); | 179 | dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp); |
165 | return -1; | 180 | return -EIO; |
166 | } | 181 | } |
167 | return 0; | 182 | return 0; |
168 | } | 183 | } |
169 | 184 | ||
170 | /* Return -1 on error */ | 185 | /* Return negative errno on error */ |
171 | static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | 186 | static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, |
172 | unsigned short flags, char read_write, | 187 | unsigned short flags, char read_write, |
173 | u8 command, int size, union i2c_smbus_data * data) | 188 | u8 command, int size, union i2c_smbus_data * data) |
@@ -175,7 +190,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
175 | struct nforce2_smbus *smbus = adap->algo_data; | 190 | struct nforce2_smbus *smbus = adap->algo_data; |
176 | unsigned char protocol, pec; | 191 | unsigned char protocol, pec; |
177 | u8 len; | 192 | u8 len; |
178 | int i; | 193 | int i, status; |
179 | 194 | ||
180 | protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : | 195 | protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : |
181 | NVIDIA_SMB_PRTCL_WRITE; | 196 | NVIDIA_SMB_PRTCL_WRITE; |
@@ -219,7 +234,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
219 | "Transaction failed " | 234 | "Transaction failed " |
220 | "(requested block size: %d)\n", | 235 | "(requested block size: %d)\n", |
221 | len); | 236 | len); |
222 | return -1; | 237 | return -EINVAL; |
223 | } | 238 | } |
224 | outb_p(len, NVIDIA_SMB_BCNT); | 239 | outb_p(len, NVIDIA_SMB_BCNT); |
225 | for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) | 240 | for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) |
@@ -231,14 +246,15 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
231 | 246 | ||
232 | default: | 247 | default: |
233 | dev_err(&adap->dev, "Unsupported transaction %d\n", size); | 248 | dev_err(&adap->dev, "Unsupported transaction %d\n", size); |
234 | return -1; | 249 | return -EOPNOTSUPP; |
235 | } | 250 | } |
236 | 251 | ||
237 | outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); | 252 | outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); |
238 | outb_p(protocol, NVIDIA_SMB_PRTCL); | 253 | outb_p(protocol, NVIDIA_SMB_PRTCL); |
239 | 254 | ||
240 | if (nforce2_check_status(adap)) | 255 | status = nforce2_check_status(adap); |
241 | return -1; | 256 | if (status) |
257 | return status; | ||
242 | 258 | ||
243 | if (read_write == I2C_SMBUS_WRITE) | 259 | if (read_write == I2C_SMBUS_WRITE) |
244 | return 0; | 260 | return 0; |
@@ -260,7 +276,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
260 | dev_err(&adap->dev, "Transaction failed " | 276 | dev_err(&adap->dev, "Transaction failed " |
261 | "(received block size: 0x%02x)\n", | 277 | "(received block size: 0x%02x)\n", |
262 | len); | 278 | len); |
263 | return -1; | 279 | return -EPROTO; |
264 | } | 280 | } |
265 | for (i = 0; i < len; i++) | 281 | for (i = 0; i < len; i++) |
266 | data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); | 282 | data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); |
@@ -321,21 +337,26 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, | |||
321 | != PCIBIOS_SUCCESSFUL) { | 337 | != PCIBIOS_SUCCESSFUL) { |
322 | dev_err(&dev->dev, "Error reading PCI config for %s\n", | 338 | dev_err(&dev->dev, "Error reading PCI config for %s\n", |
323 | name); | 339 | name); |
324 | return -1; | 340 | return -EIO; |
325 | } | 341 | } |
326 | 342 | ||
327 | smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; | 343 | smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; |
328 | smbus->size = 64; | 344 | smbus->size = 64; |
329 | } | 345 | } |
330 | 346 | ||
347 | error = acpi_check_region(smbus->base, smbus->size, | ||
348 | nforce2_driver.name); | ||
349 | if (error) | ||
350 | return -1; | ||
351 | |||
331 | if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { | 352 | if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { |
332 | dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", | 353 | dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", |
333 | smbus->base, smbus->base+smbus->size-1, name); | 354 | smbus->base, smbus->base+smbus->size-1, name); |
334 | return -1; | 355 | return -EBUSY; |
335 | } | 356 | } |
336 | smbus->adapter.owner = THIS_MODULE; | 357 | smbus->adapter.owner = THIS_MODULE; |
337 | smbus->adapter.id = I2C_HW_SMBUS_NFORCE2; | 358 | smbus->adapter.id = I2C_HW_SMBUS_NFORCE2; |
338 | smbus->adapter.class = I2C_CLASS_HWMON; | 359 | smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; |
339 | smbus->adapter.algo = &smbus_algorithm; | 360 | smbus->adapter.algo = &smbus_algorithm; |
340 | smbus->adapter.algo_data = smbus; | 361 | smbus->adapter.algo_data = smbus; |
341 | smbus->adapter.dev.parent = &dev->dev; | 362 | smbus->adapter.dev.parent = &dev->dev; |
@@ -346,7 +367,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, | |||
346 | if (error) { | 367 | if (error) { |
347 | dev_err(&smbus->adapter.dev, "Failed to register adapter.\n"); | 368 | dev_err(&smbus->adapter.dev, "Failed to register adapter.\n"); |
348 | release_region(smbus->base, smbus->size); | 369 | release_region(smbus->base, smbus->size); |
349 | return -1; | 370 | return error; |
350 | } | 371 | } |
351 | dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base); | 372 | dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base); |
352 | return 0; | 373 | return 0; |
@@ -398,6 +419,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ | |||
398 | return -ENODEV; | 419 | return -ENODEV; |
399 | } | 420 | } |
400 | 421 | ||
422 | nforce2_set_reference(&smbuses[0].adapter); | ||
401 | return 0; | 423 | return 0; |
402 | } | 424 | } |
403 | 425 | ||
@@ -406,6 +428,7 @@ static void __devexit nforce2_remove(struct pci_dev *dev) | |||
406 | { | 428 | { |
407 | struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev); | 429 | struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev); |
408 | 430 | ||
431 | nforce2_set_reference(NULL); | ||
409 | if (smbuses[0].base) { | 432 | if (smbuses[0].base) { |
410 | i2c_del_adapter(&smbuses[0].adapter); | 433 | i2c_del_adapter(&smbuses[0].adapter); |
411 | release_region(smbuses[0].base, smbuses[0].size); | 434 | release_region(smbuses[0].base, smbuses[0].size); |