Path: blob/master/drivers/i2c/busses/i2c-nforce2.c
15111 views
/*1SMBus driver for nVidia nForce2 MCP23Added nForce3 Pro 150 Thomas Leibold <[email protected]>,4Ported to 2.5 Patrick Dreker <[email protected]>,5Copyright (c) 2003 Hans-Frieder Vogt <[email protected]>,6Based on7SMBus 2.0 driver for AMD-8111 IO-Hub8Copyright (c) 2002 Vojtech Pavlik910This program is free software; you can redistribute it and/or modify11it under the terms of the GNU General Public License as published by12the Free Software Foundation; either version 2 of the License, or13(at your option) any later version.1415This program is distributed in the hope that it will be useful,16but WITHOUT ANY WARRANTY; without even the implied warranty of17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the18GNU General Public License for more details.1920You should have received a copy of the GNU General Public License21along with this program; if not, write to the Free Software22Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.23*/2425/*26SUPPORTED DEVICES PCI ID27nForce2 MCP 006428nForce2 Ultra 400 MCP 008429nForce3 Pro150 MCP 00D430nForce3 250Gb MCP 00E431nForce4 MCP 005232nForce4 MCP-04 003433nForce MCP51 026434nForce MCP55 036835nForce MCP61 03EB36nForce MCP65 044637nForce MCP67 054238nForce MCP73 07D839nForce MCP78S 075240nForce MCP79 0AA24142This driver supports the 2 SMBuses that are included in the MCP of the43nForce2/3/4/5xx chipsets.44*/4546/* Note: we assume there can only be one nForce2, with two SMBus interfaces */4748#include <linux/module.h>49#include <linux/pci.h>50#include <linux/kernel.h>51#include <linux/stddef.h>52#include <linux/ioport.h>53#include <linux/init.h>54#include <linux/i2c.h>55#include <linux/delay.h>56#include <linux/dmi.h>57#include <linux/acpi.h>58#include <linux/slab.h>59#include <linux/io.h>6061MODULE_LICENSE("GPL");62MODULE_AUTHOR ("Hans-Frieder Vogt <[email protected]>");63MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");646566struct nforce2_smbus {67struct i2c_adapter adapter;68int base;69int size;70int blockops;71int can_abort;72};737475/*76* nVidia nForce2 SMBus control register definitions77* (Newer incarnations use standard BARs 4 and 5 instead)78*/79#define NFORCE_PCI_SMB1 0x5080#define NFORCE_PCI_SMB2 0x54818283/*84* ACPI 2.0 chapter 13 SMBus 2.0 EC register model85*/86#define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */87#define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */88#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */89#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */90#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */91#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data92bytes */93#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to94check the status of95the abort command */96#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */9798#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that99abort succeeded */100#define NVIDIA_SMB_CTRL_ABORT 0x20101#define NVIDIA_SMB_STS_DONE 0x80102#define NVIDIA_SMB_STS_ALRM 0x40103#define NVIDIA_SMB_STS_RES 0x20104#define NVIDIA_SMB_STS_STATUS 0x1f105106#define NVIDIA_SMB_PRTCL_WRITE 0x00107#define NVIDIA_SMB_PRTCL_READ 0x01108#define NVIDIA_SMB_PRTCL_QUICK 0x02109#define NVIDIA_SMB_PRTCL_BYTE 0x04110#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06111#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08112#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a113#define NVIDIA_SMB_PRTCL_PEC 0x80114115/* Misc definitions */116#define MAX_TIMEOUT 100117118/* We disable the second SMBus channel on these boards */119static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = {120{121.ident = "DFI Lanparty NF4 Expert",122.matches = {123DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"),124DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"),125},126},127{ }128};129130static struct pci_driver nforce2_driver;131132/* For multiplexing support, we need a global reference to the 1st133SMBus channel */134#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE135struct i2c_adapter *nforce2_smbus;136EXPORT_SYMBOL_GPL(nforce2_smbus);137138static void nforce2_set_reference(struct i2c_adapter *adap)139{140nforce2_smbus = adap;141}142#else143static inline void nforce2_set_reference(struct i2c_adapter *adap) { }144#endif145146static void nforce2_abort(struct i2c_adapter *adap)147{148struct nforce2_smbus *smbus = adap->algo_data;149int timeout = 0;150unsigned char temp;151152dev_dbg(&adap->dev, "Aborting current transaction\n");153154outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);155do {156msleep(1);157temp = inb_p(NVIDIA_SMB_STATUS_ABRT);158} while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&159(timeout++ < MAX_TIMEOUT));160if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))161dev_err(&adap->dev, "Can't reset the smbus\n");162outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);163}164165static int nforce2_check_status(struct i2c_adapter *adap)166{167struct nforce2_smbus *smbus = adap->algo_data;168int timeout = 0;169unsigned char temp;170171do {172msleep(1);173temp = inb_p(NVIDIA_SMB_STS);174} while ((!temp) && (timeout++ < MAX_TIMEOUT));175176if (timeout > MAX_TIMEOUT) {177dev_dbg(&adap->dev, "SMBus Timeout!\n");178if (smbus->can_abort)179nforce2_abort(adap);180return -ETIMEDOUT;181}182if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {183dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);184return -EIO;185}186return 0;187}188189/* Return negative errno on error */190static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,191unsigned short flags, char read_write,192u8 command, int size, union i2c_smbus_data * data)193{194struct nforce2_smbus *smbus = adap->algo_data;195unsigned char protocol, pec;196u8 len;197int i, status;198199protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :200NVIDIA_SMB_PRTCL_WRITE;201pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;202203switch (size) {204205case I2C_SMBUS_QUICK:206protocol |= NVIDIA_SMB_PRTCL_QUICK;207read_write = I2C_SMBUS_WRITE;208break;209210case I2C_SMBUS_BYTE:211if (read_write == I2C_SMBUS_WRITE)212outb_p(command, NVIDIA_SMB_CMD);213protocol |= NVIDIA_SMB_PRTCL_BYTE;214break;215216case I2C_SMBUS_BYTE_DATA:217outb_p(command, NVIDIA_SMB_CMD);218if (read_write == I2C_SMBUS_WRITE)219outb_p(data->byte, NVIDIA_SMB_DATA);220protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;221break;222223case I2C_SMBUS_WORD_DATA:224outb_p(command, NVIDIA_SMB_CMD);225if (read_write == I2C_SMBUS_WRITE) {226outb_p(data->word, NVIDIA_SMB_DATA);227outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);228}229protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;230break;231232case I2C_SMBUS_BLOCK_DATA:233outb_p(command, NVIDIA_SMB_CMD);234if (read_write == I2C_SMBUS_WRITE) {235len = data->block[0];236if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {237dev_err(&adap->dev,238"Transaction failed "239"(requested block size: %d)\n",240len);241return -EINVAL;242}243outb_p(len, NVIDIA_SMB_BCNT);244for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)245outb_p(data->block[i + 1],246NVIDIA_SMB_DATA+i);247}248protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;249break;250251default:252dev_err(&adap->dev, "Unsupported transaction %d\n", size);253return -EOPNOTSUPP;254}255256outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);257outb_p(protocol, NVIDIA_SMB_PRTCL);258259status = nforce2_check_status(adap);260if (status)261return status;262263if (read_write == I2C_SMBUS_WRITE)264return 0;265266switch (size) {267268case I2C_SMBUS_BYTE:269case I2C_SMBUS_BYTE_DATA:270data->byte = inb_p(NVIDIA_SMB_DATA);271break;272273case I2C_SMBUS_WORD_DATA:274data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);275break;276277case I2C_SMBUS_BLOCK_DATA:278len = inb_p(NVIDIA_SMB_BCNT);279if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {280dev_err(&adap->dev, "Transaction failed "281"(received block size: 0x%02x)\n",282len);283return -EPROTO;284}285for (i = 0; i < len; i++)286data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);287data->block[0] = len;288break;289}290291return 0;292}293294295static u32 nforce2_func(struct i2c_adapter *adapter)296{297/* other functionality might be possible, but is not tested */298return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |299I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |300I2C_FUNC_SMBUS_PEC |301(((struct nforce2_smbus*)adapter->algo_data)->blockops ?302I2C_FUNC_SMBUS_BLOCK_DATA : 0);303}304305static struct i2c_algorithm smbus_algorithm = {306.smbus_xfer = nforce2_access,307.functionality = nforce2_func,308};309310311static const struct pci_device_id nforce2_ids[] = {312{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },313{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },314{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },315{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },316{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },317{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },318{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },319{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },320{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },321{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },322{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS) },323{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS) },324{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS) },325{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS) },326{ 0 }327};328329MODULE_DEVICE_TABLE (pci, nforce2_ids);330331332static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,333int alt_reg, struct nforce2_smbus *smbus, const char *name)334{335int error;336337smbus->base = pci_resource_start(dev, bar);338if (smbus->base) {339smbus->size = pci_resource_len(dev, bar);340} else {341/* Older incarnations of the device used non-standard BARs */342u16 iobase;343344if (pci_read_config_word(dev, alt_reg, &iobase)345!= PCIBIOS_SUCCESSFUL) {346dev_err(&dev->dev, "Error reading PCI config for %s\n",347name);348return -EIO;349}350351smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;352smbus->size = 64;353}354355error = acpi_check_region(smbus->base, smbus->size,356nforce2_driver.name);357if (error)358return -1;359360if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {361dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",362smbus->base, smbus->base+smbus->size-1, name);363return -EBUSY;364}365smbus->adapter.owner = THIS_MODULE;366smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;367smbus->adapter.algo = &smbus_algorithm;368smbus->adapter.algo_data = smbus;369smbus->adapter.dev.parent = &dev->dev;370snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),371"SMBus nForce2 adapter at %04x", smbus->base);372373error = i2c_add_adapter(&smbus->adapter);374if (error) {375dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");376release_region(smbus->base, smbus->size);377return error;378}379dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base);380return 0;381}382383384static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)385{386struct nforce2_smbus *smbuses;387int res1, res2;388389/* we support 2 SMBus adapters */390if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL)))391return -ENOMEM;392pci_set_drvdata(dev, smbuses);393394switch(dev->device) {395case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:396case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:397case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:398smbuses[0].blockops = 1;399smbuses[1].blockops = 1;400smbuses[0].can_abort = 1;401smbuses[1].can_abort = 1;402}403404/* SMBus adapter 1 */405res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");406if (res1 < 0)407smbuses[0].base = 0; /* to have a check value */408409/* SMBus adapter 2 */410if (dmi_check_system(nforce2_dmi_blacklist2)) {411dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n");412res2 = -EPERM;413smbuses[1].base = 0;414} else {415res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1],416"SMB2");417if (res2 < 0)418smbuses[1].base = 0; /* to have a check value */419}420421if ((res1 < 0) && (res2 < 0)) {422/* we did not find even one of the SMBuses, so we give up */423kfree(smbuses);424return -ENODEV;425}426427nforce2_set_reference(&smbuses[0].adapter);428return 0;429}430431432static void __devexit nforce2_remove(struct pci_dev *dev)433{434struct nforce2_smbus *smbuses = pci_get_drvdata(dev);435436nforce2_set_reference(NULL);437if (smbuses[0].base) {438i2c_del_adapter(&smbuses[0].adapter);439release_region(smbuses[0].base, smbuses[0].size);440}441if (smbuses[1].base) {442i2c_del_adapter(&smbuses[1].adapter);443release_region(smbuses[1].base, smbuses[1].size);444}445kfree(smbuses);446}447448static struct pci_driver nforce2_driver = {449.name = "nForce2_smbus",450.id_table = nforce2_ids,451.probe = nforce2_probe,452.remove = __devexit_p(nforce2_remove),453};454455static int __init nforce2_init(void)456{457return pci_register_driver(&nforce2_driver);458}459460static void __exit nforce2_exit(void)461{462pci_unregister_driver(&nforce2_driver);463}464465module_init(nforce2_init);466module_exit(nforce2_exit);467468469470