| 48 | | |
| 49 | | #ifndef PCI_DEVICE_ID_AMD_756 |
| 50 | | #define PCI_DEVICE_ID_AMD_756 0x740B |
| 51 | | #endif |
| 52 | | #ifndef PCI_DEVICE_ID_AMD_766 |
| 53 | | #define PCI_DEVICE_ID_AMD_766 0x7413 |
| 54 | | #endif |
| 55 | | #ifndef PCI_DEVICE_ID_AMD_768_SMBUS |
| 56 | | #define PCI_DEVICE_ID_AMD_768_SMBUS 0x7443 |
| 57 | | #endif |
| 58 | | #ifndef PCI_DEVICE_ID_AMD_8111_SMBUS |
| 59 | | #define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746B |
| 60 | | #endif |
| 61 | | #ifndef PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS |
| 62 | | #define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01B4 |
| 63 | | #endif |
| 64 | | |
| 65 | | struct sd { |
| 66 | | const unsigned short vendor; |
| 67 | | const unsigned short device; |
| 68 | | const unsigned short function; |
| 69 | | const char* name; |
| 70 | | int amdsetup:1; |
| 71 | | }; |
| 72 | | |
| 73 | | static struct sd supported[] = { |
| 74 | | {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_756, 3, "AMD756", 1}, |
| 75 | | {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_766, 3, "AMD766", 1}, |
| 76 | | {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_768_SMBUS, 3, "AMD768", 1}, |
| 77 | | {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, 3, "AMD8111", 1}, |
| 78 | | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS, 1, "nVidia nForce", 0}, |
| 79 | | {0, 0, 0} |
| 80 | | }; |
| | 48 | #include <asm/io.h> |
| | 49 | |
| | 50 | #define DRV_NAME "i2c-amd756" |
| 85 | | #define SMB_GLOBAL_STATUS (0x0 + amd756_smba) |
| 86 | | #define SMB_GLOBAL_ENABLE (0x2 + amd756_smba) |
| 87 | | #define SMB_HOST_ADDRESS (0x4 + amd756_smba) |
| 88 | | #define SMB_HOST_DATA (0x6 + amd756_smba) |
| 89 | | #define SMB_HOST_COMMAND (0x8 + amd756_smba) |
| 90 | | #define SMB_HOST_BLOCK_DATA (0x9 + amd756_smba) |
| 91 | | #define SMB_HAS_DATA (0xA + amd756_smba) |
| 92 | | #define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_smba) |
| 93 | | #define SMB_HAS_HOST_ADDRESS (0xE + amd756_smba) |
| 94 | | #define SMB_SNOOP_ADDRESS (0xF + amd756_smba) |
| | 55 | #define SMB_GLOBAL_STATUS (0x0 + amd756_ioport) |
| | 56 | #define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport) |
| | 57 | #define SMB_HOST_ADDRESS (0x4 + amd756_ioport) |
| | 58 | #define SMB_HOST_DATA (0x6 + amd756_ioport) |
| | 59 | #define SMB_HOST_COMMAND (0x8 + amd756_ioport) |
| | 60 | #define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport) |
| | 61 | #define SMB_HAS_DATA (0xA + amd756_ioport) |
| | 62 | #define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport) |
| | 63 | #define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport) |
| | 64 | #define SMB_SNOOP_ADDRESS (0xF + amd756_ioport) |
| 119 | | /* insmod parameters */ |
| 120 | | |
| 121 | | #ifdef MODULE |
| 122 | | static |
| 123 | | #else |
| 124 | | extern |
| 125 | | #endif |
| 126 | | int __init i2c_amd756_init(void); |
| 127 | | static int __init amd756_cleanup(void); |
| 128 | | static int amd756_setup(void); |
| 129 | | static s32 amd756_access(struct i2c_adapter *adap, u16 addr, |
| 130 | | unsigned short flags, char read_write, |
| 131 | | u8 command, int size, union i2c_smbus_data *data); |
| 132 | | static void amd756_do_pause(unsigned int amount); |
| 133 | | static void amd756_abort(void); |
| 134 | | static int amd756_transaction(void); |
| 135 | | static void amd756_inc(struct i2c_adapter *adapter); |
| 136 | | static void amd756_dec(struct i2c_adapter *adapter); |
| 137 | | static u32 amd756_func(struct i2c_adapter *adapter); |
| 138 | | |
| 139 | | #ifdef MODULE |
| 140 | | extern int init_module(void); |
| 141 | | extern int cleanup_module(void); |
| 142 | | #endif /* MODULE */ |
| 143 | | |
| 144 | | static struct i2c_algorithm smbus_algorithm = { |
| 145 | | /* name */ "Non-I2C SMBus adapter", |
| 146 | | /* id */ I2C_ALGO_SMBUS, |
| 147 | | /* master_xfer */ NULL, |
| 148 | | /* smbus_access */ amd756_access, |
| 149 | | /* slave;_send */ NULL, |
| 150 | | /* slave_rcv */ NULL, |
| 151 | | /* algo_control */ NULL, |
| 152 | | /* functionality */ amd756_func, |
| 153 | | }; |
| 154 | | |
| 155 | | static struct i2c_adapter amd756_adapter = { |
| 156 | | "unset", |
| 157 | | I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, |
| 158 | | &smbus_algorithm, |
| 159 | | NULL, |
| 160 | | amd756_inc, |
| 161 | | amd756_dec, |
| 162 | | NULL, |
| 163 | | NULL, |
| 164 | | }; |
| 165 | | |
| 166 | | static int __initdata amd756_initialized; |
| 167 | | static struct sd *amd756_sd = NULL; |
| 168 | | static unsigned short amd756_smba = 0; |
| 169 | | |
| 170 | | int amd756_setup(void) |
| 171 | | { |
| 172 | | unsigned char temp; |
| 173 | | struct sd *currdev; |
| 174 | | struct pci_dev *AMD756_dev = NULL; |
| 175 | | |
| 176 | | if (pci_present() == 0) { |
| 177 | | return -ENODEV; |
| 178 | | } |
| 179 | | |
| 180 | | /* Look for a supported chip */ |
| 181 | | for(currdev = supported; currdev->vendor; ) { |
| 182 | | AMD756_dev = pci_find_device(currdev->vendor, |
| 183 | | currdev->device, AMD756_dev); |
| 184 | | if (AMD756_dev != NULL) { |
| 185 | | if (PCI_FUNC(AMD756_dev->devfn) == currdev->function) |
| 186 | | break; |
| 187 | | } else { |
| 188 | | currdev++; |
| 189 | | } |
| 190 | | } |
| 191 | | |
| 192 | | if (AMD756_dev == NULL) { |
| 193 | | printk |
| 194 | | ("i2c-amd756.o: Error: No AMD756 or compatible device detected!\n"); |
| 195 | | return -ENODEV; |
| 196 | | } |
| 197 | | printk(KERN_INFO "i2c-amd756.o: Found %s SMBus controller.\n", currdev->name); |
| 198 | | |
| 199 | | if (currdev->amdsetup) |
| 200 | | { |
| 201 | | pci_read_config_byte(AMD756_dev, SMBGCFG, &temp); |
| 202 | | if ((temp & 128) == 0) { |
| 203 | | printk("i2c-amd756.o: Error: SMBus controller I/O not enabled!\n"); |
| 204 | | return -ENODEV; |
| 205 | | } |
| 206 | | |
| 207 | | /* Determine the address of the SMBus areas */ |
| 208 | | /* Technically it is a dword but... */ |
| 209 | | pci_read_config_word(AMD756_dev, SMBBA, &amd756_smba); |
| 210 | | amd756_smba &= 0xff00; |
| 211 | | amd756_smba += SMB_ADDR_OFFSET; |
| 212 | | } else { |
| 213 | | pci_read_config_word(AMD756_dev, SMBBANFORCE, &amd756_smba); |
| 214 | | amd756_smba &= 0xfffc; |
| 215 | | } |
| 216 | | if(amd756_smba == 0) { |
| 217 | | printk(KERN_ERR "i2c-amd756.o: Error: SMB base address uninitialized\n"); |
| 218 | | return -ENODEV; |
| 219 | | } |
| 220 | | if (check_region(amd756_smba, SMB_IOSIZE)) { |
| 221 | | printk |
| 222 | | ("i2c-amd756.o: SMB region 0x%x already in use!\n", |
| 223 | | amd756_smba); |
| 224 | | return -ENODEV; |
| 225 | | } |
| 226 | | |
| 227 | | /* Everything is happy, let's grab the memory and set things up. */ |
| 228 | | request_region(amd756_smba, SMB_IOSIZE, "amd756-smbus"); |
| 229 | | |
| 230 | | #ifdef DEBUG |
| 231 | | pci_read_config_byte(AMD756_dev, SMBREV, &temp); |
| 232 | | printk("i2c-amd756.o: SMBREV = 0x%X\n", temp); |
| 233 | | printk("i2c-amd756.o: AMD756_smba = 0x%X\n", amd756_smba); |
| 234 | | #endif /* DEBUG */ |
| 235 | | |
| 236 | | /* store struct sd * for future reference */ |
| 237 | | amd756_sd = currdev; |
| 238 | | |
| 239 | | return 0; |
| 240 | | } |
| | 89 | |
| | 90 | static unsigned short amd756_ioport = 0; |
| 355 | | printk |
| 356 | | ("i2c-amd756.o: Failed reset at end of transaction (%04x)\n", |
| 357 | | temp); |
| 358 | | } |
| 359 | | printk |
| 360 | | ("i2c-amd756.o: Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", |
| 361 | | inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), |
| 362 | | inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); |
| | 185 | pr_debug(DRV_NAME |
| | 186 | ": Failed reset at end of transaction (%04x)\n", temp); |
| | 187 | } |
| | 188 | |
| | 189 | pr_debug(DRV_NAME |
| | 190 | ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", |
| | 191 | inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), |
| | 192 | inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); |
| 482 | | int __init i2c_amd756_init(void) |
| 483 | | { |
| 484 | | int res; |
| 485 | | printk("i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE); |
| | 318 | static struct i2c_algorithm smbus_algorithm = { |
| | 319 | .name = "Non-I2C SMBus adapter", |
| | 320 | .id = I2C_ALGO_SMBUS, |
| | 321 | .smbus_xfer = amd756_access, |
| | 322 | .functionality = amd756_func, |
| | 323 | }; |
| | 324 | |
| | 325 | static struct i2c_adapter amd756_adapter = { |
| | 326 | .name = "unset", |
| | 327 | .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, |
| | 328 | .algo = &smbus_algorithm, |
| | 329 | .inc_use = amd756_inc, |
| | 330 | .dec_use = amd756_dec, |
| | 331 | }; |
| | 332 | |
| | 333 | enum chiptype { AMD756, AMD766, AMD768, NFORCE }; |
| | 334 | |
| | 335 | static struct pci_device_id amd756_ids[] __devinitdata = { |
| | 336 | {PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 }, |
| | 337 | {PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 }, |
| | 338 | {PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 }, |
| | 339 | {PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE }, |
| | 340 | { 0, } |
| | 341 | }; |
| | 342 | |
| | 343 | static int __devinit amd756_probe(struct pci_dev *pdev, |
| | 344 | const struct pci_device_id *id) |
| | 345 | { |
| | 346 | int nforce = (id->driver_data == NFORCE), error; |
| | 347 | u8 temp; |
| | 348 | |
| | 349 | if (amd756_ioport) { |
| | 350 | printk(KERN_ERR DRV_NAME ": Only one device supported. " |
| | 351 | "(you have a strange motherboard, btw..)\n"); |
| | 352 | return -ENODEV; |
| | 353 | } |
| | 354 | |
| | 355 | if (nforce) { |
| | 356 | if (PCI_FUNC(pdev->devfn) != 1) |
| | 357 | return -ENODEV; |
| | 358 | |
| | 359 | pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport); |
| | 360 | amd756_ioport &= 0xfffc; |
| | 361 | } else { /* amd */ |
| | 362 | if (PCI_FUNC(pdev->devfn) != 3) |
| | 363 | return -ENODEV; |
| | 364 | |
| | 365 | pci_read_config_byte(pdev, SMBGCFG, &temp); |
| | 366 | if ((temp & 128) == 0) { |
| | 367 | printk(KERN_ERR DRV_NAME |
| | 368 | ": Error: SMBus controller I/O not enabled!\n"); |
| | 369 | return -ENODEV; |
| | 370 | } |
| | 371 | |
| | 372 | /* Determine the address of the SMBus areas */ |
| | 373 | /* Technically it is a dword but... */ |
| | 374 | pci_read_config_word(pdev, SMBBA, &amd756_ioport); |
| | 375 | amd756_ioport &= 0xff00; |
| | 376 | amd756_ioport += SMB_ADDR_OFFSET; |
| | 377 | } |
| | 378 | |
| | 379 | if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { |
| | 380 | printk(KERN_ERR DRV_NAME |
| | 381 | ": SMB region 0x%x already in use!\n", amd756_ioport); |
| | 382 | return -ENODEV; |
| | 383 | } |
| | 384 | |
| 494 | | amd756_initialized = 0; |
| 495 | | if ((res = amd756_setup())) { |
| 496 | | printk |
| 497 | | ("i2c-amd756.o: AMD756 or compatible device not detected, module not inserted.\n"); |
| 498 | | amd756_cleanup(); |
| 499 | | return res; |
| 500 | | } |
| 501 | | amd756_initialized++; |
| 502 | | sprintf(amd756_adapter.name, "SMBus %s adapter at %04x", |
| 503 | | amd756_sd->name, amd756_smba); |
| 504 | | if ((res = i2c_add_adapter(&amd756_adapter))) { |
| 505 | | printk |
| 506 | | ("i2c-amd756.o: Adapter registration failed, module not inserted.\n"); |
| 507 | | amd756_cleanup(); |
| 508 | | return res; |
| 509 | | } |
| 510 | | amd756_initialized++; |
| 511 | | printk("i2c-amd756.o: %s bus detected and initialized\n", |
| 512 | | amd756_sd->name); |
| | 390 | |
| | 391 | sprintf(amd756_adapter.name, |
| | 392 | "SMBus AMD75x adapter at %04x", amd756_ioport); |
| | 393 | |
| | 394 | error = i2c_add_adapter(&amd756_adapter); |
| | 395 | if (error) { |
| | 396 | printk(KERN_ERR DRV_NAME |
| | 397 | ": Adapter registration failed, module not inserted.\n"); |
| | 398 | goto out_err; |
| | 399 | } |
| | 400 | |
| 514 | | } |
| 515 | | |
| 516 | | int __init amd756_cleanup(void) |
| 517 | | { |
| 518 | | int res; |
| 519 | | if (amd756_initialized >= 2) { |
| 520 | | if ((res = i2c_del_adapter(&amd756_adapter))) { |
| 521 | | printk |
| 522 | | ("i2c-amd756.o: i2c_del_adapter failed, module not removed\n"); |
| 523 | | return res; |
| 524 | | } else |
| 525 | | amd756_initialized--; |
| 526 | | } |
| 527 | | if (amd756_initialized >= 1) { |
| 528 | | release_region(amd756_smba, SMB_IOSIZE); |
| 529 | | amd756_initialized--; |
| 530 | | } |
| 531 | | return 0; |
| 532 | | } |
| 533 | | |
| 534 | | EXPORT_NO_SYMBOLS; |
| 535 | | |
| 536 | | #ifdef MODULE |
| | 402 | |
| | 403 | out_err: |
| | 404 | release_region(amd756_ioport, SMB_IOSIZE); |
| | 405 | return error; |
| | 406 | } |
| | 407 | |
| | 408 | static void __devexit amd756_remove(struct pci_dev *dev) |
| | 409 | { |
| | 410 | i2c_del_adapter(&amd756_adapter); |
| | 411 | release_region(amd756_ioport, SMB_IOSIZE); |
| | 412 | } |
| | 413 | |
| | 414 | static struct pci_driver amd756_driver = { |
| | 415 | .name = "amd75x smbus", |
| | 416 | .id_table = amd756_ids, |
| | 417 | .probe = amd756_probe, |
| | 418 | .remove = __devexit_p(amd756_remove), |
| | 419 | }; |
| | 420 | |
| | 421 | static int __init amd756_init(void) |
| | 422 | { |
| | 423 | printk(KERN_INFO "i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE); |
| | 424 | return pci_module_init(&amd756_driver); |
| | 425 | } |
| | 426 | |
| | 427 | static void __exit amd756_exit(void) |
| | 428 | { |
| | 429 | pci_unregister_driver(&amd756_driver); |
| | 430 | } |