diff options
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 33 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-acorn.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-gpio.c | 12 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 249 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-iop3xx.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mpc.c | 26 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nforce2.c | 44 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pmcmsp.c | 653 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-powermac.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-rpx.c | 101 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-savage4.c | 21 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sis5595.c | 27 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-taos-evm.c | 330 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-viapro.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/scx200_acb.c | 16 |
19 files changed, 1302 insertions, 242 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c63bfa68e14..da1647869f9 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -207,6 +207,7 @@ config I2C_PIIX4 ATI IXP300 ATI IXP400 ATI SB600 + ATI SB700 Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 @@ -387,11 +388,6 @@ config I2C_PROSAVAGE This support is also available as a module. If so, the module will be called i2c-prosavage. -config I2C_RPXLITE - tristate "Embedded Planet RPX Lite/Classic support" - depends on RPXLITE || RPXCLASSIC - select I2C_ALGO8XX - config I2C_S3C2410 tristate "S3C2410 I2C Driver" depends on ARCH_S3C2410 @@ -509,6 +505,22 @@ config I2C_SIS96X This driver can also be built as a module. If so, the module will be called i2c-sis96x. +config I2C_TAOS_EVM + tristate "TAOS evaluation module" + depends on EXPERIMENTAL + select SERIO + select SERIO_SERPORT + default n + help + This supports TAOS evaluation modules on serial port. In order to + use this driver, you will need the inputattach tool, which is part + of the input-utils package. + + If unsure, say N. + + This support is also available as a module. If so, the module + will be called i2c-taos-evm. + config I2C_STUB tristate "I2C/SMBus Test Stub" depends on EXPERIMENTAL && m @@ -545,7 +557,7 @@ config I2C_VERSATILE will be called i2c-versatile. config I2C_ACORN - bool "Acorn IOC/IOMD I2C bus support" + tristate "Acorn IOC/IOMD I2C bus support" depends on ARCH_ACORN default y select I2C_ALGOBIT @@ -632,4 +644,13 @@ config I2C_PNX This driver can also be built as a module. If so, the module will be called i2c-pnx. +config I2C_PMCMSP + tristate "PMC MSP I2C TWI Controller" + depends on PMC_MSP + help + This driver supports the PMC TWI controller on MSP devices. + + This driver can also be built as module. If so, the module + will be called i2c-pmcmsp. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index b6a8037f1fe..5b752e4e191 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -31,10 +31,10 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o +obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o -obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o @@ -43,6 +43,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o +obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index 09bd7f40b90..7c2be3558a2 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -94,4 +94,4 @@ static int __init i2c_ioc_init(void) return i2c_bit_add_bus(&ioc_ops); } -__initcall(i2c_ioc_init); +module_init(i2c_ioc_init); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index a7dd54654a9..025f19423fa 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -63,14 +63,14 @@ static void i2c_gpio_setscl_val(void *data, int state) gpio_set_value(pdata->scl_pin, state); } -int i2c_gpio_getsda(void *data) +static int i2c_gpio_getsda(void *data) { struct i2c_gpio_platform_data *pdata = data; return gpio_get_value(pdata->sda_pin); } -int i2c_gpio_getscl(void *data) +static int i2c_gpio_getscl(void *data) { struct i2c_gpio_platform_data *pdata = data; @@ -142,7 +142,13 @@ static int __init i2c_gpio_probe(struct platform_device *pdev) adap->algo_data = bit_data; adap->dev.parent = &pdev->dev; - ret = i2c_bit_add_bus(adap); + /* + * If "dev->id" is negative we consider it as zero. + * The reason to do so is to avoid sysfs names that only make + * sense when there are multiple adapters. + */ + adap->nr = pdev->id >= 0 ? pdev->id : 0; + ret = i2c_bit_add_numbered_bus(adap); if (ret) goto err_add_bus; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 611b57192c9..8f5c686123b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -22,12 +22,12 @@ /* SUPPORTED DEVICES PCI ID - 82801AA 2413 - 82801AB 2423 - 82801BA 2443 - 82801CA/CAM 2483 - 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) - 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) + 82801AA 2413 + 82801AB 2423 + 82801BA 2443 + 82801CA/CAM 2483 + 82801DB 24C3 (HW PEC supported) + 82801EB 24D3 (HW PEC supported) 6300ESB 25A4 ICH6 266A ICH7 27DA @@ -74,6 +74,13 @@ #define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_I2C_EN 4 +/* Auxillary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC 1 +#define SMBAUXCTL_E32B 2 + +/* kill bit for SMBHSTCNT */ +#define SMBHSTCNT_KILL 2 + /* Other settings */ #define MAX_TIMEOUT 100 #define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ @@ -91,10 +98,15 @@ #define I801_START 0x40 #define I801_PEC_EN 0x80 /* ICH4 only */ - -static int i801_transaction(void); -static int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command, int hwpec); +/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE 0x80 +#define SMBHSTSTS_INUSE_STS 0x40 +#define SMBHSTSTS_SMBALERT_STS 0x20 +#define SMBHSTSTS_FAILED 0x10 +#define SMBHSTSTS_BUS_ERR 0x08 +#define SMBHSTSTS_DEV_ERR 0x04 +#define SMBHSTSTS_INTR 0x02 +#define SMBHSTSTS_HOST_BUSY 0x01 static unsigned long i801_smba; static unsigned char i801_original_hstcfg; @@ -102,7 +114,7 @@ static struct pci_driver i801_driver; static struct pci_dev *I801_dev; static int isich4; -static int i801_transaction(void) +static int i801_transaction(int xact) { int temp; int result = 0; @@ -127,33 +139,40 @@ static int i801_transaction(void) } } - outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); + /* the current contents of SMBHSTCNT can be overwritten, since PEC, + * INTREN, SMBSCMD are passed in xact */ + outb_p(xact | I801_START, SMBHSTCNT); /* We will always wait for a fraction of a second! */ do { msleep(1); temp = inb_p(SMBHSTSTS); - } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); + } while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); result = -1; + /* try to stop the current command */ + dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); + outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); + msleep(1); + outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); } - if (temp & 0x10) { + if (temp & SMBHSTSTS_FAILED) { result = -1; dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); } - if (temp & 0x08) { + if (temp & SMBHSTSTS_BUS_ERR) { result = -1; dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " "until next hard reset. (sorry!)\n"); /* Clock stops and slave is stuck in mid-transmission */ } - if (temp & 0x04) { + if (temp & SMBHSTSTS_DEV_ERR) { result = -1; dev_dbg(&I801_dev->dev, "Error: no response!\n"); } @@ -172,44 +191,70 @@ static int i801_transaction(void) return result; } -/* All-inclusive block transaction function */ -static int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command, int hwpec) +/* wait for INTR bit as advised by Intel */ +static void i801_wait_hwpec(void) +{ + int timeout = 0; + int temp; + + do { + msleep(1); + temp = inb_p(SMBHSTSTS); + } while ((!(temp & SMBHSTSTS_INTR)) + && (timeout++ < MAX_TIMEOUT)); + + if (timeout >= MAX_TIMEOUT) { + dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); + } + outb_p(temp, SMBHSTSTS); +} + +static int i801_block_transaction_by_block(union i2c_smbus_data *data, + char read_write, int hwpec) +{ + int i, len; + + inb_p(SMBHSTCNT); /* reset the data buffer index */ + + /* Use 32-byte buffer to process this transaction */ + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + outb_p(len, SMBHSTDAT0); + for (i = 0; i < len; i++) + outb_p(data->block[i+1], SMBBLKDAT); + } + + if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 | + I801_PEC_EN * hwpec)) + return -1; + + if (read_write == I2C_SMBUS_READ) { + len = inb_p(SMBHSTDAT0); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + return -1; + + data->block[0] = len; + for (i = 0; i < len; i++) + data->block[i + 1] = inb_p(SMBBLKDAT); + } + return 0; +} + +static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, + char read_write, int hwpec) { int i, len; int smbcmd; int temp; int result = 0; int timeout; - unsigned char hostc, errmask; + unsigned char errmask; - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (read_write == I2C_SMBUS_WRITE) { - /* set I2C_EN bit in configuration register */ - pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); - pci_write_config_byte(I801_dev, SMBHSTCFG, - hostc | SMBHSTCFG_I2C_EN); - } else { - dev_err(&I801_dev->dev, - "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); - return -1; - } - } + len = data->block[0]; if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 1) - len = 1; - if (len > 32) - len = 32; outb_p(len, SMBHSTDAT0); outb_p(data->block[1], SMBBLKDAT); - } else { - len = 32; /* max for reads */ - } - - if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) { - /* set 32 byte buffer */ } for (i = 1; i <= len; i++) { @@ -227,13 +272,13 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, /* Make sure the SMBus host is ready to start transmitting */ temp = inb_p(SMBHSTSTS); if (i == 1) { - /* Erronenous conditions before transaction: + /* Erronenous conditions before transaction: * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ - errmask=0x9f; + errmask = 0x9f; } else { - /* Erronenous conditions during transaction: + /* Erronenous conditions during transaction: * Failed, Bus_Err, Dev_Err, Intr */ - errmask=0x1e; + errmask = 0x1e; } if (temp & errmask) { dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " @@ -242,14 +287,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { dev_err(&I801_dev->dev, "Reset failed! (%02x)\n", temp); - result = -1; - goto END; + return -1; } - if (i != 1) { + if (i != 1) /* if die in middle of block transaction, fail */ - result = -1; - goto END; - } + return -1; } if (i == 1) @@ -261,33 +303,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, msleep(1); temp = inb_p(SMBHSTSTS); } - while ((!(temp & 0x80)) - && (timeout++ < MAX_TIMEOUT)); + while ((!(temp & SMBHSTSTS_BYTE_DONE)) + && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { + /* try to stop the current command */ + dev_dbg(&I801_dev->dev, "Terminating the current " + "operation\n"); + outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); + msleep(1); + outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), + SMBHSTCNT); result = -1; dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); } - if (temp & 0x10) { + if (temp & SMBHSTSTS_FAILED) { result = -1; dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); - } else if (temp & 0x08) { + } else if (temp & SMBHSTSTS_BUS_ERR) { result = -1; dev_err(&I801_dev->dev, "Bus collision!\n"); - } else if (temp & 0x04) { + } else if (temp & SMBHSTSTS_DEV_ERR) { result = -1; dev_dbg(&I801_dev->dev, "Error: no response!\n"); } if (i == 1 && read_write == I2C_SMBUS_READ) { len = inb_p(SMBHSTDAT0); - if (len < 1) - len = 1; - if (len > 32) - len = 32; + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + return -1; data->block[0] = len; } @@ -310,25 +357,58 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); if (result < 0) - goto END; + return result; } + return result; +} - if (hwpec) { - /* wait for INTR bit as advised by Intel */ - timeout = 0; - do { - msleep(1); - temp = inb_p(SMBHSTSTS); - } while ((!(temp & 0x02)) - && (timeout++ < MAX_TIMEOUT)); +static int i801_set_block_buffer_mode(void) +{ + outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL); + if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0) + return -1; + return 0; +} - if (timeout >= MAX_TIMEOUT) { - dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); +/* Block transaction function */ +static int i801_block_transaction(union i2c_smbus_data *data, char read_write, + int command, int hwpec) +{ + int result = 0; + unsigned char hostc; + + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(I801_dev, SMBHSTCFG, + hostc | SMBHSTCFG_I2C_EN); + } else { + dev_err(&I801_dev->dev, + "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + return -1; } - outb_p(temp, SMBHSTSTS); } - result = 0; -END: + + if (read_write == I2C_SMBUS_WRITE) { + if (data->block[0] < 1) + data->block[0] = 1; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + } else { + data->block[0] = 32; /* max for reads */ + } + + if (isich4 && i801_set_block_buffer_mode() == 0 ) + result = i801_block_transaction_by_block(data, read_write, + hwpec); + else + result = i801_block_transaction_byte_by_byte(data, read_write, + hwpec); + + if (result == 0 && hwpec) + i801_wait_hwpec(); + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); @@ -393,19 +473,22 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, return -1; } - outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */ + if (hwpec) /* enable/disable hardware PEC */ + outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL); + else + outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL); if(block) ret = i801_block_transaction(data, read_write, size, hwpec); - else { - outb_p(xact | ENABLE_INT9, SMBHSTCNT); - ret = i801_transaction(); - } + else + ret = i801_transaction(xact | ENABLE_INT9); /* Some BIOSes don't like it when PEC is enabled at reboot or resume - time, so we forcibly disable it after every transaction. */ + time, so we forcibly disable it after every transaction. Turn off + E32B for the same reason. */ if (hwpec) - outb_p(0, SMBAUXCTL); + outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), + SMBAUXCTL); if(block) return ret; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 90e2d9350c1..440342bc62e 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -491,6 +491,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) new_adapter->id = I2C_HW_IOP3XX; new_adapter->owner = THIS_MODULE; new_adapter->dev.parent = &pdev->dev; + new_adapter->nr = pdev->id; /* * Default values...should these come in from board code? @@ -508,7 +509,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, new_adapter); new_adapter->algo_data = adapter_data; - i2c_add_adapter(new_adapter); + i2c_add_numbered_adapter(new_adapter); return 0; diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index c6b6898592b..851c3ed513d 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -74,6 +74,25 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id) return IRQ_HANDLED; } +/* Sometimes 9th clock pulse isn't generated, and slave doesn't release + * the bus, because it wants to send ACK. + * Following sequence of enabling/disabling and sending start/stop generates + * the pulse, so it's all OK. + */ +static void mpc_i2c_fixup(struct mpc_i2c *i2c) +{ + writeccr(i2c, 0); + udelay(30); + writeccr(i2c, CCR_MEN); + udelay(30); + writeccr(i2c, CCR_MSTA | CCR_MTX); + udelay(30); + writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN); + udelay(30); + writeccr(i2c, CCR_MEN); + udelay(30); +} + static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) { unsigned long orig_jiffies = jiffies; @@ -153,6 +172,7 @@ static void mpc_i2c_start(struct mpc_i2c *i2c) static void mpc_i2c_stop(struct mpc_i2c *i2c) { writeccr(i2c, CCR_MEN); + writeccr(i2c, 0); } static int mpc_write(struct mpc_i2c *i2c, int target, @@ -245,6 +265,9 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) } if (time_after(jiffies, orig_jiffies + HZ)) { pr_debug("I2C: timeout\n"); + if (readb(i2c->base + MPC_I2C_SR) == + (CSR_MCF | CSR_MBB | CSR_RXAK)) + mpc_i2c_fixup(i2c); return -EIO; } schedule(); @@ -327,9 +350,10 @@ static int fsl_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); i2c->adap = mpc_ops; + i2c->adap.nr = pdev->id; i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; - if ((result = i2c_add_adapter(&i2c->adap)) < 0) { + if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) { printk(KERN_ERR "i2c-mpc - failed to add adapter\n"); goto fail_add; } diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a55b3335d1b..251154ae5d9 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -527,6 +527,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) drv_data->adapter.class = I2C_CLASS_HWMON; drv_data->adapter.timeout = pdata->timeout; drv_data->adapter.retries = pdata->retries; + drv_data->adapter.nr = pd->id; platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); @@ -539,7 +540,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) drv_data->irq); rc = -EINVAL; goto exit_unmap_regs; - } else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { + } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { dev_err(&drv_data->adapter.dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); goto exit_free_irq; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 3cd0d63e7b5..c48140f782d 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -61,6 +61,7 @@ struct nforce2_smbus { struct i2c_adapter adapter; int base; int size; + int blockops; }; @@ -80,6 +81,8 @@ struct nforce2_smbus { #define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ #define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ +#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data + bytes */ #define NVIDIA_SMB_STS_DONE 0x80 #define NVIDIA_SMB_STS_ALRM 0x40 @@ -92,6 +95,7 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_BYTE 0x04 #define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 #define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 +#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a #define NVIDIA_SMB_PRTCL_PEC 0x80 static struct pci_driver nforce2_driver; @@ -103,6 +107,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, { struct nforce2_smbus *smbus = adap->algo_data; unsigned char protocol, pec, temp; + u8 len; + int i; protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE; @@ -137,6 +143,25 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; break; + case I2C_SMBUS_BLOCK_DATA: + outb_p(command, NVIDIA_SMB_CMD); + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) { + dev_err(&adap->dev, + "Transaction failed " + "(requested block size: %d)\n", + len); + return -1; + } + outb_p(len, NVIDIA_SMB_BCNT); + for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) + outb_p(data->block[i + 1], + NVIDIA_SMB_DATA+i); + } + protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; + break; + default: dev_err(&adap->dev, "Unsupported transaction %d\n", size); return -1; @@ -174,6 +199,14 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_WORD_DATA: data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); break; + + case I2C_SMBUS_BLOCK_DATA: + len = inb_p(NVIDIA_SMB_BCNT); + len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); + for (i = 0; i < len; i++) + data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); + data->block[0] = len; + break; } return 0; @@ -184,7 +217,9 @@ static u32 nforce2_func(struct i2c_adapter *adapter) { /* other functionality might be possible, but is not tested */ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA; + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + (((struct nforce2_smbus*)adapter->algo_data)->blockops ? + I2C_FUNC_SMBUS_BLOCK_DATA : 0); } static struct i2c_algorithm smbus_algorithm = { @@ -268,6 +303,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ return -ENOMEM; pci_set_drvdata(dev, smbuses); + switch(dev->device) { + case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: + case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: + smbuses[0].blockops = 1; + smbuses[1].blockops = 1; + } + /* SMBus adapter 1 */ res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); if (res1 < 0) { diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 5a52bf5e3fb..debc76cd216 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -23,7 +23,7 @@ Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000 - ATI IXP200, IXP300, IXP400, SB600 + ATI IXP200, IXP300, IXP400, SB600, SB700 SMSC Victory66 Note: we assume there can only be one device, with one SMBus interface. @@ -399,6 +399,8 @@ static struct pci_device_id piix4_ids[] = { .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS), .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS), + .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c new file mode 100644 index 00000000000..17cecf1ea79 --- /dev/null +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -0,0 +1,653 @@ +/* + * Specific bus support for PMC-TWI compliant implementation on MSP71xx. + * + * Copyright 2005-2007 PMC-Sierra, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/completion.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <asm/io.h> + +#define DRV_NAME "pmcmsptwi" + +#define MSP_TWI_SF_CLK_REG_OFFSET 0x00 +#define MSP_TWI_HS_CLK_REG_OFFSET 0x04 +#define MSP_TWI_CFG_REG_OFFSET 0x08 +#define MSP_TWI_CMD_REG_OFFSET 0x0c +#define MSP_TWI_ADD_REG_OFFSET 0x10 +#define MSP_TWI_DAT_0_REG_OFFSET 0x14 +#define MSP_TWI_DAT_1_REG_OFFSET 0x18 +#define MSP_TWI_INT_STS_REG_OFFSET 0x1c +#define MSP_TWI_INT_MSK_REG_OFFSET 0x20 +#define MSP_TWI_BUSY_REG_OFFSET 0x24 + +#define MSP_TWI_INT_STS_DONE (1 << 0) +#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1) +#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2) +#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3) +#define MSP_TWI_INT_STS_BUSY (1 << 4) +#define MSP_TWI_INT_STS_ALL 0x1f + +#define MSP_MAX_BYTES_PER_RW 8 +#define MSP_MAX_POLL 5 +#define MSP_POLL_DELAY 10 +#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY) + +/* IO Operation macros */ +#define pmcmsptwi_readl __raw_readl +#define pmcmsptwi_writel __raw_writel + +/* TWI command type */ +enum pmcmsptwi_cmd_type { + MSP_TWI_CMD_WRITE = 0, /* Write only */ + MSP_TWI_CMD_READ = 1, /* Read only */ + MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */ +}; + +/* The possible results of the xferCmd */ +enum pmcmsptwi_xfer_result { + MSP_TWI_XFER_OK = 0, + MSP_TWI_XFER_TIMEOUT, + MSP_TWI_XFER_BUSY, + MSP_TWI_XFER_DATA_COLLISION, + MSP_TWI_XFER_NO_RESPONSE, + MSP_TWI_XFER_LOST_ARBITRATION, +}; + +/* Corresponds to a PMCTWI clock configuration register */ +struct pmcmsptwi_clock { + u8 filter; /* Bits 15:12, default = 0x03 */ + u16 clock; /* Bits 9:0, default = 0x001f */ +}; + +struct pmcmsptwi_clockcfg { + struct pmcmsptwi_clock standard; /* The standard/fast clock config */ + struct pmcmsptwi_clock highspeed; /* The highspeed clock config */ +}; + +/* Corresponds to the main TWI configuration register */ +struct pmcmsptwi_cfg { + u8 arbf; /* Bits 15:12, default=0x03 */ + u8 nak; /* Bits 11:8, default=0x03 */ + u8 add10; /* Bit 7, default=0x00 */ + u8 mst_code; /* Bits 6:4, default=0x00 */ + u8 arb; /* Bit 1, default=0x01 */ + u8 highspeed; /* Bit 0, default=0x00 */ +}; + +/* A single pmctwi command to issue */ +struct pmcmsptwi_cmd { + u16 addr; /* The slave address (7 or 10 bits) */ + enum pmcmsptwi_cmd_type type; /* The command type */ + u8 write_len; /* Number of bytes in the write buffer */ + u8 read_len; /* Number of bytes in the read buffer */ + u8 *write_data; /* Buffer of characters to send */ + u8 *read_data; /* Buffer to fill with incoming data */ +}; + +/* The private data */ +struct pmcmsptwi_data { + void __iomem *iobase; /* iomapped base for IO */ + int irq; /* IRQ to use (0 disables) */ + struct completion wait; /* Completion for xfer */ + struct mutex lock; /* Used for threadsafeness */ + enum pmcmsptwi_xfer_result last_result; /* result of last xfer */ +}; + +/* The default settings */ +const static struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = { + .standard = { + .filter = 0x3, + .clock = 0x1f, + }, + .highspeed = { + .filter = 0x3, + .clock = 0x1f, + }, +}; + +const static struct pmcmsptwi_cfg pmcmsptwi_defcfg = { + .arbf = 0x0 |