1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds piix4.c - Part of lm_sensors, Linux kernel modules for hardware 3*1da177e4SLinus Torvalds monitoring 4*1da177e4SLinus Torvalds Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and 5*1da177e4SLinus Torvalds Philip Edelbrock <phil@netroedge.com> 6*1da177e4SLinus Torvalds 7*1da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify 8*1da177e4SLinus Torvalds it under the terms of the GNU General Public License as published by 9*1da177e4SLinus Torvalds the Free Software Foundation; either version 2 of the License, or 10*1da177e4SLinus Torvalds (at your option) any later version. 11*1da177e4SLinus Torvalds 12*1da177e4SLinus Torvalds This program is distributed in the hope that it will be useful, 13*1da177e4SLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 14*1da177e4SLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*1da177e4SLinus Torvalds GNU General Public License for more details. 16*1da177e4SLinus Torvalds 17*1da177e4SLinus Torvalds You should have received a copy of the GNU General Public License 18*1da177e4SLinus Torvalds along with this program; if not, write to the Free Software 19*1da177e4SLinus Torvalds Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*1da177e4SLinus Torvalds */ 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds /* 23*1da177e4SLinus Torvalds Supports: 24*1da177e4SLinus Torvalds Intel PIIX4, 440MX 25*1da177e4SLinus Torvalds Serverworks OSB4, CSB5, CSB6 26*1da177e4SLinus Torvalds SMSC Victory66 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds Note: we assume there can only be one device, with one SMBus interface. 29*1da177e4SLinus Torvalds */ 30*1da177e4SLinus Torvalds 31*1da177e4SLinus Torvalds #include <linux/config.h> 32*1da177e4SLinus Torvalds #include <linux/module.h> 33*1da177e4SLinus Torvalds #include <linux/moduleparam.h> 34*1da177e4SLinus Torvalds #include <linux/pci.h> 35*1da177e4SLinus Torvalds #include <linux/kernel.h> 36*1da177e4SLinus Torvalds #include <linux/delay.h> 37*1da177e4SLinus Torvalds #include <linux/stddef.h> 38*1da177e4SLinus Torvalds #include <linux/sched.h> 39*1da177e4SLinus Torvalds #include <linux/ioport.h> 40*1da177e4SLinus Torvalds #include <linux/i2c.h> 41*1da177e4SLinus Torvalds #include <linux/init.h> 42*1da177e4SLinus Torvalds #include <linux/apm_bios.h> 43*1da177e4SLinus Torvalds #include <linux/dmi.h> 44*1da177e4SLinus Torvalds #include <asm/io.h> 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds struct sd { 48*1da177e4SLinus Torvalds const unsigned short mfr; 49*1da177e4SLinus Torvalds const unsigned short dev; 50*1da177e4SLinus Torvalds const unsigned char fn; 51*1da177e4SLinus Torvalds const char *name; 52*1da177e4SLinus Torvalds }; 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds /* PIIX4 SMBus address offsets */ 55*1da177e4SLinus Torvalds #define SMBHSTSTS (0 + piix4_smba) 56*1da177e4SLinus Torvalds #define SMBHSLVSTS (1 + piix4_smba) 57*1da177e4SLinus Torvalds #define SMBHSTCNT (2 + piix4_smba) 58*1da177e4SLinus Torvalds #define SMBHSTCMD (3 + piix4_smba) 59*1da177e4SLinus Torvalds #define SMBHSTADD (4 + piix4_smba) 60*1da177e4SLinus Torvalds #define SMBHSTDAT0 (5 + piix4_smba) 61*1da177e4SLinus Torvalds #define SMBHSTDAT1 (6 + piix4_smba) 62*1da177e4SLinus Torvalds #define SMBBLKDAT (7 + piix4_smba) 63*1da177e4SLinus Torvalds #define SMBSLVCNT (8 + piix4_smba) 64*1da177e4SLinus Torvalds #define SMBSHDWCMD (9 + piix4_smba) 65*1da177e4SLinus Torvalds #define SMBSLVEVT (0xA + piix4_smba) 66*1da177e4SLinus Torvalds #define SMBSLVDAT (0xC + piix4_smba) 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds /* count for request_region */ 69*1da177e4SLinus Torvalds #define SMBIOSIZE 8 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* PCI Address Constants */ 72*1da177e4SLinus Torvalds #define SMBBA 0x090 73*1da177e4SLinus Torvalds #define SMBHSTCFG 0x0D2 74*1da177e4SLinus Torvalds #define SMBSLVC 0x0D3 75*1da177e4SLinus Torvalds #define SMBSHDW1 0x0D4 76*1da177e4SLinus Torvalds #define SMBSHDW2 0x0D5 77*1da177e4SLinus Torvalds #define SMBREV 0x0D6 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds /* Other settings */ 80*1da177e4SLinus Torvalds #define MAX_TIMEOUT 500 81*1da177e4SLinus Torvalds #define ENABLE_INT9 0 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds /* PIIX4 constants */ 84*1da177e4SLinus Torvalds #define PIIX4_QUICK 0x00 85*1da177e4SLinus Torvalds #define PIIX4_BYTE 0x04 86*1da177e4SLinus Torvalds #define PIIX4_BYTE_DATA 0x08 87*1da177e4SLinus Torvalds #define PIIX4_WORD_DATA 0x0C 88*1da177e4SLinus Torvalds #define PIIX4_BLOCK_DATA 0x14 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds /* insmod parameters */ 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds /* If force is set to anything different from 0, we forcibly enable the 93*1da177e4SLinus Torvalds PIIX4. DANGEROUS! */ 94*1da177e4SLinus Torvalds static int force = 0; 95*1da177e4SLinus Torvalds module_param (force, int, 0); 96*1da177e4SLinus Torvalds MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!"); 97*1da177e4SLinus Torvalds 98*1da177e4SLinus Torvalds /* If force_addr is set to anything different from 0, we forcibly enable 99*1da177e4SLinus Torvalds the PIIX4 at the given address. VERY DANGEROUS! */ 100*1da177e4SLinus Torvalds static int force_addr = 0; 101*1da177e4SLinus Torvalds module_param (force_addr, int, 0); 102*1da177e4SLinus Torvalds MODULE_PARM_DESC(force_addr, 103*1da177e4SLinus Torvalds "Forcibly enable the PIIX4 at the given address. " 104*1da177e4SLinus Torvalds "EXTREMELY DANGEROUS!"); 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds /* If fix_hstcfg is set to anything different from 0, we reset one of the 107*1da177e4SLinus Torvalds registers to be a valid value. */ 108*1da177e4SLinus Torvalds static int fix_hstcfg = 0; 109*1da177e4SLinus Torvalds module_param (fix_hstcfg, int, 0); 110*1da177e4SLinus Torvalds MODULE_PARM_DESC(fix_hstcfg, 111*1da177e4SLinus Torvalds "Fix config register. Needed on some boards (Force CPCI735)."); 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds static int piix4_transaction(void); 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds static unsigned short piix4_smba = 0; 116*1da177e4SLinus Torvalds static struct i2c_adapter piix4_adapter; 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds static struct dmi_system_id __devinitdata piix4_dmi_table[] = { 119*1da177e4SLinus Torvalds { 120*1da177e4SLinus Torvalds .ident = "IBM", 121*1da177e4SLinus Torvalds .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, 122*1da177e4SLinus Torvalds }, 123*1da177e4SLinus Torvalds { }, 124*1da177e4SLinus Torvalds }; 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, 127*1da177e4SLinus Torvalds const struct pci_device_id *id) 128*1da177e4SLinus Torvalds { 129*1da177e4SLinus Torvalds unsigned char temp; 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds /* match up the function */ 132*1da177e4SLinus Torvalds if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data) 133*1da177e4SLinus Torvalds return -ENODEV; 134*1da177e4SLinus Torvalds 135*1da177e4SLinus Torvalds dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev)); 136*1da177e4SLinus Torvalds 137*1da177e4SLinus Torvalds /* Don't access SMBus on IBM systems which get corrupted eeproms */ 138*1da177e4SLinus Torvalds if (dmi_check_system(piix4_dmi_table) && 139*1da177e4SLinus Torvalds PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) { 140*1da177e4SLinus Torvalds dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module " 141*1da177e4SLinus Torvalds "may corrupt your serial eeprom! Refusing to load " 142*1da177e4SLinus Torvalds "module!\n"); 143*1da177e4SLinus Torvalds return -EPERM; 144*1da177e4SLinus Torvalds } 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds /* Determine the address of the SMBus areas */ 147*1da177e4SLinus Torvalds if (force_addr) { 148*1da177e4SLinus Torvalds piix4_smba = force_addr & 0xfff0; 149*1da177e4SLinus Torvalds force = 0; 150*1da177e4SLinus Torvalds } else { 151*1da177e4SLinus Torvalds pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba); 152*1da177e4SLinus Torvalds piix4_smba &= 0xfff0; 153*1da177e4SLinus Torvalds if(piix4_smba == 0) { 154*1da177e4SLinus Torvalds dev_err(&PIIX4_dev->dev, "SMB base address " 155*1da177e4SLinus Torvalds "uninitialized - upgrade BIOS or use " 156*1da177e4SLinus Torvalds "force_addr=0xaddr\n"); 157*1da177e4SLinus Torvalds return -ENODEV; 158*1da177e4SLinus Torvalds } 159*1da177e4SLinus Torvalds } 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds if (!request_region(piix4_smba, SMBIOSIZE, "piix4-smbus")) { 162*1da177e4SLinus Torvalds dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n", 163*1da177e4SLinus Torvalds piix4_smba); 164*1da177e4SLinus Torvalds return -ENODEV; 165*1da177e4SLinus Torvalds } 166*1da177e4SLinus Torvalds 167*1da177e4SLinus Torvalds pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); 168*1da177e4SLinus Torvalds 169*1da177e4SLinus Torvalds /* Some BIOS will set up the chipset incorrectly and leave a register 170*1da177e4SLinus Torvalds in an undefined state (causing I2C to act very strangely). */ 171*1da177e4SLinus Torvalds if (temp & 0x02) { 172*1da177e4SLinus Torvalds if (fix_hstcfg) { 173*1da177e4SLinus Torvalds dev_info(&PIIX4_dev->dev, "Working around buggy BIOS " 174*1da177e4SLinus Torvalds "(I2C)\n"); 175*1da177e4SLinus Torvalds temp &= 0xfd; 176*1da177e4SLinus Torvalds pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp); 177*1da177e4SLinus Torvalds } else { 178*1da177e4SLinus Torvalds dev_info(&PIIX4_dev->dev, "Unusual config register " 179*1da177e4SLinus Torvalds "value\n"); 180*1da177e4SLinus Torvalds dev_info(&PIIX4_dev->dev, "Try using fix_hstcfg=1 if " 181*1da177e4SLinus Torvalds "you experience problems\n"); 182*1da177e4SLinus Torvalds } 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds /* If force_addr is set, we program the new address here. Just to make 186*1da177e4SLinus Torvalds sure, we disable the PIIX4 first. */ 187*1da177e4SLinus Torvalds if (force_addr) { 188*1da177e4SLinus Torvalds pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe); 189*1da177e4SLinus Torvalds pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba); 190*1da177e4SLinus Torvalds pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01); 191*1da177e4SLinus Torvalds dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to " 192*1da177e4SLinus Torvalds "new address %04x!\n", piix4_smba); 193*1da177e4SLinus Torvalds } else if ((temp & 1) == 0) { 194*1da177e4SLinus Torvalds if (force) { 195*1da177e4SLinus Torvalds /* This should never need to be done, but has been 196*1da177e4SLinus Torvalds * noted that many Dell machines have the SMBus 197*1da177e4SLinus Torvalds * interface on the PIIX4 disabled!? NOTE: This assumes 198*1da177e4SLinus Torvalds * I/O space and other allocations WERE done by the 199*1da177e4SLinus Torvalds * Bios! Don't complain if your hardware does weird 200*1da177e4SLinus Torvalds * things after enabling this. :') Check for Bios 201*1da177e4SLinus Torvalds * updates before resorting to this. 202*1da177e4SLinus Torvalds */ 203*1da177e4SLinus Torvalds pci_write_config_byte(PIIX4_dev, SMBHSTCFG, 204*1da177e4SLinus Torvalds temp | 1); 205*1da177e4SLinus Torvalds dev_printk(KERN_NOTICE, &PIIX4_dev->dev, 206*1da177e4SLinus Torvalds "WARNING: SMBus interface has been " 207*1da177e4SLinus Torvalds "FORCEFULLY ENABLED!\n"); 208*1da177e4SLinus Torvalds } else { 209*1da177e4SLinus Torvalds dev_err(&PIIX4_dev->dev, 210*1da177e4SLinus Torvalds "Host SMBus controller not enabled!\n"); 211*1da177e4SLinus Torvalds release_region(piix4_smba, SMBIOSIZE); 212*1da177e4SLinus Torvalds piix4_smba = 0; 213*1da177e4SLinus Torvalds return -ENODEV; 214*1da177e4SLinus Torvalds } 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds if ((temp & 0x0E) == 8) 218*1da177e4SLinus Torvalds dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n"); 219*1da177e4SLinus Torvalds else if ((temp & 0x0E) == 0) 220*1da177e4SLinus Torvalds dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n"); 221*1da177e4SLinus Torvalds else 222*1da177e4SLinus Torvalds dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration " 223*1da177e4SLinus Torvalds "(or code out of date)!\n"); 224*1da177e4SLinus Torvalds 225*1da177e4SLinus Torvalds pci_read_config_byte(PIIX4_dev, SMBREV, &temp); 226*1da177e4SLinus Torvalds dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp); 227*1da177e4SLinus Torvalds dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba); 228*1da177e4SLinus Torvalds 229*1da177e4SLinus Torvalds return 0; 230*1da177e4SLinus Torvalds } 231*1da177e4SLinus Torvalds 232*1da177e4SLinus Torvalds /* Another internally used function */ 233*1da177e4SLinus Torvalds static int piix4_transaction(void) 234*1da177e4SLinus Torvalds { 235*1da177e4SLinus Torvalds int temp; 236*1da177e4SLinus Torvalds int result = 0; 237*1da177e4SLinus Torvalds int timeout = 0; 238*1da177e4SLinus Torvalds 239*1da177e4SLinus Torvalds dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " 240*1da177e4SLinus Torvalds "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), 241*1da177e4SLinus Torvalds inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), 242*1da177e4SLinus Torvalds inb_p(SMBHSTDAT1)); 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds /* Make sure the SMBus host is ready to start transmitting */ 245*1da177e4SLinus Torvalds if ((temp = inb_p(SMBHSTSTS)) != 0x00) { 246*1da177e4SLinus Torvalds dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " 247*1da177e4SLinus Torvalds "Resetting... \n", temp); 248*1da177e4SLinus Torvalds outb_p(temp, SMBHSTSTS); 249*1da177e4SLinus Torvalds if ((temp = inb_p(SMBHSTSTS)) != 0x00) { 250*1da177e4SLinus Torvalds dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); 251*1da177e4SLinus Torvalds return -1; 252*1da177e4SLinus Torvalds } else { 253*1da177e4SLinus Torvalds dev_dbg(&piix4_adapter.dev, "Successfull!\n"); 254*1da177e4SLinus Torvalds } 255*1da177e4SLinus Torvalds } 256*1da177e4SLinus Torvalds 257*1da177e4SLinus Torvalds /* start the transaction by setting bit 6 */ 258*1da177e4SLinus Torvalds outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ 261*1da177e4SLinus Torvalds do { 262*1da177e4SLinus Torvalds msleep(1); 263*1da177e4SLinus Torvalds temp = inb_p(SMBHSTSTS); 264*1da177e4SLinus Torvalds } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); 265*1da177e4SLinus Torvalds 266*1da177e4SLinus Torvalds /* If the SMBus is still busy, we give up */ 267*1da177e4SLinus Torvalds if (timeout >= MAX_TIMEOUT) { 268*1da177e4SLinus Torvalds dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); 269*1da177e4SLinus Torvalds result = -1; 270*1da177e4SLinus Torvalds } 271*1da177e4SLinus Torvalds 272*1da177e4SLinus Torvalds if (temp & 0x10) { 273*1da177e4SLinus Torvalds result = -1; 274*1da177e4SLinus Torvalds dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); 275*1da177e4SLinus Torvalds } 276*1da177e4SLinus Torvalds 277*1da177e4SLinus Torvalds if (temp & 0x08) { 278*1da177e4SLinus Torvalds result = -1; 279*1da177e4SLinus Torvalds dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " 280*1da177e4SLinus Torvalds "locked until next hard reset. (sorry!)\n"); 281*1da177e4SLinus Torvalds /* Clock stops and slave is stuck in mid-transmission */ 282*1da177e4SLinus Torvalds } 283*1da177e4SLinus Torvalds 284*1da177e4SLinus Torvalds if (temp & 0x04) { 285*1da177e4SLinus Torvalds result = -1; 286*1da177e4SLinus Torvalds dev_dbg(&piix4_adapter.dev, "Error: no response!\n"); 287*1da177e4SLinus Torvalds } 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds if (inb_p(SMBHSTSTS) != 0x00) 290*1da177e4SLinus Torvalds outb_p(inb(SMBHSTSTS), SMBHSTSTS); 291*1da177e4SLinus Torvalds 292*1da177e4SLinus Torvalds if ((temp = inb_p(SMBHSTSTS)) != 0x00) { 293*1da177e4SLinus Torvalds dev_err(&piix4_adapter.dev, "Failed reset at end of " 294*1da177e4SLinus Torvalds "transaction (%02x)\n", temp); 295*1da177e4SLinus Torvalds } 296*1da177e4SLinus Torvalds dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " 297*1da177e4SLinus Torvalds "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), 298*1da177e4SLinus Torvalds inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), 299*1da177e4SLinus Torvalds inb_p(SMBHSTDAT1)); 300*1da177e4SLinus Torvalds return result; 301*1da177e4SLinus Torvalds } 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds /* Return -1 on error. */ 304*1da177e4SLinus Torvalds static s32 piix4_access(struct i2c_adapter * adap, u16 addr, 305*1da177e4SLinus Torvalds unsigned short flags, char read_write, 306*1da177e4SLinus Torvalds u8 command, int size, union i2c_smbus_data * data) 307*1da177e4SLinus Torvalds { 308*1da177e4SLinus Torvalds int i, len; 309*1da177e4SLinus Torvalds 310*1da177e4SLinus Torvalds switch (size) { 311*1da177e4SLinus Torvalds case I2C_SMBUS_PROC_CALL: 312*1da177e4SLinus Torvalds dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); 313*1da177e4SLinus Torvalds return -1; 314*1da177e4SLinus Torvalds case I2C_SMBUS_QUICK: 315*1da177e4SLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 316*1da177e4SLinus Torvalds SMBHSTADD); 317*1da177e4SLinus Torvalds size = PIIX4_QUICK; 318*1da177e4SLinus Torvalds break; 319*1da177e4SLinus Torvalds case I2C_SMBUS_BYTE: 320*1da177e4SLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 321*1da177e4SLinus Torvalds SMBHSTADD); 322*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 323*1da177e4SLinus Torvalds outb_p(command, SMBHSTCMD); 324*1da177e4SLinus Torvalds size = PIIX4_BYTE; 325*1da177e4SLinus Torvalds break; 326*1da177e4SLinus Torvalds case I2C_SMBUS_BYTE_DATA: 327*1da177e4SLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 328*1da177e4SLinus Torvalds SMBHSTADD); 329*1da177e4SLinus Torvalds outb_p(command, SMBHSTCMD); 330*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 331*1da177e4SLinus Torvalds outb_p(data->byte, SMBHSTDAT0); 332*1da177e4SLinus Torvalds size = PIIX4_BYTE_DATA; 333*1da177e4SLinus Torvalds break; 334*1da177e4SLinus Torvalds case I2C_SMBUS_WORD_DATA: 335*1da177e4SLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 336*1da177e4SLinus Torvalds SMBHSTADD); 337*1da177e4SLinus Torvalds outb_p(command, SMBHSTCMD); 338*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) { 339*1da177e4SLinus Torvalds outb_p(data->word & 0xff, SMBHSTDAT0); 340*1da177e4SLinus Torvalds outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); 341*1da177e4SLinus Torvalds } 342*1da177e4SLinus Torvalds size = PIIX4_WORD_DATA; 343*1da177e4SLinus Torvalds break; 344*1da177e4SLinus Torvalds case I2C_SMBUS_BLOCK_DATA: 345*1da177e4SLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 346*1da177e4SLinus Torvalds SMBHSTADD); 347*1da177e4SLinus Torvalds outb_p(command, SMBHSTCMD); 348*1da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) { 349*1da177e4SLinus Torvalds len = data->block[0]; 350*1da177e4SLinus Torvalds if (len < 0) 351*1da177e4SLinus Torvalds len = 0; 352*1da177e4SLinus Torvalds if (len > 32) 353*1da177e4SLinus Torvalds len = 32; 354*1da177e4SLinus Torvalds outb_p(len, SMBHSTDAT0); 355*1da177e4SLinus Torvalds i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ 356*1da177e4SLinus Torvalds for (i = 1; i <= len; i++) 357*1da177e4SLinus Torvalds outb_p(data->block[i], SMBBLKDAT); 358*1da177e4SLinus Torvalds } 359*1da177e4SLinus Torvalds size = PIIX4_BLOCK_DATA; 360*1da177e4SLinus Torvalds break; 361*1da177e4SLinus Torvalds } 362*1da177e4SLinus Torvalds 363*1da177e4SLinus Torvalds outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); 364*1da177e4SLinus Torvalds 365*1da177e4SLinus Torvalds if (piix4_transaction()) /* Error in transaction */ 366*1da177e4SLinus Torvalds return -1; 367*1da177e4SLinus Torvalds 368*1da177e4SLinus Torvalds if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) 369*1da177e4SLinus Torvalds return 0; 370*1da177e4SLinus Torvalds 371*1da177e4SLinus Torvalds 372*1da177e4SLinus Torvalds switch (size) { 373*1da177e4SLinus Torvalds case PIIX4_BYTE: /* Where is the result put? I assume here it is in 374*1da177e4SLinus Torvalds SMBHSTDAT0 but it might just as well be in the 375*1da177e4SLinus Torvalds SMBHSTCMD. No clue in the docs */ 376*1da177e4SLinus Torvalds 377*1da177e4SLinus Torvalds data->byte = inb_p(SMBHSTDAT0); 378*1da177e4SLinus Torvalds break; 379*1da177e4SLinus Torvalds case PIIX4_BYTE_DATA: 380*1da177e4SLinus Torvalds data->byte = inb_p(SMBHSTDAT0); 381*1da177e4SLinus Torvalds break; 382*1da177e4SLinus Torvalds case PIIX4_WORD_DATA: 383*1da177e4SLinus Torvalds data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); 384*1da177e4SLinus Torvalds break; 385*1da177e4SLinus Torvalds case PIIX4_BLOCK_DATA: 386*1da177e4SLinus Torvalds data->block[0] = inb_p(SMBHSTDAT0); 387*1da177e4SLinus Torvalds i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ 388*1da177e4SLinus Torvalds for (i = 1; i <= data->block[0]; i++) 389*1da177e4SLinus Torvalds data->block[i] = inb_p(SMBBLKDAT); 390*1da177e4SLinus Torvalds break; 391*1da177e4SLinus Torvalds } 392*1da177e4SLinus Torvalds return 0; 393*1da177e4SLinus Torvalds } 394*1da177e4SLinus Torvalds 395*1da177e4SLinus Torvalds static u32 piix4_func(struct i2c_adapter *adapter) 396*1da177e4SLinus Torvalds { 397*1da177e4SLinus Torvalds return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 398*1da177e4SLinus Torvalds I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 399*1da177e4SLinus Torvalds I2C_FUNC_SMBUS_BLOCK_DATA; 400*1da177e4SLinus Torvalds } 401*1da177e4SLinus Torvalds 402*1da177e4SLinus Torvalds static struct i2c_algorithm smbus_algorithm = { 403*1da177e4SLinus Torvalds .name = "Non-I2C SMBus adapter", 404*1da177e4SLinus Torvalds .id = I2C_ALGO_SMBUS, 405*1da177e4SLinus Torvalds .smbus_xfer = piix4_access, 406*1da177e4SLinus Torvalds .functionality = piix4_func, 407*1da177e4SLinus Torvalds }; 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds static struct i2c_adapter piix4_adapter = { 410*1da177e4SLinus Torvalds .owner = THIS_MODULE, 411*1da177e4SLinus Torvalds .class = I2C_CLASS_HWMON, 412*1da177e4SLinus Torvalds .algo = &smbus_algorithm, 413*1da177e4SLinus Torvalds .name = "unset", 414*1da177e4SLinus Torvalds }; 415*1da177e4SLinus Torvalds 416*1da177e4SLinus Torvalds static struct pci_device_id piix4_ids[] = { 417*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), 418*1da177e4SLinus Torvalds .driver_data = 3 }, 419*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), 420*1da177e4SLinus Torvalds .driver_data = 0 }, 421*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), 422*1da177e4SLinus Torvalds .driver_data = 0 }, 423*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6), 424*1da177e4SLinus Torvalds .driver_data = 0 }, 425*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3), 426*1da177e4SLinus Torvalds .driver_data = 3 }, 427*1da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3), 428*1da177e4SLinus Torvalds .driver_data = 0 }, 429*1da177e4SLinus Torvalds { 0, } 430*1da177e4SLinus Torvalds }; 431*1da177e4SLinus Torvalds 432*1da177e4SLinus Torvalds MODULE_DEVICE_TABLE (pci, piix4_ids); 433*1da177e4SLinus Torvalds 434*1da177e4SLinus Torvalds static int __devinit piix4_probe(struct pci_dev *dev, 435*1da177e4SLinus Torvalds const struct pci_device_id *id) 436*1da177e4SLinus Torvalds { 437*1da177e4SLinus Torvalds int retval; 438*1da177e4SLinus Torvalds 439*1da177e4SLinus Torvalds retval = piix4_setup(dev, id); 440*1da177e4SLinus Torvalds if (retval) 441*1da177e4SLinus Torvalds return retval; 442*1da177e4SLinus Torvalds 443*1da177e4SLinus Torvalds /* set up the driverfs linkage to our parent device */ 444*1da177e4SLinus Torvalds piix4_adapter.dev.parent = &dev->dev; 445*1da177e4SLinus Torvalds 446*1da177e4SLinus Torvalds snprintf(piix4_adapter.name, I2C_NAME_SIZE, 447*1da177e4SLinus Torvalds "SMBus PIIX4 adapter at %04x", piix4_smba); 448*1da177e4SLinus Torvalds 449*1da177e4SLinus Torvalds if ((retval = i2c_add_adapter(&piix4_adapter))) { 450*1da177e4SLinus Torvalds dev_err(&dev->dev, "Couldn't register adapter!\n"); 451*1da177e4SLinus Torvalds release_region(piix4_smba, SMBIOSIZE); 452*1da177e4SLinus Torvalds piix4_smba = 0; 453*1da177e4SLinus Torvalds } 454*1da177e4SLinus Torvalds 455*1da177e4SLinus Torvalds return retval; 456*1da177e4SLinus Torvalds } 457*1da177e4SLinus Torvalds 458*1da177e4SLinus Torvalds static void __devexit piix4_remove(struct pci_dev *dev) 459*1da177e4SLinus Torvalds { 460*1da177e4SLinus Torvalds if (piix4_smba) { 461*1da177e4SLinus Torvalds i2c_del_adapter(&piix4_adapter); 462*1da177e4SLinus Torvalds release_region(piix4_smba, SMBIOSIZE); 463*1da177e4SLinus Torvalds piix4_smba = 0; 464*1da177e4SLinus Torvalds } 465*1da177e4SLinus Torvalds } 466*1da177e4SLinus Torvalds 467*1da177e4SLinus Torvalds static struct pci_driver piix4_driver = { 468*1da177e4SLinus Torvalds .name = "piix4_smbus", 469*1da177e4SLinus Torvalds .id_table = piix4_ids, 470*1da177e4SLinus Torvalds .probe = piix4_probe, 471*1da177e4SLinus Torvalds .remove = __devexit_p(piix4_remove), 472*1da177e4SLinus Torvalds }; 473*1da177e4SLinus Torvalds 474*1da177e4SLinus Torvalds static int __init i2c_piix4_init(void) 475*1da177e4SLinus Torvalds { 476*1da177e4SLinus Torvalds return pci_register_driver(&piix4_driver); 477*1da177e4SLinus Torvalds } 478*1da177e4SLinus Torvalds 479*1da177e4SLinus Torvalds static void __exit i2c_piix4_exit(void) 480*1da177e4SLinus Torvalds { 481*1da177e4SLinus Torvalds pci_unregister_driver(&piix4_driver); 482*1da177e4SLinus Torvalds } 483*1da177e4SLinus Torvalds 484*1da177e4SLinus Torvalds MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " 485*1da177e4SLinus Torvalds "Philip Edelbrock <phil@netroedge.com>"); 486*1da177e4SLinus Torvalds MODULE_DESCRIPTION("PIIX4 SMBus driver"); 487*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 488*1da177e4SLinus Torvalds 489*1da177e4SLinus Torvalds module_init(i2c_piix4_init); 490*1da177e4SLinus Torvalds module_exit(i2c_piix4_exit); 491