summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/Kconfig94
-rw-r--r--drivers/i2c/busses/Makefile5
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-at91.c325
-rw-r--r--drivers/i2c/busses/i2c-au1550.c21
-rw-r--r--drivers/i2c/busses/i2c-elektor.c5
-rw-r--r--drivers/i2c/busses/i2c-hydra.c3
-rw-r--r--drivers/i2c/busses/i2c-i801.c20
-rw-r--r--drivers/i2c/busses/i2c-i810.c8
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c15
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.h2
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c20
-rw-r--r--drivers/i2c/busses/i2c-isa.c42
-rw-r--r--drivers/i2c/busses/i2c-ite.c279
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c3
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c8
-rw-r--r--drivers/i2c/busses/i2c-mpc.c4
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c4
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c89
-rw-r--r--drivers/i2c/busses/i2c-ocores.c5
-rw-r--r--drivers/i2c/busses/i2c-omap.c676
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c3
-rw-r--r--drivers/i2c/busses/i2c-parport.c3
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c4
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-pnx.c708
-rw-r--r--drivers/i2c/busses/i2c-powermac.c30
-rw-r--r--drivers/i2c/busses/i2c-prosavage.c3
-rw-r--r--drivers/i2c/busses/i2c-pxa.c143
-rw-r--r--drivers/i2c/busses/i2c-rpx.c4
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c5
-rw-r--r--drivers/i2c/busses/i2c-savage4.c3
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c160
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-stub.c21
-rw-r--r--drivers/i2c/busses/i2c-versatile.c153
-rw-r--r--drivers/i2c/busses/i2c-via.c3
-rw-r--r--drivers/i2c/busses/i2c-viapro.c10
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c8
-rw-r--r--drivers/i2c/busses/scx200_acb.c9
-rw-r--r--drivers/i2c/busses/scx200_i2c.c16
47 files changed, 2294 insertions, 638 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 884320e..e1989f3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -74,12 +74,19 @@ config I2C_AMD8111
This driver can also be built as a module. If so, the module
will be called i2c-amd8111.
+config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on I2C && ARCH_AT91 && EXPERIMENTAL
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
config I2C_AU1550
- tristate "Au1550 SMBus interface"
- depends on I2C && SOC_AU1550
+ tristate "Au1550/Au1200 SMBus interface"
+ depends on I2C && (SOC_AU1550 || SOC_AU1200)
help
If you say yes to this option, support will be included for the
- Au1550 SMBus interface.
+ Au1550 and Au1200 SMBus interface.
This driver can also be built as a module. If so, the module
will be called i2c-au1550.
@@ -125,6 +132,7 @@ config I2C_I801
ICH7
ESB2
ICH8
+ ICH9
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -195,11 +203,11 @@ config I2C_IBM_IIC
will be called i2c-ibm_iic.
config I2C_IOP3XX
- tristate "Intel IOP3xx and IXP4xx on-chip I2C interface"
- depends on (ARCH_IOP3XX || ARCH_IXP4XX) && I2C
+ tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
+ depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C
help
Say Y here if you want to use the IIC bus controller on
- the Intel IOP3xx I/O Processors or IXP4xx Network Processors.
+ the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
@@ -208,18 +216,6 @@ config I2C_ISA
tristate
depends on I2C
-config I2C_ITE
- tristate "ITE I2C Adapter"
- depends on I2C && MIPS_ITE8172
- select I2C_ALGOITE
- help
- This supports the ITE8172 I2C peripheral found on some MIPS
- systems. Say Y if you have one of these. You should also say Y for
- the ITE I2C driver algorithm support above.
-
- This support is also available as a module. If so, the module
- will be called i2c-ite.
-
config I2C_IXP4XX
tristate "IXP4xx GPIO-Based I2C Interface"
depends on I2C && ARCH_IXP4XX
@@ -287,6 +283,16 @@ config I2C_OCORES
This driver can also be built as a module. If so, the module
will be called i2c-ocores.
+config I2C_OMAP
+ tristate "OMAP I2C adapter"
+ depends on I2C && ARCH_OMAP
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Texas Instruments OMAP1/2 family of processors.
+ Like OMAP1510/1610/1710/5912 and OMAP242x.
+ For details see http://www.ti.com/omap.
+
config I2C_PARPORT
tristate "Parallel port adapter"
depends on I2C && PARPORT
@@ -323,10 +329,10 @@ config I2C_PARPORT_LIGHT
This driver is a light version of i2c-parport. It doesn't depend
on the parport driver, and uses direct I/O access instead. This
- might be prefered on embedded systems where wasting memory for
+ might be preferred on embedded systems where wasting memory for
the clean but heavy parport handling is not an option. The
drawback is a reduced portability and the impossibility to
- dasiy-chain other parallel port devices.
+ daisy-chain other parallel port devices.
Don't say Y here if you said Y or M to i2c-parport. Saying M to
both is possible but both modules should not be loaded at the same
@@ -470,6 +476,17 @@ config I2C_STUB
If you don't know what to do here, definitely say N.
+config I2C_VERSATILE
+ tristate "ARM Versatile/Realview I2C bus support"
+ depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW)
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C serial bus on ARMs Versatile
+ range of platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-versatile.
+
config I2C_VIA
tristate "VIA 82C586B"
depends on I2C && PCI && EXPERIMENTAL
@@ -482,19 +499,19 @@ config I2C_VIA
will be called i2c-via.
config I2C_VIAPRO
- tristate "VIA 82C596/82C686/823x"
+ tristate "VIA 82C596/82C686/82xx"
depends on I2C && PCI
help
If you say yes to this option, support will be included for the VIA
- 82C596/82C686/823x I2C interfaces. Specifically, the following
+ 82C596/82C686/82xx I2C interfaces. Specifically, the following
chipsets are supported:
- 82C596A/B
- 82C686A/B
- 8231
- 8233
- 8233A
- 8235
- 8237
+ VT82C596A/B
+ VT82C686A/B
+ VT8231
+ VT8233/A
+ VT8235
+ VT8237R/A
+ VT8251
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
@@ -537,4 +554,23 @@ config I2C_MV64XXX
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_PNX
+ tristate "I2C bus support for Philips PNX targets"
+ depends on ARCH_PNX4008 && I2C
+ help
+ This driver supports the Philips IP3204 I2C IP block master and/or
+ slave controller
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pnx.
+
+config I2C_PNX_EARLY
+ bool "Early initialization for I2C on PNXxxxx"
+ depends on I2C_PNX=y
+ help
+ Under certain circumstances one may need to make sure I2C on PNXxxxx
+ is initialized earlier than some other driver that depends on it
+ (for instance, that might be USB in case of PNX4008). With this
+ option turned on you can guarantee that.
+
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ac56df5..37196c1 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
+obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
@@ -16,7 +17,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_ISA) += i2c-isa.o
-obj-$(CONFIG_I2C_ITE) += i2c-ite.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
@@ -24,10 +24,12 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.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
@@ -38,6 +40,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_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index d3ef46a..e75d339 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -468,7 +468,7 @@ static u32 ali1535_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = ali1535_access,
.functionality = ali1535_func,
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index e6f6320..33fbb47 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -367,7 +367,7 @@ static void ali1563_shutdown(struct pci_dev *dev)
release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
}
-static struct i2c_algorithm ali1563_algorithm = {
+static const struct i2c_algorithm ali1563_algorithm = {
.smbus_xfer = ali1563_access,
.functionality = ali1563_func,
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 7a5c094..3f11b6e 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -463,7 +463,7 @@ static u32 ali15x3_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = ali15x3_access,
.functionality = ali15x3_func,
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 1750ded..2d21afd 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -294,7 +294,7 @@ static u32 amd756_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = amd756_access,
.functionality = amd756_func,
};
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index e5ef560..0fbc718 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -316,7 +316,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = amd8111_access,
.functionality = amd8111_func,
};
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 0000000..67f91bd
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,325 @@
+/*
+ i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+
+ Copyright (C) 2004 Rick Bronson
+ Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+
+ Borrowed heavily from original work by:
+ Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ 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.
+*/
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/at91_twi.h>
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+
+#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+
+
+static struct clk *twi_clk;
+static void __iomem *twi_base;
+
+#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
+#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+
+
+/*
+ * Initialize the TWI hardware registers.
+ */
+static void __devinit at91_twi_hwinit(void)
+{
+ unsigned long cdiv, ckdiv;
+
+ at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
+
+ /* Calcuate clock dividers */
+ cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+ cdiv = cdiv + 1; /* round up */
+ ckdiv = 0;
+ while (cdiv > 255) {
+ ckdiv++;
+ cdiv = cdiv >> 1;
+ }
+
+ if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
+ if (ckdiv > 5) {
+ printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+ ckdiv = 5;
+ }
+ }
+
+ at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+}
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short at91_poll_status(unsigned long bit)
+{
+ int loop_cntr = 10000;
+
+ do {
+ udelay(10);
+ } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+
+ return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ /* Read data */
+ while (length--) {
+ if (!length) /* need to send Stop before reading last byte */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+ if (!at91_poll_status(AT91_TWI_RXRDY)) {
+ dev_dbg(&adap->dev, "RXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+ *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+ }
+
+ return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Load first byte into transmitter */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ do {
+ if (!at91_poll_status(AT91_TWI_TXRDY)) {
+ dev_dbg(&adap->dev, "TXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ length--; /* byte was transmitted */
+
+ if (length > 0) /* more data to send? */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+ } while (length);
+
+ /* Send Stop */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ * Note: We do not use Atmel's feature of storing the "internal device address".
+ * Instead the "internal device address" has to be written using a seperate
+ * i2c message.
+ * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+ */
+static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+ int i, ret;
+
+ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+
+ for (i = 0; i < num; i++) {
+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+ pmsg->flags & I2C_M_RD ? "read" : "writ",
+ pmsg->len, pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+ at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+ | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+ if (pmsg->len && pmsg->buf) { /* sanity check */
+ if (pmsg->flags & I2C_M_RD)
+ ret = xfer_read(adap, pmsg->buf, pmsg->len);
+ else
+ ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+ if (ret)
+ return ret;
+
+ /* Wait until transfer is finished */
+ if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+ dev_dbg(&adap->dev, "TXCOMP timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+ return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 at91_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm at91_algorithm = {
+ .master_xfer = at91_xfer,
+ .functionality = at91_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit at91_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct resource *res;
+ int rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1, "at91_i2c"))
+ return -EBUSY;
+
+ twi_base = ioremap(res->start, res->end - res->start + 1);
+ if (!twi_base) {
+ rc = -ENOMEM;
+ goto fail0;
+ }
+
+ twi_clk = clk_get(NULL, "twi_clk");
+ if (IS_ERR(twi_clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ rc = -ENODEV;
+ goto fail1;
+ }
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "can't allocate inteface!\n");
+ rc = -ENOMEM;
+ goto fail2;
+ }
+ sprintf(adapter->name, "AT91");
+ adapter->algo = &at91_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+
+ platform_set_drvdata(pdev, adapter);
+
+ clk_enable(twi_clk); /* enable peripheral clock */
+ at91_twi_hwinit(); /* initialize TWI controller */
+
+ rc = i2c_add_adapter(adapter);
+ if (rc) {
+ dev_err(&pdev->dev, "Adapter %s registration failed\n",
+ adapter->name);
+ goto fail3;
+ }
+
+ dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+ return 0;
+
+fail3:
+ platform_set_drvdata(pdev, NULL);
+ kfree(adapter);
+ clk_disable(twi_clk);
+fail2:
+ clk_put(twi_clk);
+fail1:
+ iounmap(twi_base);
+fail0:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ return rc;
+}
+
+static int __devexit at91_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct resource *res;
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(twi_base);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ clk_disable(twi_clk); /* disable peripheral clock */
+ clk_put(twi_clk);
+
+ return rc;
+}
+
+#ifdef CONFIG_PM
+
+/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+
+static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ clk_disable(twi_clk);
+ return 0;
+}
+
+static int at91_i2c_resume(struct platform_device *pdev)
+{
+ return clk_enable(twi_clk);
+}
+
+#else
+#define at91_i2c_suspend NULL
+#define at91_i2c_resume NULL
+#endif
+
+static struct platform_driver at91_i2c_driver = {
+ .probe = at91_i2c_probe,
+ .remove = __devexit_p(at91_i2c_remove),
+ .suspend = at91_i2c_suspend,
+ .resume = at91_i2c_resume,
+ .driver = {
+ .name = "at91_i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_i2c_init(void)
+{
+ return platform_driver_register(&at91_i2c_driver);
+}
+
+static void __exit at91_i2c_exit(void)
+{
+ platform_driver_unregister(&at91_i2c_driver);
+}
+
+module_init(at91_i2c_init);
+module_exit(at91_i2c_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index d06edce..d7e7c35 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -34,8 +34,7 @@
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1550.h>
+#include <asm/mach-au1x00/au1xxx.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include "i2c-au1550.h"
@@ -118,13 +117,19 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
/* Reset the FIFOs, clear events.
*/
- sp->psc_smbpcr = PSC_SMBPCR_DC;
+ stat = sp->psc_smbstat;
sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
au_sync();
- do {
- stat = sp->psc_smbpcr;
+
+ if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
+ sp->psc_smbpcr = PSC_SMBPCR_DC;
au_sync();
- } while ((stat & PSC_SMBPCR_DC) != 0);
+ do {
+ stat = sp->psc_smbpcr;
+ au_sync();
+ } while ((stat & PSC_SMBPCR_DC) != 0);
+ udelay(50);
+ }
/* Write out the i2c chip address and specify operation
*/
@@ -279,10 +284,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
static u32
au1550_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm au1550_algo = {
+static const struct i2c_algorithm au1550_algo = {
.master_xfer = au1550_xfer,
.functionality = au1550_func,
};
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 59f8308..8349674 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -131,7 +131,7 @@ static void pcf_isa_waitforpin(void) {
}
-static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
spin_lock(&lock);
pcf_pending = 1;
spin_unlock(&lock);
@@ -196,7 +196,6 @@ static struct i2c_algo_pcf_data pcf_isa_data = {
.getclock = pcf_isa_getclock,
.waitforpin = pcf_isa_waitforpin,
.udelay = 10,
- .mdelay = 10,
.timeout = 100,
};
@@ -294,7 +293,7 @@ static int __init i2c_pcfisa_init(void)
static void i2c_pcfisa_exit(void)
{
- i2c_pcf_del_bus(&pcf_isa_ops);
+ i2c_del_adapter(&pcf_isa_ops);
if (irq > 0) {
disable_irq(irq);
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index e0cb3b0..9832f77 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -99,7 +99,6 @@ static struct i2c_algo_bit_data hydra_bit_data = {
.getsda = hydra_bit_getsda,
.getscl = hydra_bit_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = HZ
};
@@ -147,7 +146,7 @@ static int __devinit hydra_probe(struct pci_dev *dev,
static void __devexit hydra_remove(struct pci_dev *dev)
{
pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */
- i2c_bit_del_bus(&hydra_adap);
+ i2c_del_adapter(&hydra_adap);
iounmap(hydra_bit_data.data);
release_mem_region(pci_resource_start(dev, 0)+
offsetof(struct Hydra, CachePD), 4);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 7be1d0a..ae625b8 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -33,6 +33,7 @@
ICH7 27DA
ESB2 269B
ICH8 283E
+ ICH9 2930
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.
@@ -434,7 +435,7 @@ static u32 i801_func(struct i2c_adapter *adapter)
| (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = i801_access,
.functionality = i801_func,
};
@@ -457,6 +458,7 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
{ 0, }
};
@@ -468,12 +470,20 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
int err;
I801_dev = dev;
- if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
- (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
- (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
+ 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:
+ case PCI_DEVICE_ID_INTEL_ICH7_17:
+ case PCI_DEVICE_ID_INTEL_ESB2_17:
+ case PCI_DEVICE_ID_INTEL_ICH8_5:
+ case PCI_DEVICE_ID_INTEL_ICH9_6:
isich4 = 1;
- else
+ break;
+ default:
isich4 = 0;
+ }
err = pci_enable_device(dev);
if (err) {
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
index 748be30..10c98bc 100644
--- a/drivers/i2c/busses/i2c-i810.c
+++ b/drivers/i2c/busses/i2c-i810.c
@@ -166,7 +166,6 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = {
.getsda = bit_i810i2c_getsda,
.getscl = bit_i810i2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT,
};
@@ -182,7 +181,6 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = {
.getsda = bit_i810ddc_getsda,
.getscl = bit_i810ddc_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT,
};
@@ -221,14 +219,14 @@ static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id
return retval;
retval = i2c_bit_add_bus(&i810_ddc_adapter);
if (retval)
- i2c_bit_del_bus(&i810_i2c_adapter);
+ i2c_del_adapter(&i810_i2c_adapter);
return retval;
}
static void __devexit i810_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&i810_ddc_adapter);
- i2c_bit_del_bus(&i810_i2c_adapter);
+ i2c_del_adapter(&i810_ddc_adapter);
+ i2c_del_adapter(&i810_i2c_adapter);
iounmap(ioaddr);
}
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 0599bbd..1898e99 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/i2c-ibm_iic.c
+ * drivers/i2c/busses/i2c-ibm_iic.c
*
* Support for the IIC peripheral on IBM PPC 4xx
*
@@ -320,7 +320,7 @@ err:
/*
* IIC interrupt handler
*/
-static irqreturn_t iic_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t iic_handler(int irq, void *dev_id)
{
struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
volatile struct iic_regs __iomem *iic = dev->vaddr;
@@ -625,7 +625,7 @@ static u32 iic_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
-static struct i2c_algorithm iic_algo = {
+static const struct i2c_algorithm iic_algo = {
.master_xfer = iic_xfer,
.functionality = iic_func
};
@@ -680,6 +680,12 @@ static int __devinit iic_probe(struct ocp_device *ocp){
dev->idx = ocp->def->index;
ocp_set_drvdata(ocp, dev);
+ if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
+ "ibm_iic")) {
+ ret = -EBUSY;
+ goto fail1;
+ }
+
if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
dev->idx);
@@ -750,6 +756,8 @@ fail:
iounmap(dev->vaddr);
fail2:
+ release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
+fail1:
ocp_set_drvdata(ocp, NULL);
kfree(dev);
return ret;
@@ -777,6 +785,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
free_irq(dev->irq, dev);
}
iounmap(dev->vaddr);
+ release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
kfree(dev);
}
}
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
index 2b3219d..59d7b43 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.h
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/i2c-ibm_iic.h
+ * drivers/i2c/busses/i2c-ibm_iic.h
*
* Support for the IIC peripheral on IBM PPC 4xx
*
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 48c5693..d108ab4 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -82,14 +82,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
/*
* Every time unit enable is asserted, GPOD needs to be cleared
- * on IOP321 to avoid data corruption on the bus.
+ * on IOP3XX to avoid data corruption on the bus.
*/
-#ifdef CONFIG_ARCH_IOP321
-#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
-#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
-
- *IOP321_GPOD &= (iop3xx_adap->id == 0) ? ~IOP321_GPOD_I2C0 :
- ~IOP321_GPOD_I2C1;
+#ifdef CONFIG_PLAT_IOP
+ if (iop3xx_adap->id == 0) {
+ gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+ } else {
+ gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+ }
#endif
/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->SR_enabled =
@@ -118,7 +120,7 @@ iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
* Then it passes the SR flags of interest to BH via adap data
*/
static irqreturn_t
-iop3xx_i2c_irq_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
@@ -401,7 +403,7 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm iop3xx_i2c_algo = {
+static const struct i2c_algorithm iop3xx_i2c_algo = {
.master_xfer = iop3xx_i2c_master_xfer,
.algo_control = iop3xx_i2c_algo_control,
.functionality = iop3xx_i2c_func,
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index c3e1d3e8..8ed59a2 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -43,7 +43,7 @@
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
-static struct i2c_algorithm isa_algorithm = {
+static const struct i2c_algorithm isa_algorithm = {
.functionality = isa_func,
};
@@ -89,9 +89,14 @@ int i2c_isa_add_driver(struct i2c_driver *driver)
dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
/* Now look for clients */
- driver->attach_adapter(&isa_adapter);
-
- return 0;
+ res = driver->attach_adapter(&isa_adapter);
+ if (res) {
+ dev_dbg(&isa_adapter.dev,
+ "Driver %s failed to attach adapter, unregistering\n",
+ driver->driver.name);
+ driver_unregister(&driver->driver);
+ }
+ return res;
}
int i2c_isa_del_driver(struct i2c_driver *driver)
@@ -125,6 +130,8 @@ int i2c_isa_del_driver(struct i2c_driver *driver)
static int __init i2c_isa_init(void)
{
+ int err;
+
mutex_init(&isa_adapter.clist_lock);
INIT_LIST_HEAD(&isa_adapter.clients);
@@ -133,8 +140,16 @@ static int __init i2c_isa_init(void)
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
isa_adapter.dev.driver = &i2c_adapter_driver;
isa_adapter.dev.release = &i2c_adapter_dev_release;
- device_register(&isa_adapter.dev);
- device_create_file(&isa_adapter.dev, &dev_attr_name);
+ err = device_register(&isa_adapter.dev);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to register device\n");
+ goto exit;
+ }
+ err = device_create_file(&isa_adapter.dev, &dev_attr_name);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to create name file\n");
+ goto exit_unregister;
+ }
/* Add this adapter to the i2c_adapter class */
memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
@@ -142,11 +157,24 @@ static int __init i2c_isa_init(void)
isa_adapter.class_dev.class = &i2c_adapter_class;
strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
BUS_ID_SIZE);
- class_device_register(&isa_adapter.class_dev);
+ err = class_device_register(&isa_adapter.class_dev);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to register class device\n");
+ goto exit_remove_name;
+ }
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
return 0;
+
+exit_remove_name:
+ device_remove_file(&isa_adapter.dev, &dev_attr_name);
+exit_unregister:
+ init_completion(&isa_adapter.dev_released); /* Needed? */
+ device_unregister(&isa_adapter.dev);
+ wait_for_completion(&isa_adapter.dev_released);
+exit:
+ return err;
}
static void __exit i2c_isa_exit(void)
diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
deleted file mode 100644
index d82e6da..0000000
--- a/drivers/i2c/busses/i2c-ite.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- -------------------------------------------------------------------------
- i2c-adap-ite.c i2c-hw access for the IIC peripheral on the ITE MIPS system
- -------------------------------------------------------------------------
- Hai-Pao Fan, MontaVista Software, Inc.
- hpfan@mvista.com or source@mvista.com
-
- Copyright 2001 MontaVista Software Inc.
-
- ----------------------------------------------------------------------------
- This file was highly leveraged from i2c-elektor.c, which was created
- by Simon G. Vogl and Hans Berglund:
-
-
- Copyright (C) 1995-97 Simon G. Vogl
- 1998-99 Hans Berglund
-
- 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. */
-/* ------------------------------------------------------------------------- */
-
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl> */
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-ite.h>
-#include <linux/i2c-adap-ite.h>
-#include "../i2c-ite.h"
-
-#define DEFAULT_BASE 0x14014030
-#define ITE_IIC_IO_SIZE 0x40
-#define DEFAULT_IRQ 0
-#define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */
-#define DEFAULT_OWN 0x55
-
-static int base;
-static int irq;
-static int clock;
-static int own;
-
-static struct iic_ite gpi;
-static wait_queue_head_t iic_wait;
-static int iic_pending;
-static spinlock_t lock;
-
-/* ----- local functions ---------------------------------------------- */
-
-static void iic_ite_setiic(void *data, int ctl, short val)
-{
- unsigned long j = jiffies + 10;
-
- pr_debug(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff);
-#ifdef DEBUG
- while (time_before(jiffies, j))
- schedule();
-#endif
- outw(val,ctl);
-}
-
-static short iic_ite_getiic(void *data, int ctl)
-{
- short val;
-
- val = inw(ctl);
- pr_debug("Read 0x%02x from 0x%x\n",(unsigned short)val, ctl&0xff);
- return (val);
-}
-
-/* Return our slave address. This is the address
- * put on the I2C bus when another master on the bus wants to address us
- * as a slave
- */
-static int iic_ite_getown(void *data)
-{
- return (gpi.iic_own);
-}
-
-
-static int iic_ite_getclock(void *data)
-{
- return (gpi.iic_clock);
-}
-
-
-/* Put this process to sleep. We will wake up when the
- * IIC controller interrupts.
- */
-static void iic_ite_waitforpin(void) {
- DEFINE_WAIT(wait);
- int timeout = 2;
- long flags;
-
- /* If interrupts are enabled (which they are), then put the process to
- * sleep. This process will be awakened by two events -- either the
- * the IIC peripheral interrupts or the timeout expires.
- * If interrupts are not enabled then delay for a reasonable amount
- * of time and return.
- */
- if (gpi.iic_irq > 0) {
- spin_lock_irqsave(&lock, flags);
- if (iic_pending == 0) {
- spin_unlock_irqrestore(&lock, flags);
- prepare_to_wait(&iic_wait, &wait, TASK_INTERRUPTIBLE);
- if (schedule_timeout(timeout*HZ)) {
- spin_lock_irqsave(&lock, flags);
- if (iic_pending == 1) {
- iic_pending = 0;
- }
- spin_unlock_irqrestore(&lock, flags);
- }
- finish_wait(&iic_wait, &wait);
- } else {
- iic_pending = 0;
- spin_unlock_irqrestore(&lock, flags);
- }
- } else {
- udelay(100);
- }
-}
-
-
-static irqreturn_t iic_ite_handler(int this_irq, void *dev_id,
- struct pt_regs *regs)
-{
- spin_lock(&lock);
- iic_pending = 1;
- spin_unlock(&lock);
-
- wake_up_interruptible(&iic_wait);
-
- return IRQ_HANDLED;
-}
-
-
-/* Lock the region of memory where I/O registers exist. Request our
- * interrupt line and register its associated handler.
- */
-static int iic_hw_resrc_init(void)
-{
- if (!request_region(gpi.iic_base, ITE_IIC_IO_SIZE, "i2c"))
- return -ENODEV;
-
- if (gpi.iic_irq <= 0)
- return 0;
-
- if (request_irq(gpi.iic_irq, iic_ite_handler, 0, "ITE IIC", 0) < 0)
- gpi.iic_irq = 0;
- else
- enable_irq(gpi.iic_irq);
-
- return 0;
-}
-
-
-static void iic_ite_release(void)
-{
- if (gpi.iic_irq > 0) {
- disable_irq(gpi.iic_irq);
- free_irq(gpi.iic_irq, 0);
- }
- release_region(gpi.iic_base , 2);
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-static struct i2c_algo_iic_data iic_ite_data = {
- NULL,
- iic_ite_setiic,
- iic_ite_getiic,
- iic_ite_getown,
- iic_ite_getclock,
- iic_ite_waitforpin,
- 80, 80, 100, /* waits, timeout */
-};
-
-static struct i2c_adapter iic_ite_ops = {
- .owner = THIS_MODULE,
- .id = I2C_HW_I_IIC,
- .algo_data = &iic_ite_data,
- .name = "ITE IIC adapter",
-};
-
-/* Called when the module is loaded. This function starts the
- * cascade of calls up through the hierarchy of i2c modules (i.e. up to the
- * algorithm layer and into to the core layer)
- */
-static int __init iic_ite_init(void)
-{
-
- struct iic_ite *piic = &gpi;
-
- printk(KERN_INFO "Initialize ITE IIC adapter module\n");
- if (base == 0)
- piic->iic_base = DEFAULT_BASE;
- else
- piic->iic_base = base;
-
- if (irq == 0)
- piic->iic_irq = DEFAULT_IRQ;
- else
- piic->iic_irq = irq;
-
- if (clock == 0)
- piic->iic_clock = DEFAULT_CLOCK;
- else
- piic->iic_clock = clock;
-
- if (own == 0)
- piic->iic_own = DEFAULT_OWN;
- else
- piic->iic_own = own;
-
- iic_ite_data.data = (void *)piic;
- init_waitqueue_head(&iic_wait);
- spin_lock_init(&lock);
- if (iic_hw_resrc_init() == 0) {
- if (i2c_iic_add_bus(&iic_ite_ops) < 0)
- return -ENODEV;
- } else {
- return -ENODEV;
- }
- printk(KERN_INFO " found device at %#x irq %d.\n",
- piic->iic_base, piic->iic_irq);
- return 0;
-}
-
-
-static void iic_ite_exit(void)
-{
- i2c_iic_del_bus(&iic_ite_ops);
- iic_ite_release();
-}
-
-/* If modules is NOT defined when this file is compiled, then the MODULE_*
- * macros will resolve to nothing
- */
-MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter");
-MODULE_LICENSE("GPL");
-
-module_param(base, int, 0);
-module_param(irq, int, 0);
-module_param(clock, int, 0);
-module_param(own, int, 0);
-
-
-/* Called when module is loaded or when kernel is initialized.
- * If MODULES is defined when this file is compiled, then this function will
- * resolve to init_module (the function called when insmod is invoked for a
- * module). Otherwise, this function is called early in the boot, when the
- * kernel is intialized. Check out /include/init.h to see how this works.
- */
-module_init(iic_ite_init);
-
-/* Resolves to module_cleanup when MODULES is defined. */
-module_exit(iic_ite_exit);
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index cd6f45d..efa3ecc 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -90,7 +90,7 @@ static int ixp2000_i2c_remove(struct platform_device *plat_dev)
platform_set_drvdata(plat_dev, NULL);
- i2c_bit_del_bus(&drv_data->adapter);
+ i2c_del_adapter(&drv_data->adapter);
kfree(drv_data);
@@ -114,7 +114,6 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
drv_data->algo_data.getsda = ixp2000_bit_getsda;
drv_data->algo_data.getscl = ixp2000_bit_getscl;
drv_data->algo_data.udelay = 6;
- drv_data->algo_data.mdelay = 6;
drv_data->algo_data.timeout = 100;
drv_data->adapter.id = I2C_HW_B_IXP2000,
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 2ed0711..08e89b8 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/i2c-adap-ixp4xx.c
+ * drivers/i2c/busses/i2c-ixp4xx.c
*
* Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
* an on board I2C controller but provide 16 GPIO pins that are often
@@ -91,7 +91,7 @@ static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
platform_set_drvdata(plat_dev, NULL);
- i2c_bit_del_bus(&drv_data->adapter);
+ i2c_del_adapter(&drv_data->adapter);
kfree(drv_data);
@@ -122,7 +122,6 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
drv_data->algo_data.getsda = ixp4xx_bit_getsda;
drv_data->algo_data.getscl = ixp4xx_bit_getscl;
drv_data->algo_data.udelay = 10;
- drv_data->algo_data.mdelay = 10;
drv_data->algo_data.timeout = 100;
drv_data->adapter.id = I2C_HW_B_IXP4XX;
@@ -138,7 +137,8 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
gpio_line_set(gpio->scl_pin, 0);
gpio_line_set(gpio->sda_pin, 0);
- if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) {
+ err = i2c_bit_add_bus(&drv_data->adapter);
+ if (err) {
printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id);
kfree(drv_data);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 377ab40..ee65aa1 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -63,7 +63,7 @@ static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
writeb(x, i2c->base + MPC_I2C_CR);
}
-static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
{
struct mpc_i2c *i2c = dev_id;
if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
@@ -272,7 +272,7 @@ static u32 mpc_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm mpc_algo = {
+static const struct i2c_algorithm mpc_algo = {
.master_xfer = mpc_xfer,
.functionality = mpc_functionality,
};
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index ac5cde1..bbc8e3a 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -278,7 +278,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
}
static int
-mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs)
+mv64xxx_i2c_intr(int irq, void *dev_id)
{
struct mv64xxx_i2c_data *drv_data = dev_id;
unsigned long flags;
@@ -431,7 +431,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return num;
}
-static struct i2c_algorithm mv64xxx_i2c_algo = {
+static const struct i2c_algorithm mv64xxx_i2c_algo = {
.master_xfer = mv64xxx_i2c_xfer,
.functionality = mv64xxx_i2c_functionality,
};
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 604b49e..ad37c10 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -35,7 +35,7 @@
nForce4 MCP55 0368
This driver supports the 2 SMBuses that are included in the MCP of the
- nForce2/3/4 chipsets.
+ nForce2/3/4/5xx chipsets.
*/
/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
@@ -52,8 +52,8 @@
#include <asm/io.h>
MODULE_LICENSE("GPL");
-MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
-MODULE_DESCRIPTION("nForce2 SMBus driver");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
struct nforce2_smbus {
@@ -80,9 +80,6 @@ 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_ALRM_A (smbus->base + 0x25) /* alarm address */
-#define NVIDIA_SMB_ALRM_D (smbus->base + 0x26) /* 2 bytes alarm data */
#define NVIDIA_SMB_STS_DONE 0x80
#define NVIDIA_SMB_STS_ALRM 0x40
@@ -95,40 +92,17 @@ 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_PROC_CALL 0x0c
-#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
-#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
#define NVIDIA_SMB_PRTCL_PEC 0x80
static struct pci_driver nforce2_driver;
-static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data *data);
-static u32 nforce2_func(struct i2c_adapter *adapter);
-
-
-static struct i2c_algorithm smbus_algorithm = {
- .smbus_xfer = nforce2_access,
- .functionality = nforce2_func,
-};
-
-static struct i2c_adapter nforce2_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_HWMON,
- .algo = &smbus_algorithm,
-};
-
-/* Return -1 on error. See smbus.h for more information */
+/* Return -1 on error */
static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data)
{
struct nforce2_smbus *smbus = adap->algo_data;
unsigned char protocol, pec, temp;
- unsigned char len = 0; /* to keep the compiler quiet */
- int i;
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
NVIDIA_SMB_PRTCL_WRITE;
@@ -163,35 +137,6 @@ 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 = min_t(u8, data->block[0], 32);
- outb_p(len, NVIDIA_SMB_BCNT);
- for (i = 0; i < len; i++)
- outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
- }
- protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
- break;
-
- case I2C_SMBUS_I2C_BLOCK_DATA:
- len = min_t(u8, data->block[0], 32);
- outb_p(command, NVIDIA_SMB_CMD);
- outb_p(len, NVIDIA_SMB_BCNT);
- if (read_write == I2C_SMBUS_WRITE)
- for (i = 0; i < len; i++)
- outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
- protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
- break;
-
- case I2C_SMBUS_PROC_CALL:
- dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
- return -1;
-
- case I2C_SMBUS_BLOCK_PROC_CALL:
- dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
- return -1;
-
default:
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
return -1;
@@ -227,19 +172,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
break;
case I2C_SMBUS_WORD_DATA:
- /* case I2C_SMBUS_PROC_CALL: not supported */
data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
break;
-
- case I2C_SMBUS_BLOCK_DATA:
- /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
- len = inb_p(NVIDIA_SMB_BCNT);
- len = min_t(u8, len, 32);
- case I2C_SMBUS_I2C_BLOCK_DATA:
- for (i = 0; i < len; i++)
- data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
- data->block[0] = len;
- break;
}
return 0;
@@ -250,10 +184,14 @@ 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_BLOCK_DATA */;
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
}
+static struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = nforce2_access,
+ .functionality = nforce2_func,
+};
+
static struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
@@ -267,7 +205,6 @@ static struct pci_device_id nforce2_ids[] = {
{ 0 }
};
-
MODULE_DEVICE_TABLE (pci, nforce2_ids);
@@ -291,7 +228,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
}
smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
- smbus->size = 8;
+ smbus->size = 64;
}
smbus->dev = dev;
@@ -300,7 +237,9 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
smbus->base, smbus->base+smbus->size-1, name);
return -1;
}
- smbus->adapter = nforce2_adapter;
+ smbus->adapter.owner = THIS_MODULE;
+ smbus->adapter.class = I2C_CLASS_HWMON;
+ smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
smbus->adapter.dev.parent = &dev->dev;
snprintf(smbus->adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 5928240..f28a76d 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -9,7 +9,6 @@
* kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -144,7 +143,7 @@ static void ocores_process(struct ocores_i2c *i2c)
}
}
-static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ocores_isr(int irq, void *dev_id)
{
struct ocores_i2c *i2c = dev_id;
@@ -199,7 +198,7 @@ static u32 ocores_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm ocores_algorithm = {
+static const struct i2c_algorithm ocores_algorithm = {
.master_xfer = ocores_xfer,
.functionality = ocores_func,
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
new file mode 100644
index 0000000..bcd8367
--- /dev/null
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -0,0 +1,676 @@
+/*
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Updated to work with multiple I2C interfaces on 24xx by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+#define OMAP_I2C_REV_REG 0x00
+#define OMAP_I2C_IE_REG 0x04
+#define OMAP_I2C_STAT_REG 0x08
+#define OMAP_I2C_IV_REG 0x0c
+#define OMAP_I2C_SYSS_REG 0x10
+#define OMAP_I2C_BUF_REG 0x14
+#define OMAP_I2C_CNT_REG 0x18
+#define OMAP_I2C_DATA_REG 0x1c
+#define OMAP_I2C_SYSC_REG 0x20
+#define OMAP_I2C_CON_REG 0x24
+#define OMAP_I2C_OA_REG 0x28
+#define OMAP_I2C_SA_REG 0x2c
+#define OMAP_I2C_PSC_REG 0x30
+#define OMAP_I2C_SCLL_REG 0x34
+#define OMAP_I2C_SCLH_REG 0x38
+#define OMAP_I2C_SYSTEST_REG 0x3c
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+#endif
+
+/* I2C System Status register (OMAP_I2C_SYSS): */
+#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
+
+/* I2C System Configuration Register (OMAP_I2C_SYSC): */
+#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+
+/* REVISIT: Use platform_data instead of module parameters */
+/* Fast Mode = 400 kHz, Standard = 100 kHz */
+static int clock = 100; /* Default: 100 kHz */
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
+
+struct omap_i2c_dev {
+ struct device *dev;
+ void __iomem *base; /* virtual */
+ int irq;
+ struct clk *iclk; /* Interface clock */
+ struct clk *fclk; /* Functional clock */
+ struct completion cmd_complete;
+ struct resource *ioarea;
+ u16 cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ unsigned rev1:1;
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+{
+ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ dev->iclk = clk_get(dev->dev, "i2c_ick");
+ if (IS_ERR(dev->iclk)) {
+ dev->iclk = NULL;
+ return -ENODEV;
+ }
+ }
+
+ dev->fclk = clk_get(dev->dev, "i2c_fck");
+ if (IS_ERR(dev->fclk)) {
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+ dev->fclk = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
+{
+ clk_put(dev->fclk);
+ dev->fclk = NULL;
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+}
+
+static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_enable(dev->iclk);
+ clk_enable(dev->fclk);
+}
+
+static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_disable(dev->iclk);
+ clk_disable(dev->fclk);
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+ u16 psc = 0;
+ unsigned long fclk_rate = 12000000;
+ unsigned long timeout;
+
+ if (!dev->rev1) {
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+ /* For some reason we need to set the EN bit before the
+ * reset done bit gets set. */
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+ OMAP_I2C_SYSS_RDONE)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting"
+ "for controller reset\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+ if (cpu_class_is_omap1()) {
+ struct clk *armxor_ck;
+
+ armxor_ck = clk_get(NULL, "armxor_ck");
+ if (IS_ERR(armxor_ck))
+ dev_warn(dev->dev, "Could not get armxor_ck\n");
+ else {
+ fclk_rate = clk_get_rate(armxor_ck);
+ clk_put(armxor_ck);
+ }
+ /* TRM for 5912 says the I2C clock must be prescaled to be
+ * between 7 - 12 MHz. The XOR input clock is typically
+ * 12, 13 or 19.2 MHz. So we should have code that produces:
+ *
+ * XOR MHz Divider Prescaler
+ * 12 1 0
+ * 13 2 1
+ * 19.2 2 1
+ */
+ if (fclk_rate > 12000000)
+ psc = fclk_rate / 12000000;
+ }
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+ /* Enable interrupts */
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
+ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL));
+ return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int r;
+ u16 w;
+
+ dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+ if (stop)
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ omap_i2c_init(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (likely(!dev->cmd_err))
+ return 0;
+
+ /* We have an error */
+ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+ OMAP_I2C_STAT_XUDF)) {
+ omap_i2c_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int r;
+
+ omap_i2c_enable_clocks(dev);
+
+ /* REVISIT: initialize and use adap->retries. This is an optional
+ * feature */
+ if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+ goto out;
+
+ for (i = 0; i < num; i++) {
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (r == 0)
+ r = num;
+out:
+ omap_i2c_disable_clocks(dev);
+ return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
+{
+ dev->cmd_err |= err;
+ complete(&dev->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
+{
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+}
+
+static irqreturn_t
+omap_i2c_rev1_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 iv, w;
+
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x00: /* None */
+ break;
+ case 0x01: /* Arbitration lost */
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ break;
+ case 0x03: /* Register access ready */
+ omap_i2c_complete_cmd(dev, 0);
+ break;
+ case 0x04: /* Receive data ready */
+ if (dev->buf_len) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+ break;
+ case 0x05: /* Transmit data ready */
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+ break;
+ default:
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+omap_i2c_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 bits;
+ u16 stat, w;
+ int count = 0;
+
+ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+ dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+
+ if (stat & OMAP_I2C_STAT_ARDY) {
+ omap_i2c_complete_cmd(dev, 0);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_RRDY) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ if (dev->buf_len) {
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data"
+ "requested\n");
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_XRDY) {
+ w = 0;
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no"
+ "data to send\n");
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err(dev->dev, "Receive overrun\n");
+ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ }
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err(dev->dev, "Transmit overflow\n");
+ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ }
+ if (stat & OMAP_I2C_STAT_NACK) {
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
+ }
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static int
+omap_i2c_probe(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ if (clock > 200)
+ clock = 400; /* Fast mode */
+ else
+ clock = 100; /* Standard mode */
+
+ dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ dev->dev = &pdev->dev;
+ dev->irq = irq->start;
+ dev->base = (void __iomem *) IO_ADDRESS(mem->start);
+ platform_set_drvdata(pdev, dev);
+
+ if ((r = omap_i2c_get_clocks(dev)) != 0)
+ goto err_free_mem;
+
+ omap_i2c_enable_clocks(dev);
+
+ if (cpu_is_omap15xx())
+ dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_init(dev);
+
+ r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
+ 0, pdev->name, dev);
+
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+ r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
+ pdev->id, r >> 4, r & 0xf, clock);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ r = i2c_add_adapter(adap);
+ if (r) {
+ dev_err(dev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ omap_i2c_disable_clocks(dev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ omap_i2c_disable_clocks(dev);
+ omap_i2c_put_clocks(dev);
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+err_release_region:
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int
+omap_i2c_remove(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_irq(dev->irq, dev);
+ i2c_del_adapter(&dev->adapter);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ omap_i2c_put_clocks(dev);
+ kfree(dev);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver omap_i2c_driver = {
+ .probe = omap_i2c_probe,
+ .remove = omap_i2c_remove,
+ .driver = {
+ .name = "i2c_omap",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+ return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index e09ebbb..4bc4281 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -103,7 +103,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 50,
- .mdelay = 50,
.timeout = HZ,
};
@@ -164,7 +163,7 @@ static void __exit i2c_parport_exit(void)
if (adapter_parm[type].init.val)
line_set(0, &adapter_parm[type].init);
- i2c_bit_del_bus(&parport_adapter);
+ i2c_del_adapter(&parport_adapter);
release_region(base, 3);
}
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 934bd55..66696a4 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -138,7 +138,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 60,
- .mdelay = 60,
.timeout = HZ,
};
@@ -219,7 +218,7 @@ static void i2c_parport_detach (struct parport *port)
if (adapter_parm[type].init.val)
line_set(port, 0, &adapter_parm[type].init);
- i2c_bit_del_bus(&adapter->adapter);
+ i2c_del_adapter(&adapter->adapter);
parport_unregister_device(adapter->pdev);
if (prev)
prev->next = adapter->next;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index d9b4ddb..cc6536a 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -99,7 +99,7 @@ static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap)
return ret;
}
-static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+static irqreturn_t pca_handler(int this_irq, void *dev_id) {
wake_up_interruptible(&pca_wait);
return IRQ_HANDLED;
}
@@ -156,7 +156,7 @@ static int __init pca_isa_init(void)
static void pca_isa_exit(void)
{
- i2c_pca_del_bus(&pca_isa_ops);
+ i2c_del_adapter(&pca_isa_ops);
if (irq > 0) {
disable_irq(irq);
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 8f2f65b..30c7a1b 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -376,7 +376,7 @@ static u32 piix4_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = piix4_access,
.functionality = piix4_func,
};
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
new file mode 100644
index 0000000..de0bca7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -0,0 +1,708 @@
+/*
+ * Provides I2C support for Philips PNX010x/PNX4008 boards.
+ *
+ * Authors: Dennis Kovalev <dkovalev@ru.mvista.com>
+ * Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-pnx.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define I2C_PNX_TIMEOUT 10 /* msec */
+#define I2C_PNX_SPEED_KHZ 100
+#define I2C_PNX_REGION_SIZE 0x100
+#define PNX_DEFAULT_FREQ 13 /* MHz */
+
+static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+{
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(data)) & mstatus_active)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+{
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *data = adap->algo_data;
+ struct timer_list *timer = &data->mif.timer;
+ int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+
+ del_timer_sync(timer);
+
+ dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
+ jiffies, expires);
+
+ timer->expires = jiffies + expires;
+ timer->data = (unsigned long)adap;
+
+ add_timer(timer);
+}
+
+/**
+ * i2c_pnx_start - start a device
+ * @slave_addr: slave address
+ * @adap: pointer to adapter structure
+ *
+ * Generate a START signal in the desired mode.
+ */
+static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+
+ dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__,
+ slave_addr, alg_data->mif.mode);
+
+ /* Check for 7 bit slave addresses only */
+ if (slave_addr & ~0x7f) {
+ dev_err(&adap->dev, "%s: Invalid slave address %x. "
+ "Only 7-bit addresses are supported\n",
+ adap->name, slave_addr);
+ return -EINVAL;
+ }
+
+ /* First, make sure bus is idle */
+ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
+ /* Somebody else is monopolizing the bus */
+ dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, "
+ "cntrl = %x, stat = %x\n",
+ adap->name, slave_addr,
+ ioread32(I2C_REG_CTL(alg_data)),
+ ioread32(I2C_REG_STS(alg_data)));
+ return -EBUSY;
+ } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
+ /* Sorry, we lost the bus */
+ dev_err(&adap->dev, "%s: Arbitration failure. "
+ "Slave addr = %02x\n", adap->name, slave_addr);
+ return -EIO;
+ }
+
+ /*
+ * OK, I2C is enabled and we have the bus.
+ * Clear the current TDI and AFI status flags.
+ */
+ iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
+ I2C_REG_STS(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__,
+ (slave_addr << 1) | start_bit | alg_data->mif.mode);
+
+ /* Write the slave address, START bit and R/W bit */
+ iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
+ I2C_REG_TX(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__);
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_stop - stop a device
+ * @adap: pointer to I2C adapter structure
+ *
+ * Generate a STOP signal to terminate the master transaction.
+ */
+static void i2c_pnx_stop(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ /* Only 1 msec max timeout due to interrupt context */
+ long timeout = 1000;
+
+ dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ /* Write a STOP bit to TX FIFO */
+ iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
+
+ /* Wait until the STOP is seen. */
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) {
+ /* may be called from interrupt context */
+ udelay(1);
+ timeout--;
+ }
+
+ dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+}
+
+/**
+ * i2c_pnx_master_xmit - transmit data to slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Sends one byte of data to the slave
+ */
+static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 val;
+
+ dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (alg_data->mif.len > 0) {
+ /* We still have something to talk about... */
+ val = *alg_data->mif.buf++;
+
+ if (alg_data->mif.len == 1) {
+ val |= stop_bit;
+ if (!alg_data->last)
+ val |= start_bit;
+ }
+
+ alg_data->mif.len--;
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__,
+ val, alg_data->mif.len + 1);
+
+ if (alg_data->mif.len == 0) {
+ if (alg_data->last) {
+ /* Wait until the STOP is seen. */
+ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ dev_err(&adap->dev, "The bus is still "
+ "active after timeout\n");
+ }
+ /* Disable master interrupts */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ del_timer_sync(&alg_data->mif.timer);
+
+ dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
+ __FUNCTION__);
+
+ complete(&alg_data->mif.complete);
+ }
+ } else if (alg_data->mif.len == 0) {
+ /* zero-sized transfer */
+ i2c_pnx_stop(adap);
+
+ /* Disable master interrupts. */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ /* Stop timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
+ "zero-xfer.\n", __FUNCTION__);
+
+ complete(&alg_data->mif.complete);
+ }
+
+ dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_master_rcv - receive data from slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Reads one byte data from the slave
+ */
+static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ unsigned int val = 0;
+ u32 ctl = 0;
+
+ dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ /* Check, whether there is already data,
+ * or we didn't 'ask' for it yet.
+ */
+ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
+ dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
+ "Rx-fifo...\n", __FUNCTION__);
+
+ if (alg_data->mif.len == 1) {
+ /* Last byte, do not acknowledge next rcv. */
+ val |= stop_bit;
+ if (!alg_data->last)
+ val |= start_bit;
+
+ /*
+ * Enable interrupt RFDAIE (data in Rx fifo),
+ * and disable DRMIE (need data for Tx)
+ */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl |= mcntrl_rffie | mcntrl_daie;
+ ctl &= ~mcntrl_drmie;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ }
+
+ /*
+ * Now we'll 'ask' for data:
+ * For each byte we want to receive, we must
+ * write a (dummy) byte to the Tx-FIFO.
+ */
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ return 0;
+ }
+
+ /* Handle data. */
+ if (alg_data->mif.len > 0) {
+ val = ioread32(I2C_REG_RX(alg_data));
+ *alg_data->mif.buf++ = (u8) (val & 0xff);
+ dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val,
+ alg_data->mif.len);
+
+ alg_data->mif.len--;
+ if (alg_data->mif.len == 0) {
+ if (alg_data->last)
+ /* Wait until the STOP is seen. */
+ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ dev_err(&adap->dev, "The bus is still "
+ "active after timeout\n");
+
+ /* Disable master interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie | mcntrl_daie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Kill timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ }
+ }
+
+ dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+static irqreturn_t
+i2c_pnx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ u32 stat, ctl;
+ struct i2c_adapter *adap = dev_id;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+
+ dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
+ __FUNCTION__,
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)),
+ alg_data->mif.mode);
+ stat = ioread32(I2C_REG_STS(alg_data));
+
+ /* let's see what kind of event this is */
+ if (stat & mstatus_afi) {
+ /* We lost arbitration in the midst of a transfer */
+ alg_data->mif.ret = -EIO;
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else if (stat & mstatus_nai) {
+ /* Slave did not acknowledge, generate a STOP */
+ dev_dbg(&adap->dev, "%s(): "
+ "Slave did not acknowledge, generating a STOP.\n",
+ __FUNCTION__);
+ i2c_pnx_stop(adap);
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Our return value. */
+ alg_data->mif.ret = -EIO;
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else {
+ /*
+ * Two options:
+ * - Master Tx needs data.
+ * - There is data in the Rx-fifo
+ * The latter is only the case if we have requested for data,
+ * via a dummy write. (See 'i2c_pnx_master_rcv'.)
+ * We therefore check, as a sanity check, whether that interrupt
+ * has been enabled.
+ */
+ if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
+ if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
+ i2c_pnx_master_xmit(adap);
+ } else if (alg_data->mif.mode == I2C_SMBUS_READ) {
+ i2c_pnx_master_rcv(adap);
+ }
+ }
+ }
+
+ /* Clear TDI and AFI bits */
+ stat = ioread32(I2C_REG_STS(alg_data));
+ iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_pnx_timeout(unsigned long data)
+{
+ struct i2c_adapter *adap = (struct i2c_adapter *)data;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 ctl;
+
+ dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. "
+ "Resetting master...\n",
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ /* Reset master and disable interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ ctl |= mcntrl_reset;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ alg_data->mif.ret = -EIO;
+ complete(&alg_data->mif.complete);
+}
+
+static inline void bus_reset_if_active(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 stat;
+
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
+ dev_err(&adap->dev,
+ "%s: Bus is still active after xfer. Reset it...\n",
+ adap->name);
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
+ /* If there is data in the fifo's after transfer,
+ * flush fifo's by reset.
+ */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ } else if (stat & mstatus_nai) {
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ }
+}
+
+/**
+ * i2c_pnx_xfer - generic transfer entry point
+ * @adap: pointer to I2C adapter structure
+ * @msgs: array of messages
+ * @num: number of messages
+ *
+ * Initiates the transfer
+ */
+static int
+i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int rc = 0, completed = 0, i;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 stat = ioread32(I2C_REG_STS(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
+ __FUNCTION__, num, ioread32(I2C_REG_STS(alg_data)));
+
+ bus_reset_if_active(adap);
+
+ /* Process transactions in a loop. */
+ for (i = 0; rc >= 0 && i < num; i++) {
+ u8 addr;
+
+ pmsg = &msgs[i];
+ addr = pmsg->addr;
+
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&adap->dev,
+ "%s: 10 bits addr not supported!\n",
+ adap->name);
+ rc = -EINVAL;
+ break;
+ }
+
+ alg_data->mif.buf = pmsg->buf;
+ alg_data->mif.len = pmsg->len;
+ alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
+ I2C_SMBUS_READ : I2C_SMBUS_WRITE;
+ alg_data->mif.ret = 0;
+ alg_data->last = (i == num - 1);
+
+ dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__,
+ alg_data->mif.mode,
+ alg_data->mif.len);
+
+ i2c_pnx_arm_timer(adap);
+
+ /* initialize the completion var */
+ init_completion(&alg_data->mif.complete);
+
+ /* Enable master interrupt */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie |
+ mcntrl_naie | mcntrl_drmie,
+ I2C_REG_CTL(alg_data));
+
+ /* Put start-code and slave-address on the bus. */
+ rc = i2c_pnx_start(addr, adap);
+ if (rc < 0)
+ break;
+
+ /* Wait for completion */
+ wait_for_completion(&alg_data->mif.complete);
+
+ if (!(rc = alg_data->mif.ret))
+ completed++;
+ dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
+ __FUNCTION__, rc);
+
+ /* Clear TDI and AFI bits in case they are set. */
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
+ dev_dbg(&adap->dev,
+ "%s: TDI still set... clearing now.\n",
+ adap->name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
+ dev_dbg(&adap->dev,
+ "%s: AFI still set... clearing now.\n",
+ adap->name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ }
+
+ bus_reset_if_active(adap);
+
+ /* Cleanup to be sure... */
+ alg_data->mif.buf = NULL;
+ alg_data->mif.len = 0;
+
+ dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (completed != num)
+ return ((rc < 0) ? rc : -EREMOTEIO);
+
+ return num;
+}
+
+static u32 i2c_pnx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm pnx_algorithm = {
+ .master_xfer = i2c_pnx_xfer,
+ .functionality = i2c_pnx_func,
+};
+
+static int i2c_pnx_controller_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
+ return i2c_pnx->suspend(pdev, state);
+}
+
+static int i2c_pnx_controller_resume(struct platform_device *pdev)
+{
+ struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
+ return i2c_pnx->resume(pdev);
+}
+
+static int __devinit i2c_pnx_probe(struct platform_device *pdev)
+{
+ unsigned long tmp;
+ int ret = 0;
+ struct i2c_pnx_algo_data *alg_data;
+ int freq_mhz;
+ struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
+
+ if (!i2c_pnx || !i2c_pnx->adapter) {
+ dev_err(&pdev->dev, "%s: no platform data supplied\n",
+ __FUNCTION__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, i2c_pnx);
+
+ if (i2c_pnx->calculate_input_freq)
+ freq_mhz = i2c_pnx->calculate_input_freq(pdev);
+ else {
+ freq_mhz = PNX_DEFAULT_FREQ;
+ dev_info(&pdev->dev, "Setting bus frequency to default value: "
+ "%d MHz", freq_mhz);
+ }
+
+ i2c_pnx->adapter->algo = &pnx_algorithm;
+
+ alg_data = i2c_pnx->adapter->algo_data;
+ init_timer(&alg_data->mif.timer);
+ alg_data->mif.timer.function = i2c_pnx_timeout;
+ alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
+
+ /* Register I/O resource */
+ if (!request_region(alg_data->base, I2C_PNX_REGION_SIZE, pdev->name)) {
+ dev_err(&pdev->dev,
+ "I/O region 0x%08x for I2C already in use.\n",
+ alg_data->base);
+ ret = -ENODEV;
+ goto out_drvdata;
+ }
+
+ if (!(alg_data->ioaddr =
+ (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) {
+ dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
+ ret = -ENOMEM;
+ goto out_release;
+ }
+
+ i2c_pnx->set_clock_run(pdev);
+
+ /*
+ * Clock Divisor High This value is the number of system clocks
+ * the serial clock (SCL) will be high.
+ * For example, if the system clock period is 50 ns and the maximum
+ * desired serial period is 10000 ns (100 kHz), then CLKHI would be
+ * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value
+ * programmed into CLKHI will vary from this slightly due to
+ * variations in the output pad's rise and fall times as well as
+ * the deglitching filter length.
+ */
+
+ tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ iowrite32(tmp, I2C_REG_CKH(alg_data));
+ iowrite32(tmp, I2C_REG_CKL(alg_data));
+
+ iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
+ if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
+ ret = -ENODEV;
+ goto out_unmap;
+ }
+ init_completion(&alg_data->mif.complete);
+
+ ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
+ 0, pdev->name, i2c_pnx->adapter);
+ if (ret)
+ goto out_clock;
+
+ /* Register this adapter with the I2C subsystem */
+ i2c_pnx->adapter->dev.parent = &pdev->dev;
+ ret = i2c_add_adapter(i2c_pnx->adapter);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "I2C: Failed to add bus\n");
+ goto out_irq;
+ }
+
+ dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
+ i2c_pnx->adapter->name, alg_data->base, alg_data->irq);
+
+ return 0;
+
+out_irq:
+ free_irq(alg_data->irq, alg_data);
+out_clock:
+ i2c_pnx->set_clock_stop(pdev);
+out_unmap:
+ iounmap((void *)alg_data->ioaddr);
+out_release:
+ release_region(alg_data->base, I2C_PNX_REGION_SIZE);
+out_drvdata:
+ platform_set_drvdata(pdev, NULL);
+out:
+ return ret;
+}
+
+static int __devexit i2c_pnx_remove(struct platform_device *pdev)
+{
+ struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
+ struct i2c_adapter *adap = i2c_pnx->adapter;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+
+ free_irq(alg_data->irq, alg_data);
+ i2c_del_adapter(adap);
+ i2c_pnx->set_clock_stop(pdev);
+ iounmap((void *)alg_data->ioaddr);
+ release_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver i2c_pnx_driver = {
+ .driver = {
+ .name = "pnx-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2c_pnx_probe,
+ .remove = __devexit_p(i2c_pnx_remove),
+ .suspend = i2c_pnx_controller_suspend,
+ .resume = i2c_pnx_controller_resume,
+};
+
+static int __init i2c_adap_pnx_init(void)
+{
+ return platform_driver_register(&i2c_pnx_driver);
+}
+
+static void __exit i2c_adap_pnx_exit(void)
+{
+ platform_driver_unregister(&i2c_pnx_driver);
+}
+
+MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
+MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_I2C_PNX_EARLY
+/* We need to make sure I2C is initialized before USB */
+subsys_initcall(i2c_adap_pnx_init);
+#else
+mudule_init(i2c_adap_pnx_init);
+#endif
+module_exit(i2c_adap_pnx_exit);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index d658d91..648d555 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -175,16 +175,16 @@ static u32 i2c_powermac_func(struct i2c_adapter * adapter)
}
/* For now, we only handle smbus */
-static struct i2c_algorithm i2c_powermac_algorithm = {
+static const struct i2c_algorithm i2c_powermac_algorithm = {
.smbus_xfer = i2c_powermac_smbus_xfer,
.master_xfer = i2c_powermac_master_xfer,
.functionality = i2c_powermac_func,
};
-static int i2c_powermac_remove(struct device *dev)
+static int i2c_powermac_remove(struct platform_device *dev)
{
- struct i2c_adapter *adapter = dev_get_drvdata(dev);
+ struct i2c_adapter *adapter = platform_get_drvdata(dev);
struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
int rc;
@@ -195,16 +195,16 @@ static int i2c_powermac_remove(struct device *dev)
if (rc)
printk("i2c-powermac.c: Failed to remove bus %s !\n",
adapter->name);
- dev_set_drvdata(dev, NULL);
+ platform_set_drvdata(dev, NULL);
kfree(adapter);
return 0;
}
-static int i2c_powermac_probe(struct device *dev)
+static int __devexit i2c_powermac_probe(struct platform_device *dev)
{
- struct pmac_i2c_bus *bus = dev->platform_data;
+ struct pmac_i2c_bus *bus = dev->dev.platform_data;
struct device_node *parent = NULL;
struct i2c_adapter *adapter;
char name[32];
@@ -246,11 +246,11 @@ static int i2c_powermac_probe(struct device *dev)
printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
return -ENOMEM;
}
- dev_set_drvdata(dev, adapter);
+ platform_set_drvdata(dev, adapter);
strcpy(adapter->name, name);
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
- adapter->dev.parent = dev;
+ adapter->dev.parent = &dev->dev;
pmac_i2c_attach_adapter(bus, adapter);
rc = i2c_add_adapter(adapter);
if (rc) {
@@ -265,23 +265,25 @@ static int i2c_powermac_probe(struct device *dev)
}
-static struct device_driver i2c_powermac_driver = {
- .name = "i2c-powermac",
- .bus = &platform_bus_type,
+static struct platform_driver i2c_powermac_driver = {
.probe = i2c_powermac_probe,
- .remove = i2c_powermac_remove,
+ .remove = __devexit_p(i2c_powermac_remove),
+ .driver = {
+ .name = "i2c-powermac",
+ .bus = &platform_bus_type,
+ },
};
static int __init i2c_powermac_init(void)
{
- driver_register(&i2c_powermac_driver);
+ platform_driver_register(&i2c_powermac_driver);
return 0;
}
static void __exit i2c_powermac_cleanup(void)
{
- driver_unregister(&i2c_powermac_driver);
+ platform_driver_unregister(&i2c_powermac_driver);
}
module_init(i2c_powermac_init);
diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
index 9479525..07c1f1e 100644
--- a/drivers/i2c/busses/i2c-prosavage.c
+++ b/drivers/i2c/busses/i2c-prosavage.c
@@ -180,7 +180,6 @@ static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iom
p->algo.getsda = bit_s3via_getsda;
p->algo.getscl = bit_s3via_getscl;
p->algo.udelay = CYCLE_DELAY;
- p->algo.mdelay = CYCLE_DELAY;
p->algo.timeout = TIMEOUT;
p->algo.data = p;
p->mmvga = mmvga;
@@ -213,7 +212,7 @@ static void prosavage_remove(struct pci_dev *dev)
if (chip->i2c_bus[i].adap_ok == 0)
continue;
- ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
+ ret = i2c_del_adapter(&chip->i2c_bus[i].adap);
if (ret) {
dev_err(&dev->dev, "%s not removed\n",
chip->i2c_bus[i].adap.name);
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index ee114b4..c3b1567 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -272,7 +272,8 @@ static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
__func__, (long)jiffies, ISR, ICR, IBMR);
- if ((ISR & (ISR_UB|ISR_IBB|ISR_SAD)) == ISR_SAD ||
+ if ((ISR & (ISR_UB|ISR_IBB)) == 0 ||
+ (ISR & ISR_SAD) != 0 ||
(ICR & ICR_SCLE) == 0) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
@@ -357,133 +358,6 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c)
#ifdef CONFIG_I2C_PXA_SLAVE
/*
- * I2C EEPROM emulation.
- */
-static struct i2c_eeprom_emu eeprom = {
- .size = I2C_EEPROM_EMU_SIZE,
- .watch = LIST_HEAD_INIT(eeprom.watch),
-};
-
-struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void)
-{
- return &eeprom;
-}
-
-int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *emu, void *data,
- unsigned int addr, unsigned int size,
- struct i2c_eeprom_emu_watcher *watcher)
-{
- struct i2c_eeprom_emu_watch *watch;
- unsigned long flags;
-
- if (addr + size > emu->size)
- return -EINVAL;
-
- watch = kmalloc(sizeof(struct i2c_eeprom_emu_watch), GFP_KERNEL);
- if (watch) {
- watch->start = addr;
- watch->end = addr + size - 1;
- watch->ops = watcher;
- watch->data = data;
-
- local_irq_save(flags);
- list_add(&watch->node, &emu->watch);
- local_irq_restore(flags);
- }
-
- return watch ? 0 : -ENOMEM;
-}
-
-void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *emu, void *data,
- struct i2c_eeprom_emu_watcher *watcher)
-{
- struct i2c_eeprom_emu_watch *watch, *n;
- unsigned long flags;
-
- list_for_each_entry_safe(watch, n, &emu->watch, node) {
- if (watch->ops == watcher && watch->data == data) {
- local_irq_save(flags);
- list_del(&watch->node);
- local_irq_restore(flags);
- kfree(watch);
- }
- }
-}
-
-static void i2c_eeprom_emu_event(void *ptr, i2c_slave_event_t event)
-{
- struct i2c_eeprom_emu *emu = ptr;
-
- eedbg(3, "i2c_eeprom_emu_event: %d\n", event);
-
- switch (event) {
- case I2C_SLAVE_EVENT_START_WRITE:
- emu->seen_start = 1;
- eedbg(2, "i2c_eeprom: write initiated\n");
- break;
-
- case I2C_SLAVE_EVENT_START_READ:
- emu->seen_start = 0;
- eedbg(2, "i2c_eeprom: read initiated\n");
- break;
-
- case I2C_SLAVE_EVENT_STOP:
- emu->seen_start = 0;
- eedbg(2, "i2c_eeprom: received stop\n");
- break;
-
- default:
- eedbg(0, "i2c_eeprom: unhandled event\n");
- break;
- }
-}
-
-static int i2c_eeprom_emu_read(void *ptr)
-{
- struct i2c_eeprom_emu *emu = ptr;
- int ret;
-
- ret = emu->bytes[emu->ptr];
- emu->ptr = (emu->ptr + 1) % emu->size;
-
- return ret;
-}
-
-static void i2c_eeprom_emu_write(void *ptr, unsigned int val)
-{
- struct i2c_eeprom_emu *emu = ptr;
- struct i2c_eeprom_emu_watch *watch;
-
- if (emu->seen_start != 0) {
- eedbg(2, "i2c_eeprom_emu_write: setting ptr %02x\n", val);
- emu->ptr = val;
- emu->seen_start = 0;
- return;
- }
-
- emu->bytes[emu->ptr] = val;
-
- eedbg(1, "i2c_eeprom_emu_write: ptr=0x%02x, val=0x%02x\n",
- emu->ptr, val);
-
- list_for_each_entry(watch, &emu->watch, node) {
- if (!watch->ops || !watch->ops->write)
- continue;
- if (watch->start <= emu->ptr && watch->end >= emu->ptr)
- watch->ops->write(watch->data, emu->ptr, val);
- }
-
- emu->ptr = (emu->ptr + 1) % emu->size;
-}
-
-struct i2c_slave_client eeprom_client = {
- .data = &eeprom,
- .event = i2c_eeprom_emu_event,
- .read = i2c_eeprom_emu_read,
- .write = i2c_eeprom_emu_write
-};
-
-/*
* PXA I2C Slave mode
*/
@@ -492,7 +366,10 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
if (isr & ISR_BED) {
/* what should we do here? */
} else {
- int ret = i2c->slave->read(i2c->slave->data);
+ int ret = 0;
+
+ if (i2c->slave != NULL)
+ ret = i2c->slave->read(i2c->slave->data);
IDBR = ret;
ICR |= ICR_TB; /* allow next byte */
@@ -850,7 +727,7 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
ICR = icr;
}
-static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
{
struct pxa_i2c *i2c = dev_id;
u32 isr = ISR;
@@ -926,7 +803,7 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm i2c_pxa_algorithm = {
+static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer = i2c_pxa_xfer,
.functionality = i2c_pxa_functionality,
};
@@ -959,11 +836,9 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
#ifdef CONFIG_I2C_PXA_SLAVE
- i2c->slave = &eeprom_client;
if (plat) {
i2c->slave_addr = plat->slave_addr;
- if (plat->slave)
- i2c->slave = plat->slave;
+ i2c->slave = plat->slave;
}
#endif
diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
index 0ebec3c..8764df0 100644
--- a/drivers/i2c/busses/i2c-rpx.c
+++ b/drivers/i2c/busses/i2c-rpx.c
@@ -55,10 +55,10 @@ rpx_iic_init(struct i2c_algo_8xx_data *data)
data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
}
-static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
+static int rpx_install_isr(int irq, void (*func)(void *), void *data)
{
/* install interrupt handler */
- cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
+ cpm_install_handler(irq, func, data);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 5d2950e..4ca6de2 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -423,8 +423,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
* top level IRQ servicing routine
*/
-static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
struct s3c24xx_i2c *i2c = dev_id;
unsigned long status;
@@ -566,7 +565,7 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
/* i2c bus registration info */
-static struct i2c_algorithm s3c24xx_i2c_algorithm = {
+static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index 0c85182..844b4ff 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -140,7 +140,6 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = {
.getsda = bit_savi2c_getsda,
.getscl = bit_savi2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
@@ -174,7 +173,7 @@ static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_
static void __devexit savage4_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&savage4_i2c_adapter);
+ i2c_del_adapter(&savage4_i2c_adapter);
iounmap(ioaddr);
}
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
index fa503ed..0ca599d 100644
--- a/drivers/i2c/busses/i2c-sibyte.c
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2004 Steven J. Hill
* Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 1995-2000 Simon G. Vogl
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -17,11 +18,162 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c-algo-sibyte.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_smbus.h>
+
+struct i2c_algo_sibyte_data {
+ void *data; /* private data */
+ int bus; /* which bus */
+ void *reg_base; /* CSR base */
+};
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+/* ----- global variables --------------------------------------------- */
+
+/* module parameters:
+ */
+static int bit_scan; /* have a look at what's hanging 'round */
+module_param(bit_scan, int, 0);
+MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+ int data_bytes = 0;
+ int error;
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ csr_out32((V_SMB_ADDR(addr) |
+ (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_LB(data->byte),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 2;
+ } else {
+ csr_out32(V_SMB_LB(data->word & 0xff),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32(V_SMB_MB(data->word >> 8),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ default:
+ return -1; /* XXXKW better error code? */
+ }
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+ if (error & M_SMB_ERROR) {
+ /* Clear error bit by writing a 1 */
+ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+ return -1; /* XXXKW better error code? */
+ }
+
+ if (data_bytes == 1)
+ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+ if (data_bytes == 2)
+ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+ return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm i2c_sibyte_algo = {
+ .smbus_xfer = smbus_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+ int i;
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+ /* register new adapter to i2c module... */
+ i2c_adap->algo = &i2c_sibyte_algo;
+
+ /* Set the frequency to 100 kHz */
+ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+ /* scan bus */
+ if (bit_scan) {
+ union i2c_smbus_data data;
+ int rc;
+ printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
+ i2c_adap->name);
+ for (i = 0x00; i < 0x7f; i++) {
+ /* XXXKW is this a realistic probe? */
+ rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (!rc) {
+ printk("(%02x)",i);
+ } else
+ printk(".");
+ }
+ printk("\n");
+ }
+
+ return i2c_add_adapter(i2c_adap);
+}
+
+
static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
{ NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
{ NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
@@ -58,13 +210,13 @@ static int __init i2c_sibyte_init(void)
static void __exit i2c_sibyte_exit(void)
{
- i2c_sibyte_del_bus(&sibyte_board_adapter[0]);
- i2c_sibyte_del_bus(&sibyte_board_adapter[1]);
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ i2c_del_adapter(&sibyte_board_adapter[1]);
}
module_init(i2c_sibyte_init);
module_exit(i2c_sibyte_exit);
-MODULE_AUTHOR("Kip Walker <kwalker@broadcom.com>, Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index b57ab74..38bbfd8 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -358,7 +358,7 @@ static u32 sis5595_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis5595_access,
.functionality = sis5595_func,
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index acb75e2..dec0baf 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -450,7 +450,7 @@ exit:
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis630_access,
.functionality = sis630_func,
};
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 1a73c05..7fd07fb 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -242,7 +242,7 @@ static u32 sis96x_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis96x_access,
.functionality = sis96x_func,
};
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 73f481e..a54adc5 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -27,6 +27,10 @@
#include <linux/errno.h>
#include <linux/i2c.h>
+static unsigned short chip_addr;
+module_param(chip_addr, ushort, S_IRUGO);
+MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
+
static u8 stub_pointer;
static u8 stub_bytes[256];
static u16 stub_words[256];
@@ -37,6 +41,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
{
s32 ret;
+ if (addr != chip_addr)
+ return -ENODEV;
+
switch (size) {
case I2C_SMBUS_QUICK:
@@ -108,7 +115,7 @@ static u32 stub_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.functionality = stub_func,
.smbus_xfer = stub_xfer,
};
@@ -122,7 +129,17 @@ static struct i2c_adapter stub_adapter = {
static int __init i2c_stub_init(void)
{
- printk(KERN_INFO "i2c-stub loaded\n");
+ if (!chip_addr) {
+ printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+ return -ENODEV;
+ }
+ if (chip_addr < 0x03 || chip_addr > 0x77) {
+ printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
+ chip_addr);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
return i2c_add_adapter(&stub_adapter);
}
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
new file mode 100644
index 0000000..081d957
--- /dev/null
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -0,0 +1,153 @@
+/*
+ * i2c-versatile.c
+ *
+ * Copyright (C) 2006 ARM Ltd.
+ * written by Russell King, Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#define I2C_CONTROL 0x00
+#define I2C_CONTROLS 0x00
+#define I2C_CONTROLC 0x04
+#define SCL (1 << 0)
+#define SDA (1 << 1)
+
+struct i2c_versatile {
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data algo;
+ void __iomem *base;
+};
+
+static void i2c_versatile_setsda(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static void i2c_versatile_setscl(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static int i2c_versatile_getsda(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SDA);
+}
+
+static int i2c_versatile_getscl(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SCL);
+}
+
+static struct i2c_algo_bit_data i2c_versatile_algo = {
+ .setsda = i2c_versatile_setsda,
+ .setscl = i2c_versatile_setscl,
+ .getsda = i2c_versatile_getsda,
+ .getscl = i2c_versatile_getscl,
+ .udelay = 30,
+ .timeout = HZ,
+};
+
+static int i2c_versatile_probe(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c;
+ struct resource *r;
+ int ret;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) {
+ ret = -EBUSY;
+ goto err_out;
+ }
+
+ i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ i2c->base = ioremap(r->start, r->end - r->start + 1);
+ if (!i2c->base) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ writel(SCL | SDA, i2c->base + I2C_CONTROLS);
+
+ i2c->adap.owner = THIS_MODULE;
+ strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
+ i2c->adap.algo_data = &i2c->algo;
+ i2c->adap.dev.parent = &dev->dev;
+ i2c->algo = i2c_versatile_algo;
+ i2c->algo.data = i2c;
+
+ ret = i2c_bit_add_bus(&i2c->adap);
+ if (ret >= 0) {
+ platform_set_drvdata(dev, i2c);
+ return 0;
+ }
+
+ iounmap(i2c->base);
+ err_free:
+ kfree(i2c);
+ err_release:
+ release_mem_region(r->start, r->end - r->start + 1);
+ err_out:
+ return ret;
+}
+
+static int i2c_versatile_remove(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+}
+
+static struct platform_driver i2c_versatile_driver = {
+ .probe = i2c_versatile_probe,
+ .remove = i2c_versatile_remove,
+ .driver = {
+ .name = "versatile-i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_versatile_init(void)
+{
+ return platform_driver_register(&i2c_versatile_driver);
+}
+
+static void __exit i2c_versatile_exit(void)
+{
+ platform_driver_unregister(&i2c_versatile_driver);
+}
+
+module_init(i2c_versatile_init);
+module_exit(i2c_versatile_exit);
+
+MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 484bbac..15d7e00 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -81,7 +81,6 @@ static struct i2c_algo_bit_data bit_data = {
.getsda = bit_via_getsda,
.getscl = bit_via_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = HZ
};
@@ -152,7 +151,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i
static void __devexit vt586b_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&vt586b_adapter);
+ i2c_del_adapter(&vt586b_adapter);
release_region(I2C_DIR, IOSPACE);
pm_io_base = 0;
}
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 47e52bf..efc6bbf 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -34,6 +34,8 @@
VT8233A 0x3147 yes?
VT8235 0x3177 yes
VT8237R 0x3227 yes
+ VT8237A 0x3337 yes
+ VT8251 0x3287 yes
Note: we assume there can only be one device, with one SMBus interface.
*/
@@ -297,7 +299,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
return func;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = vt596_access,
.functionality = vt596_func,
};
@@ -381,7 +383,9 @@ found:
dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
switch (pdev->device) {
+ case PCI_DEVICE_ID_VIA_8251:
case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
case PCI_DEVICE_ID_VIA_8235:
case PCI_DEVICE_ID_VIA_8233A:
case PCI_DEVICE_ID_VIA_8233_0:
@@ -432,8 +436,12 @@ static struct pci_device_id vt596_ids[] = {
.driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
.driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+ .driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
.driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+ .driver_data = SMBBA3 },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
index b675773..b0377b8 100644
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ b/drivers/i2c/busses/i2c-voodoo3.c
@@ -160,7 +160,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
.getsda = bit_vooi2c_getsda,
.getscl = bit_vooi2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
@@ -177,7 +176,6 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = {
.getsda = bit_vooddc_getsda,
.getscl = bit_vooddc_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
@@ -213,14 +211,14 @@ static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_
return retval;
retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
if (retval)
- i2c_bit_del_bus(&voodoo3_i2c_adapter);
+ i2c_del_adapter(&voodoo3_i2c_adapter);
return retval;
}
static void __devexit voodoo3_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&voodoo3_i2c_adapter);
- i2c_bit_del_bus(&voodoo3_ddc_adapter);
+ i2c_del_adapter(&voodoo3_i2c_adapter);
+ i2c_del_adapter(&voodoo3_ddc_adapter);
iounmap(ioaddr);
}
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index eae9e81..714bae7 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -383,7 +383,7 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter)
}
/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm scx200_acb_algorithm = {
+static const struct i2c_algorithm scx200_acb_algorithm = {
.smbus_xfer = scx200_acb_smbus_xfer,
.functionality = scx200_acb_func,
};
@@ -494,11 +494,12 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
iface->pdev = pdev;
iface->bar = bar;
- pci_enable_device_bars(iface->pdev, 1 << iface->bar);
+ rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar);
+ if (rc)
+ goto errout_free;
rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
-
- if (rc != 0) {
+ if (rc) {
printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
iface->bar);
goto errout_free;
diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
index cb3ef5a..6cd96e4 100644
--- a/drivers/i2c/busses/scx200_i2c.c
+++ b/drivers/i2c/busses/scx200_i2c.c
@@ -1,4 +1,4 @@
-/* linux/drivers/i2c/scx200_i2c.c
+/* linux/drivers/i2c/busses/scx200_i2c.c
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
@@ -71,12 +71,12 @@ static int scx200_i2c_getsda(void *data)
*/
static struct i2c_algo_bit_data scx200_i2c_data = {
- NULL,
- scx200_i2c_setsda,
- scx200_i2c_setscl,
- scx200_i2c_getsda,
- scx200_i2c_getscl,
- 10, 10, 100, /* waits, timeout */
+ .setsda = scx200_i2c_setsda,
+ .setscl = scx200_i2c_setscl,
+ .getsda = scx200_i2c_getsda,
+ .getscl = scx200_i2c_getscl,
+ .udelay = 10,
+ .timeout = 100,
};
static struct i2c_adapter scx200_i2c_ops = {
@@ -116,7 +116,7 @@ static int scx200_i2c_init(void)
static void scx200_i2c_cleanup(void)
{
- i2c_bit_del_bus(&scx200_i2c_ops);
+ i2c_del_adapter(&scx200_i2c_ops);
}
module_init(scx200_i2c_init);