1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds amd756.c - Part of lm_sensors, Linux kernel modules for hardware 3*1da177e4SLinus Torvalds monitoring 4*1da177e4SLinus Torvalds 5*1da177e4SLinus Torvalds Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org> 6*1da177e4SLinus Torvalds 7*1da177e4SLinus Torvalds Shamelessly ripped from i2c-piix4.c: 8*1da177e4SLinus Torvalds 9*1da177e4SLinus Torvalds Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and 10*1da177e4SLinus Torvalds Philip Edelbrock <phil@netroedge.com> 11*1da177e4SLinus Torvalds 12*1da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify 13*1da177e4SLinus Torvalds it under the terms of the GNU General Public License as published by 14*1da177e4SLinus Torvalds the Free Software Foundation; either version 2 of the License, or 15*1da177e4SLinus Torvalds (at your option) any later version. 16*1da177e4SLinus Torvalds 17*1da177e4SLinus Torvalds This program is distributed in the hope that it will be useful, 18*1da177e4SLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 19*1da177e4SLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20*1da177e4SLinus Torvalds GNU General Public License for more details. 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds You should have received a copy of the GNU General Public License 23*1da177e4SLinus Torvalds along with this program; if not, write to the Free Software 24*1da177e4SLinus Torvalds Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25*1da177e4SLinus Torvalds */ 26*1da177e4SLinus Torvalds 27*1da177e4SLinus Torvalds /* 28*1da177e4SLinus Torvalds 2002-04-08: Added nForce support. (Csaba Halasz) 29*1da177e4SLinus Torvalds 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil) 30*1da177e4SLinus Torvalds 2002-12-28: Rewritten into something that resembles a Linux driver (hch) 31*1da177e4SLinus Torvalds 2003-11-29: Added back AMD8111 removed by the previous rewrite. 32*1da177e4SLinus Torvalds (Philip Pokorny) 33*1da177e4SLinus Torvalds */ 34*1da177e4SLinus Torvalds 35*1da177e4SLinus Torvalds /* 36*1da177e4SLinus Torvalds Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce 37*1da177e4SLinus Torvalds Note: we assume there can only be one device, with one SMBus interface. 38*1da177e4SLinus Torvalds */ 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds #include <linux/config.h> 41*1da177e4SLinus Torvalds #include <linux/module.h> 42*1da177e4SLinus Torvalds #include <linux/pci.h> 43*1da177e4SLinus Torvalds #include <linux/kernel.h> 44*1da177e4SLinus Torvalds #include <linux/delay.h> 45*1da177e4SLinus Torvalds #include <linux/stddef.h> 46*1da177e4SLinus Torvalds #include <linux/sched.h> 47*1da177e4SLinus Torvalds #include <linux/ioport.h> 48*1da177e4SLinus Torvalds #include <linux/i2c.h> 49*1da177e4SLinus Torvalds #include <linux/init.h> 50*1da177e4SLinus Torvalds #include <asm/io.h> 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds /* AMD756 SMBus address offsets */ 53*1da177e4SLinus Torvalds #define SMB_ADDR_OFFSET 0xE0 54*1da177e4SLinus Torvalds #define SMB_IOSIZE 16 55*1da177e4SLinus Torvalds #define SMB_GLOBAL_STATUS (0x0 + amd756_ioport) 56*1da177e4SLinus Torvalds #define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport) 57*1da177e4SLinus Torvalds #define SMB_HOST_ADDRESS (0x4 + amd756_ioport) 58*1da177e4SLinus Torvalds #define SMB_HOST_DATA (0x6 + amd756_ioport) 59*1da177e4SLinus Torvalds #define SMB_HOST_COMMAND (0x8 + amd756_ioport) 60*1da177e4SLinus Torvalds #define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport) 61*1da177e4SLinus Torvalds #define SMB_HAS_DATA (0xA + amd756_ioport) 62*1da177e4SLinus Torvalds #define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport) 63*1da177e4SLinus Torvalds #define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport) 64*1da177e4SLinus Torvalds #define SMB_SNOOP_ADDRESS (0xF + amd756_ioport) 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds /* PCI Address Constants */ 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds /* address of I/O space */ 69*1da177e4SLinus Torvalds #define SMBBA 0x058 /* mh */ 70*1da177e4SLinus Torvalds #define SMBBANFORCE 0x014 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds /* general configuration */ 73*1da177e4SLinus Torvalds #define SMBGCFG 0x041 /* mh */ 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds /* silicon revision code */ 76*1da177e4SLinus Torvalds #define SMBREV 0x008 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds /* Other settings */ 79*1da177e4SLinus Torvalds #define MAX_TIMEOUT 500 80*1da177e4SLinus Torvalds 81*1da177e4SLinus Torvalds /* AMD756 constants */ 82*1da177e4SLinus Torvalds #define AMD756_QUICK 0x00 83*1da177e4SLinus Torvalds #define AMD756_BYTE 0x01 84*1da177e4SLinus Torvalds #define AMD756_BYTE_DATA 0x02 85*1da177e4SLinus Torvalds #define AMD756_WORD_DATA 0x03 86*1da177e4SLinus Torvalds #define AMD756_PROCESS_CALL 0x04 87*1da177e4SLinus Torvalds #define AMD756_BLOCK_DATA 0x05 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds static unsigned short amd756_ioport = 0; 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds /* 93*1da177e4SLinus Torvalds SMBUS event = I/O 28-29 bit 11 94*1da177e4SLinus Torvalds see E0 for the status bits and enabled in E2 95*1da177e4SLinus Torvalds 96*1da177e4SLinus Torvalds */ 97*1da177e4SLinus Torvalds #define GS_ABRT_STS (1 << 0) 98*1da177e4SLinus Torvalds #define GS_COL_STS (1 << 1) 99*1da177e4SLinus Torvalds #define GS_PRERR_STS (1 << 2) 100*1da177e4SLinus Torvalds #define GS_HST_STS (1 << 3) 101*1da177e4SLinus Torvalds #define GS_HCYC_STS (1 << 4) 102*1da177e4SLinus Torvalds #define GS_TO_STS (1 << 5) 103*1da177e4SLinus Torvalds #define GS_SMB_STS (1 << 11) 104*1da177e4SLinus Torvalds 105*1da177e4SLinus Torvalds #define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ 106*1da177e4SLinus Torvalds GS_HCYC_STS | GS_TO_STS ) 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds #define GE_CYC_TYPE_MASK (7) 109*1da177e4SLinus Torvalds #define GE_HOST_STC (1 << 3) 110*1da177e4SLinus Torvalds #define GE_ABORT (1 << 5) 111*1da177e4SLinus Torvalds 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds static int amd756_transaction(struct i2c_adapter *adap) 114*1da177e4SLinus Torvalds { 115*1da177e4SLinus Torvalds int temp; 116*1da177e4SLinus Torvalds int result = 0; 117*1da177e4SLinus Torvalds int timeout = 0; 118*1da177e4SLinus Torvalds 119*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, " 120*1da177e4SLinus Torvalds "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS), 121*1da177e4SLinus Torvalds inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS), 122*1da177e4SLinus Torvalds inb_p(SMB_HOST_DATA)); 123*1da177e4SLinus Torvalds 124*1da177e4SLinus Torvalds /* Make sure the SMBus host is ready to start transmitting */ 125*1da177e4SLinus Torvalds if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) { 126*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp); 127*1da177e4SLinus Torvalds do { 128*1da177e4SLinus Torvalds msleep(1); 129*1da177e4SLinus Torvalds temp = inw_p(SMB_GLOBAL_STATUS); 130*1da177e4SLinus Torvalds } while ((temp & (GS_HST_STS | GS_SMB_STS)) && 131*1da177e4SLinus Torvalds (timeout++ < MAX_TIMEOUT)); 132*1da177e4SLinus Torvalds /* If the SMBus is still busy, we give up */ 133*1da177e4SLinus Torvalds if (timeout >= MAX_TIMEOUT) { 134*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp); 135*1da177e4SLinus Torvalds goto abort; 136*1da177e4SLinus Torvalds } 137*1da177e4SLinus Torvalds timeout = 0; 138*1da177e4SLinus Torvalds } 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds /* start the transaction by setting the start bit */ 141*1da177e4SLinus Torvalds outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE); 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds /* We will always wait for a fraction of a second! */ 144*1da177e4SLinus Torvalds do { 145*1da177e4SLinus Torvalds msleep(1); 146*1da177e4SLinus Torvalds temp = inw_p(SMB_GLOBAL_STATUS); 147*1da177e4SLinus Torvalds } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT)); 148*1da177e4SLinus Torvalds 149*1da177e4SLinus Torvalds /* If the SMBus is still busy, we give up */ 150*1da177e4SLinus Torvalds if (timeout >= MAX_TIMEOUT) { 151*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "Completion timeout!\n"); 152*1da177e4SLinus Torvalds goto abort; 153*1da177e4SLinus Torvalds } 154*1da177e4SLinus Torvalds 155*1da177e4SLinus Torvalds if (temp & GS_PRERR_STS) { 156*1da177e4SLinus Torvalds result = -1; 157*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n"); 158*1da177e4SLinus Torvalds } 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds if (temp & GS_COL_STS) { 161*1da177e4SLinus Torvalds result = -1; 162*1da177e4SLinus Torvalds dev_warn(&adap->dev, "SMBus collision!\n"); 163*1da177e4SLinus Torvalds } 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds if (temp & GS_TO_STS) { 166*1da177e4SLinus Torvalds result = -1; 167*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "SMBus protocol timeout!\n"); 168*1da177e4SLinus Torvalds } 169*1da177e4SLinus Torvalds 170*1da177e4SLinus Torvalds if (temp & GS_HCYC_STS) 171*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "SMBus protocol success!\n"); 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); 174*1da177e4SLinus Torvalds 175*1da177e4SLinus Torvalds #ifdef DEBUG 176*1da177e4SLinus Torvalds if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) { 177*1da177e4SLinus Torvalds dev_dbg(&adap->dev, 178*1da177e4SLinus Torvalds "Failed reset at end of transaction (%04x)\n", temp); 179*1da177e4SLinus Torvalds } 180*1da177e4SLinus Torvalds #endif 181*1da177e4SLinus Torvalds 182*1da177e4SLinus Torvalds dev_dbg(&adap->dev, 183*1da177e4SLinus Torvalds "Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", 184*1da177e4SLinus Torvalds inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), 185*1da177e4SLinus Torvalds inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds return result; 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds abort: 190*1da177e4SLinus Torvalds dev_warn(&adap->dev, "Sending abort\n"); 191*1da177e4SLinus Torvalds outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); 192*1da177e4SLinus Torvalds msleep(100); 193*1da177e4SLinus Torvalds outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); 194*1da177e4SLinus Torvalds return -1; 195*1da177e4SLinus Torvalds } 196*1da177e4SLinus Torvalds 197*1da177e4SLinus Torvalds /* Return -1 on error. */ 198*1da177e4SLinus Torvalds static s32 amd756_access(struct i2c_adapter * adap, u16 addr, 199*1da177e4SLinus Torvalds unsigned short flags, char read_write, 200*1da177e4SLinus Torvalds u8 command, int size, union i2c_smbus_data * data) 201*1da177e4SLinus Torvalds { 202*1da177e4SLinus Torvalds int i, len; 203*1da177e4SLinus Torvalds 204*1da177e4SLinus Torvalds /** TODO: Should I supporte the 10-bit transfers? */ 205*1da177e4SLinus Torvalds switch (size) { 206*1da177e4SLinus Torvalds case I2C_SMBUS_PROC_CALL: 207*1da177e4SLinus Torvalds dev_dbg(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); 208*1da177e4SLinus Torvalds /* TODO: Well... It is supported, I'm just not sure what to do here... */ 209*1da177e4SLinus Torvalds return -1; 210*1da177e4SLinus Torvalds case I2C_SMBUS_QUICK: 211*1da177e4SLinus Torvalds outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), 212*1da177e4SLinus Torvalds SMB_HOST_ADDRESS); 213*1da177e4SLinus Torvalds size = AMD756_QUICK; 214*1da177e4SLinus Torvalds break; 215*1da177e4SLinus Torvalds case I2C_SMBUS_BYTE: 216*1da177e4SLinus Torvalds outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), 217*1da177e4SLinus Torvalds SMB_HOST_ADDRESS); 218*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 219*1da177e4SLinus Torvalds outb_p(command, SMB_HOST_DATA); 220*1da177e4SLinus Torvalds size = AMD756_BYTE; 221*1da177e4SLinus Torvalds break; 222*1da177e4SLinus Torvalds case I2C_SMBUS_BYTE_DATA: 223*1da177e4SLinus Torvalds outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), 224*1da177e4SLinus Torvalds SMB_HOST_ADDRESS); 225*1da177e4SLinus Torvalds outb_p(command, SMB_HOST_COMMAND); 226*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 227*1da177e4SLinus Torvalds outw_p(data->byte, SMB_HOST_DATA); 228*1da177e4SLinus Torvalds size = AMD756_BYTE_DATA; 229*1da177e4SLinus Torvalds break; 230*1da177e4SLinus Torvalds case I2C_SMBUS_WORD_DATA: 231*1da177e4SLinus Torvalds outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), 232*1da177e4SLinus Torvalds SMB_HOST_ADDRESS); 233*1da177e4SLinus Torvalds outb_p(command, SMB_HOST_COMMAND); 234*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 235*1da177e4SLinus Torvalds outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */ 236*1da177e4SLinus Torvalds size = AMD756_WORD_DATA; 237*1da177e4SLinus Torvalds break; 238*1da177e4SLinus Torvalds case I2C_SMBUS_BLOCK_DATA: 239*1da177e4SLinus Torvalds outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), 240*1da177e4SLinus Torvalds SMB_HOST_ADDRESS); 241*1da177e4SLinus Torvalds outb_p(command, SMB_HOST_COMMAND); 242*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) { 243*1da177e4SLinus Torvalds len = data->block[0]; 244*1da177e4SLinus Torvalds if (len < 0) 245*1da177e4SLinus Torvalds len = 0; 246*1da177e4SLinus Torvalds if (len > 32) 247*1da177e4SLinus Torvalds len = 32; 248*1da177e4SLinus Torvalds outw_p(len, SMB_HOST_DATA); 249*1da177e4SLinus Torvalds /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ 250*1da177e4SLinus Torvalds for (i = 1; i <= len; i++) 251*1da177e4SLinus Torvalds outb_p(data->block[i], 252*1da177e4SLinus Torvalds SMB_HOST_BLOCK_DATA); 253*1da177e4SLinus Torvalds } 254*1da177e4SLinus Torvalds size = AMD756_BLOCK_DATA; 255*1da177e4SLinus Torvalds break; 256*1da177e4SLinus Torvalds } 257*1da177e4SLinus Torvalds 258*1da177e4SLinus Torvalds /* How about enabling interrupts... */ 259*1da177e4SLinus Torvalds outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE); 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds if (amd756_transaction(adap)) /* Error in transaction */ 262*1da177e4SLinus Torvalds return -1; 263*1da177e4SLinus Torvalds 264*1da177e4SLinus Torvalds if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK)) 265*1da177e4SLinus Torvalds return 0; 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds 268*1da177e4SLinus Torvalds switch (size) { 269*1da177e4SLinus Torvalds case AMD756_BYTE: 270*1da177e4SLinus Torvalds data->byte = inw_p(SMB_HOST_DATA); 271*1da177e4SLinus Torvalds break; 272*1da177e4SLinus Torvalds case AMD756_BYTE_DATA: 273*1da177e4SLinus Torvalds data->byte = inw_p(SMB_HOST_DATA); 274*1da177e4SLinus Torvalds break; 275*1da177e4SLinus Torvalds case AMD756_WORD_DATA: 276*1da177e4SLinus Torvalds data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */ 277*1da177e4SLinus Torvalds break; 278*1da177e4SLinus Torvalds case AMD756_BLOCK_DATA: 279*1da177e4SLinus Torvalds data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f; 280*1da177e4SLinus Torvalds if(data->block[0] > 32) 281*1da177e4SLinus Torvalds data->block[0] = 32; 282*1da177e4SLinus Torvalds /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ 283*1da177e4SLinus Torvalds for (i = 1; i <= data->block[0]; i++) 284*1da177e4SLinus Torvalds data->block[i] = inb_p(SMB_HOST_BLOCK_DATA); 285*1da177e4SLinus Torvalds break; 286*1da177e4SLinus Torvalds } 287*1da177e4SLinus Torvalds 288*1da177e4SLinus Torvalds return 0; 289*1da177e4SLinus Torvalds } 290*1da177e4SLinus Torvalds 291*1da177e4SLinus Torvalds static u32 amd756_func(struct i2c_adapter *adapter) 292*1da177e4SLinus Torvalds { 293*1da177e4SLinus Torvalds return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 294*1da177e4SLinus Torvalds I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 295*1da177e4SLinus Torvalds I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL; 296*1da177e4SLinus Torvalds } 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds static struct i2c_algorithm smbus_algorithm = { 299*1da177e4SLinus Torvalds .name = "Non-I2C SMBus adapter", 300*1da177e4SLinus Torvalds .id = I2C_ALGO_SMBUS, 301*1da177e4SLinus Torvalds .smbus_xfer = amd756_access, 302*1da177e4SLinus Torvalds .functionality = amd756_func, 303*1da177e4SLinus Torvalds }; 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds struct i2c_adapter amd756_smbus = { 306*1da177e4SLinus Torvalds .owner = THIS_MODULE, 307*1da177e4SLinus Torvalds .class = I2C_CLASS_HWMON, 308*1da177e4SLinus Torvalds .algo = &smbus_algorithm, 309*1da177e4SLinus Torvalds .name = "unset", 310*1da177e4SLinus Torvalds }; 311*1da177e4SLinus Torvalds 312*1da177e4SLinus Torvalds enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 }; 313*1da177e4SLinus Torvalds static const char* chipname[] = { 314*1da177e4SLinus Torvalds "AMD756", "AMD766", "AMD768", 315*1da177e4SLinus Torvalds "nVidia nForce", "AMD8111", 316*1da177e4SLinus Torvalds }; 317*1da177e4SLinus Torvalds 318*1da177e4SLinus Torvalds static struct pci_device_id amd756_ids[] = { 319*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), 320*1da177e4SLinus Torvalds .driver_data = AMD756 }, 321*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), 322*1da177e4SLinus Torvalds .driver_data = AMD766 }, 323*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443), 324*1da177e4SLinus Torvalds .driver_data = AMD768 }, 325*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 326*1da177e4SLinus Torvalds .driver_data = AMD8111 }, 327*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS), 328*1da177e4SLinus Torvalds .driver_data = NFORCE }, 329*1da177e4SLinus Torvalds { 0, } 330*1da177e4SLinus Torvalds }; 331*1da177e4SLinus Torvalds 332*1da177e4SLinus Torvalds MODULE_DEVICE_TABLE (pci, amd756_ids); 333*1da177e4SLinus Torvalds 334*1da177e4SLinus Torvalds static int __devinit amd756_probe(struct pci_dev *pdev, 335*1da177e4SLinus Torvalds const struct pci_device_id *id) 336*1da177e4SLinus Torvalds { 337*1da177e4SLinus Torvalds int nforce = (id->driver_data == NFORCE); 338*1da177e4SLinus Torvalds int error; 339*1da177e4SLinus Torvalds u8 temp; 340*1da177e4SLinus Torvalds 341*1da177e4SLinus Torvalds if (amd756_ioport) { 342*1da177e4SLinus Torvalds dev_err(&pdev->dev, "Only one device supported " 343*1da177e4SLinus Torvalds "(you have a strange motherboard, btw)\n"); 344*1da177e4SLinus Torvalds return -ENODEV; 345*1da177e4SLinus Torvalds } 346*1da177e4SLinus Torvalds 347*1da177e4SLinus Torvalds if (nforce) { 348*1da177e4SLinus Torvalds if (PCI_FUNC(pdev->devfn) != 1) 349*1da177e4SLinus Torvalds return -ENODEV; 350*1da177e4SLinus Torvalds 351*1da177e4SLinus Torvalds pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport); 352*1da177e4SLinus Torvalds amd756_ioport &= 0xfffc; 353*1da177e4SLinus Torvalds } else { /* amd */ 354*1da177e4SLinus Torvalds if (PCI_FUNC(pdev->devfn) != 3) 355*1da177e4SLinus Torvalds return -ENODEV; 356*1da177e4SLinus Torvalds 357*1da177e4SLinus Torvalds pci_read_config_byte(pdev, SMBGCFG, &temp); 358*1da177e4SLinus Torvalds if ((temp & 128) == 0) { 359*1da177e4SLinus Torvalds dev_err(&pdev->dev, 360*1da177e4SLinus Torvalds "Error: SMBus controller I/O not enabled!\n"); 361*1da177e4SLinus Torvalds return -ENODEV; 362*1da177e4SLinus Torvalds } 363*1da177e4SLinus Torvalds 364*1da177e4SLinus Torvalds /* Determine the address of the SMBus areas */ 365*1da177e4SLinus Torvalds /* Technically it is a dword but... */ 366*1da177e4SLinus Torvalds pci_read_config_word(pdev, SMBBA, &amd756_ioport); 367*1da177e4SLinus Torvalds amd756_ioport &= 0xff00; 368*1da177e4SLinus Torvalds amd756_ioport += SMB_ADDR_OFFSET; 369*1da177e4SLinus Torvalds } 370*1da177e4SLinus Torvalds 371*1da177e4SLinus Torvalds if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { 372*1da177e4SLinus Torvalds dev_err(&pdev->dev, "SMB region 0x%x already in use!\n", 373*1da177e4SLinus Torvalds amd756_ioport); 374*1da177e4SLinus Torvalds return -ENODEV; 375*1da177e4SLinus Torvalds } 376*1da177e4SLinus Torvalds 377*1da177e4SLinus Torvalds pci_read_config_byte(pdev, SMBREV, &temp); 378*1da177e4SLinus Torvalds dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); 379*1da177e4SLinus Torvalds dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport); 380*1da177e4SLinus Torvalds 381*1da177e4SLinus Torvalds /* set up the driverfs linkage to our parent device */ 382*1da177e4SLinus Torvalds amd756_smbus.dev.parent = &pdev->dev; 383*1da177e4SLinus Torvalds 384*1da177e4SLinus Torvalds sprintf(amd756_smbus.name, "SMBus %s adapter at %04x", 385*1da177e4SLinus Torvalds chipname[id->driver_data], amd756_ioport); 386*1da177e4SLinus Torvalds 387*1da177e4SLinus Torvalds error = i2c_add_adapter(&amd756_smbus); 388*1da177e4SLinus Torvalds if (error) { 389*1da177e4SLinus Torvalds dev_err(&pdev->dev, 390*1da177e4SLinus Torvalds "Adapter registration failed, module not inserted\n"); 391*1da177e4SLinus Torvalds goto out_err; 392*1da177e4SLinus Torvalds } 393*1da177e4SLinus Torvalds 394*1da177e4SLinus Torvalds return 0; 395*1da177e4SLinus Torvalds 396*1da177e4SLinus Torvalds out_err: 397*1da177e4SLinus Torvalds release_region(amd756_ioport, SMB_IOSIZE); 398*1da177e4SLinus Torvalds return error; 399*1da177e4SLinus Torvalds } 400*1da177e4SLinus Torvalds 401*1da177e4SLinus Torvalds static void __devexit amd756_remove(struct pci_dev *dev) 402*1da177e4SLinus Torvalds { 403*1da177e4SLinus Torvalds i2c_del_adapter(&amd756_smbus); 404*1da177e4SLinus Torvalds release_region(amd756_ioport, SMB_IOSIZE); 405*1da177e4SLinus Torvalds } 406*1da177e4SLinus Torvalds 407*1da177e4SLinus Torvalds static struct pci_driver amd756_driver = { 408*1da177e4SLinus Torvalds .name = "amd756_smbus", 409*1da177e4SLinus Torvalds .id_table = amd756_ids, 410*1da177e4SLinus Torvalds .probe = amd756_probe, 411*1da177e4SLinus Torvalds .remove = __devexit_p(amd756_remove), 412*1da177e4SLinus Torvalds }; 413*1da177e4SLinus Torvalds 414*1da177e4SLinus Torvalds static int __init amd756_init(void) 415*1da177e4SLinus Torvalds { 416*1da177e4SLinus Torvalds return pci_register_driver(&amd756_driver); 417*1da177e4SLinus Torvalds } 418*1da177e4SLinus Torvalds 419*1da177e4SLinus Torvalds static void __exit amd756_exit(void) 420*1da177e4SLinus Torvalds { 421*1da177e4SLinus Torvalds pci_unregister_driver(&amd756_driver); 422*1da177e4SLinus Torvalds } 423*1da177e4SLinus Torvalds 424*1da177e4SLinus Torvalds MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>"); 425*1da177e4SLinus Torvalds MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); 426*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 427*1da177e4SLinus Torvalds 428*1da177e4SLinus Torvalds EXPORT_SYMBOL(amd756_smbus); 429*1da177e4SLinus Torvalds 430*1da177e4SLinus Torvalds module_init(amd756_init) 431*1da177e4SLinus Torvalds module_exit(amd756_exit) 432