diff options
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 33 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-amd756.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-au1550.c | 177 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-au1550.h | 32 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-davinci.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 163 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ibm_iic.c | 191 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ibm_iic.h | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-iop3xx.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ixp4xx.c | 178 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mpc.c | 29 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nforce2.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pasemi.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 41 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 189 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sibyte.c | 29 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-stub.c | 15 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-viapro.c | 11 |
21 files changed, 538 insertions, 575 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c466c6cfc2e..8d12b26bb6c 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -182,7 +182,8 @@ config I2C_I801 will be called i2c-i801. config I2C_I810 - tristate "Intel 810/815" + tristate "Intel 810/815 (DEPRECATED)" + default n depends on PCI select I2C_ALGOBIT help @@ -195,6 +196,8 @@ config I2C_I810 i815 i845G + This driver is deprecated in favor of the i810fb and intelfb drivers. + This driver can also be built as a module. If so, the module will be called i2c-i810. @@ -259,20 +262,6 @@ config I2C_IOP3XX This driver can also be built as a module. If so, the module will be called i2c-iop3xx. -config I2C_IXP4XX - tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)" - depends on ARCH_IXP4XX - select I2C_ALGOBIT - help - Say Y here if you have an Intel IXP4xx(420,421,422,425) based - system and are using GPIO lines for an I2C bus. - - This support is also available as a module. If so, the module - will be called i2c-ixp4xx. - - This driver is deprecated and will be dropped soon. Use i2c-gpio - instead. - config I2C_IXP2000 tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)" depends on ARCH_IXP2000 @@ -396,7 +385,8 @@ config I2C_PASEMI Supports the PA Semi PWRficient on-chip SMBus interfaces. config I2C_PROSAVAGE - tristate "S3/VIA (Pro)Savage" + tristate "S3/VIA (Pro)Savage (DEPRECATED)" + default n depends on PCI select I2C_ALGOBIT help @@ -407,6 +397,8 @@ config I2C_PROSAVAGE S3/VIA KM266/VT8375 aka ProSavage8 S3/VIA KM133/VT8365 aka Savage4 + This driver is deprecated in favor of the savagefb driver. + This support is also available as a module. If so, the module will be called i2c-prosavage. @@ -418,13 +410,16 @@ config I2C_S3C2410 Samsung S3C2410 based System-on-Chip devices. config I2C_SAVAGE4 - tristate "S3 Savage 4" - depends on PCI && EXPERIMENTAL + tristate "S3 Savage 4 (DEPRECATED)" + default n + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the S3 Savage 4 I2C interface. + This driver is deprecated in favor of the savagefb driver. + This driver can also be built as a module. If so, the module will be called i2c-savage4. @@ -611,7 +606,7 @@ config I2C_VIAPRO VT8231 VT8233/A VT8235 - VT8237R/A + VT8237R/A/S VT8251 CX700 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 81d43c27cf9..ea7068f1eb6 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o -obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 7490dc1771a..573abe44084 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -334,6 +334,10 @@ static int __devinit amd756_probe(struct pci_dev *pdev, int error; u8 temp; + /* driver_data might come from user-space, so check it */ + if (id->driver_data > ARRAY_SIZE(chipname)) + return -EINVAL; + if (amd756_ioport) { dev_err(&pdev->dev, "Only one device supported " "(you have a strange motherboard, btw)\n"); @@ -405,6 +409,7 @@ static struct pci_driver amd756_driver = { .id_table = amd756_ids, .probe = amd756_probe, .remove = __devexit_p(amd756_remove), + .dynids.use_driver_data = 1, }; static int __init amd756_init(void) diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 2f684166c43..1953b26da56 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -30,14 +30,22 @@ #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/i2c.h> +#include <linux/slab.h> #include <asm/mach-au1x00/au1xxx.h> #include <asm/mach-au1x00/au1xxx_psc.h> -#include "i2c-au1550.h" +struct i2c_au1550_data { + u32 psc_base; + int xfer_timeout; + int ack_timeout; + struct i2c_adapter adap; + struct resource *ioarea; +}; static int wait_xfer_done(struct i2c_au1550_data *adap) @@ -105,7 +113,7 @@ wait_master_done(struct i2c_au1550_data *adap) } static int -do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) +do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q) { volatile psc_smb_t *sp; u32 stat; @@ -134,6 +142,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) if (rd) addr |= 1; + /* zero-byte xfers stop immediately */ + if (q) + addr |= PSC_SMBTXRX_STP; + /* Put byte into fifo, start up master. */ sp->psc_smbtxrx = addr; @@ -142,7 +154,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) au_sync(); if (wait_ack(adap)) return -EIO; - return 0; + return (q) ? wait_master_done(adap) : 0; } static u32 @@ -262,7 +274,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) for (i = 0; !err && i < num; i++) { p = &msgs[i]; - err = do_address(adap, p->addr, p->flags & I2C_M_RD); + err = do_address(adap, p->addr, p->flags & I2C_M_RD, + (p->len == 0)); if (err || !p->len) continue; if (p->flags & I2C_M_RD) @@ -294,18 +307,48 @@ static const struct i2c_algorithm au1550_algo = { * Prior to calling us, the 50MHz clock frequency and routing * must have been set up for the PSC indicated by the adapter. */ -int -i2c_au1550_add_bus(struct i2c_adapter *i2c_adap) +static int __devinit +i2c_au1550_probe(struct platform_device *pdev) { - struct i2c_au1550_data *adap = i2c_adap->algo_data; - volatile psc_smb_t *sp; - u32 stat; + struct i2c_au1550_data *priv; + volatile psc_smb_t *sp; + struct resource *r; + u32 stat; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -ENODEV; + goto out; + } + + priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out; + } + + priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, + pdev->name); + if (!priv->ioarea) { + ret = -EBUSY; + goto out_mem; + } - i2c_adap->algo = &au1550_algo; + priv->psc_base = r->start; + priv->xfer_timeout = 200; + priv->ack_timeout = 200; + + priv->adap.id = I2C_HW_AU1550_PSC; + priv->adap.nr = pdev->id; + priv->adap.algo = &au1550_algo; + priv->adap.algo_data = priv; + priv->adap.dev.parent = &pdev->dev; + strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); /* Now, set up the PSC for SMBus PIO mode. */ - sp = (volatile psc_smb_t *)(adap->psc_base); + sp = (volatile psc_smb_t *)priv->psc_base; sp->psc_ctrl = PSC_CTRL_DISABLE; au_sync(); sp->psc_sel = PSC_SEL_PS_SMBUSMODE; @@ -343,87 +386,87 @@ i2c_au1550_add_bus(struct i2c_adapter *i2c_adap) au_sync(); } while ((stat & PSC_SMBSTAT_DR) == 0); - return i2c_add_adapter(i2c_adap); -} + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret == 0) { + platform_set_drvdata(pdev, priv); + return 0; + } + /* disable the PSC */ + sp->psc_smbcfg = 0; + sp->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); -int -i2c_au1550_del_bus(struct i2c_adapter *adap) + release_resource(priv->ioarea); + kfree(priv->ioarea); +out_mem: + kfree(priv); +out: + return ret; +} + +static int __devexit +i2c_au1550_remove(struct platform_device *pdev) { - return i2c_del_adapter(adap); + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&priv->adap); + sp->psc_smbcfg = 0; + sp->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); + release_resource(priv->ioarea); + kfree(priv->ioarea); + kfree(priv); + return 0; } static int -pb1550_reg(struct i2c_client *client) +i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) { + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + sp->psc_ctrl = PSC_CTRL_SUSPEND; + au_sync(); return 0; } static int -pb1550_unreg(struct i2c_client *client) +i2c_au1550_resume(struct platform_device *pdev) { + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + sp->psc_ctrl = PSC_CTRL_ENABLE; + au_sync(); + while (!(sp->psc_smbstat & PSC_SMBSTAT_SR)) + au_sync(); return 0; } -static struct i2c_au1550_data pb1550_i2c_info = { - SMBUS_PSC_BASE, 200, 200 -}; - -static struct i2c_adapter pb1550_board_adapter = { - name: "pb1550 adapter", - id: I2C_HW_AU1550_PSC, - algo: NULL, - algo_data: &pb1550_i2c_info, - client_register: pb1550_reg, - client_unregister: pb1550_unreg, +static struct platform_driver au1xpsc_smbus_driver = { + .driver = { + .name = "au1xpsc_smbus", + .owner = THIS_MODULE, + }, + .probe = i2c_au1550_probe, + .remove = __devexit_p(i2c_au1550_remove), + .suspend = i2c_au1550_suspend, + .resume = i2c_au1550_resume, }; -/* BIG hack to support the control interface on the Wolfson WM8731 - * audio codec on the Pb1550 board. We get an address and two data - * bytes to write, create an i2c message, and send it across the - * i2c transfer function. We do this here because we have access to - * the i2c adapter structure. - */ -static struct i2c_msg wm_i2c_msg; /* We don't want this stuff on the stack */ -static u8 i2cbuf[2]; - -int -pb1550_wm_codec_write(u8 addr, u8 reg, u8 val) -{ - wm_i2c_msg.addr = addr; - wm_i2c_msg.flags = 0; - wm_i2c_msg.buf = i2cbuf; - wm_i2c_msg.len = 2; - i2cbuf[0] = reg; - i2cbuf[1] = val; - - return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1); -} - static int __init i2c_au1550_init(void) { - printk(KERN_INFO "Au1550 I2C: "); - - /* This is where we would set up a 50MHz clock source - * and routing. On the Pb1550, the SMBus is PSC2, which - * uses a shared clock with USB. This has been already - * configured by Yamon as a 48MHz clock, close enough - * for our work. - */ - if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) { - printk("failed to initialize.\n"); - return -ENODEV; - } - - printk("initialized.\n"); - return 0; + return platform_driver_register(&au1xpsc_smbus_driver); } static void __exit i2c_au1550_exit(void) { - i2c_au1550_del_bus(&pb1550_board_adapter); + platform_driver_unregister(&au1xpsc_smbus_driver); } MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC."); diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/i2c/busses/i2c-au1550.h deleted file mode 100644 index fce15d161ae..00000000000 --- a/drivers/i2c/busses/i2c-au1550.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com> - * 2.6 port by Matt Porter <mporter@kernel.crashing.org> - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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. - */ - -#ifndef I2C_AU1550_H -#define I2C_AU1550_H - -struct i2c_au1550_data { - u32 psc_base; - int xfer_timeout; - int ack_timeout; -}; - -int i2c_au1550_add_bus(struct i2c_adapter *); -int i2c_au1550_del_bus(struct i2c_adapter *); - -#endif /* I2C_AU1550_H */ diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 67224a424ab..7dbdaeb707a 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -550,6 +550,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) p_adap = &iface->adap; p_adap->id = I2C_HW_BLACKFIN; + p_adap->nr = dev->id; strlcpy(p_adap->name, dev->name, sizeof(p_adap->name)); p_adap->algo = &bfin_twi_algorithm; p_adap->algo_data = iface; @@ -576,7 +577,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); SSYNC(); - rc = i2c_add_adapter(p_adap); + rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) free_irq(iface->irq, iface); else diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 67679882ebe..cce5a614758 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -510,7 +510,6 @@ static int davinci_i2c_probe(struct platform_device *pdev) /* FIXME */ adap->timeout = 1; - adap->retries = 1; adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ac27e5f84eb..aa9157913b9 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -4,6 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com> + Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> 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 @@ -21,25 +22,34 @@ */ /* - SUPPORTED DEVICES PCI ID - 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 - ESB2 269B - ICH8 283E - ICH9 2930 - Tolapai 5032 - This driver supports several versions of Intel's I/O Controller Hubs (ICH). - For SMBus support, they are similar to the PIIX4 and are part - of Intel's '810' and other chipsets. - See the file Documentation/i2c/busses/i2c-i801 for details. - I2C Block Read and Process Call are not supported. + Supports the following Intel I/O Controller Hubs (ICH): + + I/O Block I2C + region SMBus Block proc. block + Chip name PCI ID size PEC buffer call read + ---------------------------------------------------------------------- + 82801AA (ICH) 0x2413 16 no no no no + 82801AB (ICH0) 0x2423 16 no no no no + 82801BA (ICH2) 0x2443 16 no no no no + 82801CA (ICH3) 0x2483 32 soft no no no + 82801DB (ICH4) 0x24c3 32 hard yes no no + 82801E (ICH5) 0x24d3 32 hard yes yes yes + 6300ESB 0x25a4 32 hard yes yes yes + 82801F (ICH6) 0x266a 32 hard yes yes yes + 6310ESB/6320ESB 0x269b 32 hard yes yes yes + 82801G (ICH7) 0x27da 32 hard yes yes yes + 82801H (ICH8) 0x283e 32 hard yes yes yes + 82801I (ICH9) 0x2930 32 hard yes yes yes + Tolapai 0x5032 32 hard yes ? ? + + Features supported by this driver: + Software PEC no + Hardware PEC yes + Block buffer yes + Block process call transaction no + I2C block read transaction yes (doesn't use the block buffer) + + See the file Documentation/i2c/busses/i2c-i801 for details. */ /* Note: we assume there can only be one I801, with one SMBus interface */ @@ -62,9 +72,9 @@ #define SMBHSTDAT0 (5 + i801_smba) #define SMBHSTDAT1 (6 + i801_smba) #define SMBBLKDAT (7 + i801_smba) -#define SMBPEC (8 + i801_smba) /* ICH4 only */ -#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ -#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ +#define SMBPEC (8 + i801_smba) /* ICH3 and later */ +#define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */ +#define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */ /* PCI Address Constants */ #define SMBBAR 4 @@ -91,13 +101,13 @@ #define I801_BYTE 0x04 #define I801_BYTE_DATA 0x08 #define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ +#define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ +#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ #define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ +#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */ #define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH4 only */ +#define I801_PEC_EN 0x80 /* ICH3 and later */ /* I801 Hosts Status register bits */ #define SMBHSTSTS_BYTE_DONE 0x80 @@ -113,7 +123,12 @@ static unsigned long i801_smba; static unsigned char i801_original_hstcfg; static struct pci_driver i801_driver; static struct pci_dev *I801_dev; -static int isich4; + +#define FEATURE_SMBUS_PEC (1 << 0) +#define FEATURE_BLOCK_BUFFER (1 << 1) +#define FEATURE_BLOCK_PROC (1 << 2) +#define FEATURE_I2C_BLOCK_READ (1 << 3) +static unsigned int i801_features; static int i801_transaction(int xact) { @@ -242,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data, } static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, - char read_write, int hwpec) + char read_write, int command, + int hwpec) { int i, len; int smbcmd; @@ -259,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, } for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) - smbcmd = I801_BLOCK_LAST; - else - smbcmd = I801_BLOCK_DATA; + if (i == len && read_write == I2C_SMBUS_READ) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA) + smbcmd = I801_I2C_BLOCK_LAST; + else + smbcmd = I801_BLOCK_LAST; + } else { + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + } outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); /* Make sure the SMBus host is ready to start transmitting */ temp = inb_p(SMBHSTSTS); @@ -332,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, dev_dbg(&I801_dev->dev, "Error: no response!\n"); } - if (i == 1 && read_write == I2C_SMBUS_READ) { + if (i == 1 && read_write == I2C_SMBUS_READ + && command != I2C_SMBUS_I2C_BLOCK_DATA) { len = inb_p(SMBHSTDAT0); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) return -1; @@ -353,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, temp); } dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); if (result < 0) return result; @@ -384,33 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); pci_write_config_byte(I801_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN); - } else { + } else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) { dev_err(&I801_dev->dev, - "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + "I2C block read is unsupported!\n"); return -1; } } - if (read_write == I2C_SMBUS_WRITE) { + if (read_write == I2C_SMBUS_WRITE + || command == I2C_SMBUS_I2C_BLOCK_DATA) { 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 */ + data->block[0] = 32; /* max for SMBus block reads */ } - if (isich4 && i801_set_block_buffer_mode() == 0 ) + if ((i801_features & FEATURE_BLOCK_BUFFER) + && !(command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_READ) + && 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); + command, hwpec); if (result == 0 && hwpec) i801_wait_hwpec(); - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_WRITE) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); } @@ -426,7 +456,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, int block = 0; int ret, xact = 0; - hwpec = isich4 && (flags & I2C_CLIENT_PEC) + hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; @@ -462,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, xact = I801_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); block = 1; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading */ + outb_p((addr & 0x7f) << 1, SMBHSTADD); + if (read_write == I2C_SMBUS_READ) { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ + outb_p(command, SMBHSTDAT1); + } else + outb_p(command, SMBHSTCMD); + block = 1; + break; case I2C_SMBUS_PROC_CALL: default: dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); @@ -487,7 +528,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, /* Some BIOSes don't like it when PEC is enabled at reboot or resume time, so we forcibly disable it after every transaction. Turn off E32B for the same reason. */ - if (hwpec) + if (hwpec || block) outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL); @@ -514,9 +555,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, static u32 i801_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK - | (isich4 ? I2C_FUNC_SMBUS_PEC : 0); + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | + ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((i801_features & FEATURE_I2C_BLOCK_READ) ? + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); } static const struct i2c_algorithm smbus_algorithm = { @@ -556,8 +599,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id int err; I801_dev = dev; + i801_features = 0; switch (dev->device) { - case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_82801EB_3: case PCI_DEVICE_ID_INTEL_ESB_4: case PCI_DEVICE_ID_INTEL_ICH6_16: @@ -565,11 +608,13 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ESB2_17: case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: + i801_features |= FEATURE_I2C_BLOCK_READ; + /* fall through */ + case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_TOLAPAI_1: - isich4 = 1; + i801_features |= FEATURE_SMBUS_PEC; + i801_features |= FEATURE_BLOCK_BUFFER; break; - default: - isich4 = 0; } err = pci_enable_device(dev); @@ -610,6 +655,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id else dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); + /* Clear special mode bits */ + if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) + outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), + SMBAUXCTL); + /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; @@ -678,9 +728,8 @@ static void __exit i2c_i801_exit(void) pci_unregister_driver(&i801_driver); } -MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " - "Philip Edelbrock <phil@netroedge.com>, " - "and Mark D. Studebaker <mdsxyz123@yahoo.com>"); +MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, " + "Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("I801 SMBus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 9b43ff7270d..7c7eb0cfece 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -6,7 +6,7 @@ * Copyright (c) 2003, 2004 Zultys Technologies. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Based on original work by + * Based on original work by * Ian DaSilva <idasilva@mvista.com> * Armin Kuster <akuster@mvista.com> * Matt Porter <mporter@mvista.com> @@ -86,8 +86,8 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev) KERN_DEBUG " sts = 0x%02x, extsts = 0x%02x\n" KERN_DEBUG " clkdiv = 0x%02x, xfrcnt = 0x%02x\n" KERN_DEBUG " xtcntlss = 0x%02x, directcntl = 0x%02x\n", - in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), - in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), + in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), + in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), in_8(&iic->xtcntlss), in_8(&iic->directcntl)); } # define DUMP_REGS(h,dev) dump_iic_regs((h),(dev)) @@ -125,7 +125,7 @@ static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable) { out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0); } - + /* * Initialize IIC interface. */ @@ -134,7 +134,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) volatile struct iic_regs __iomem *iic = dev->vaddr; DBG("%d: init\n", dev->idx); - + /* Clear master address */ out_8(&iic->lmadr, 0); out_8(&iic->hmadr, 0); @@ -160,7 +160,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) /* Clear control register */ out_8(&iic->cntl, 0); - + /* Enable interrupts if possible */ iic_interrupt_mode(dev, dev->irq >= 0); @@ -171,7 +171,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) DUMP_REGS("iic_init", dev); } -/* +/* * Reset IIC interface */ static void iic_dev_reset(struct ibm_iic_private* dev) @@ -179,42 +179,42 @@ static void iic_dev_reset(struct ibm_iic_private* dev) volatile struct iic_regs __iomem *iic = dev->vaddr; int i; u8 dc; - + DBG("%d: soft reset\n", dev->idx); DUMP_REGS("reset", dev); - + /* Place chip in the reset state */ out_8(&iic->xtcntlss, XTCNTLSS_SRST); - + /* Check if bus is free */ - dc = in_8(&iic->directcntl); + dc = in_8(&iic->directcntl); if (!DIRCTNL_FREE(dc)){ DBG("%d: trying to regain bus control\n", dev->idx); - + /* Try to set bus free state */ - out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); - + out_8(&a |