summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/Kconfig20
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c10
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c3
-rw-r--r--drivers/i2c/busses/Kconfig59
-rw-r--r--drivers/i2c/busses/Makefile6
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c4
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c10
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c4
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c3
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c7
-rw-r--r--drivers/i2c/busses/i2c-davinci.c1
-rw-r--r--drivers/i2c/busses/i2c-designware.c485
-rw-r--r--drivers/i2c/busses/i2c-elektor.c1
-rw-r--r--drivers/i2c/busses/i2c-gpio.c1
-rw-r--r--drivers/i2c/busses/i2c-highlander.c1
-rw-r--r--drivers/i2c/busses/i2c-hydra.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c16
-rw-r--r--drivers/i2c/busses/i2c-imx.c28
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c6
-rw-r--r--drivers/i2c/busses/i2c-isch.c68
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c1
-rw-r--r--drivers/i2c/busses/i2c-mpc.c195
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c4
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c3
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c960
-rw-r--r--drivers/i2c/busses/i2c-ocores.c1
-rw-r--r--drivers/i2c/busses/i2c-octeon.c652
-rw-r--r--drivers/i2c/busses/i2c-omap.c118
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c48
-rw-r--r--drivers/i2c/busses/i2c-parport.c44
-rw-r--r--drivers/i2c/busses/i2c-parport.h4
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c3
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c4
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c4
-rw-r--r--drivers/i2c/busses/i2c-piix4.c6
-rw-r--r--drivers/i2c/busses/i2c-pnx.c294
-rw-r--r--drivers/i2c/busses/i2c-powermac.c150
-rw-r--r--drivers/i2c/busses/i2c-pxa.c5
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c3
-rw-r--r--drivers/i2c/busses/i2c-scmi.c34
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c3
-rw-r--r--drivers/i2c/busses/i2c-simtec.c1
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c4
-rw-r--r--drivers/i2c/busses/i2c-sis630.c4
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-stu300.c1
-rw-r--r--drivers/i2c/busses/i2c-stub.c34
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c23
-rw-r--r--drivers/i2c/busses/i2c-versatile.c1
-rw-r--r--drivers/i2c/busses/i2c-via.c2
-rw-r--r--drivers/i2c/busses/i2c-viapro.c6
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c248
-rw-r--r--drivers/i2c/busses/i2c-xiic.c826
-rw-r--r--drivers/i2c/busses/scx200_acb.c1
-rw-r--r--drivers/i2c/chips/Kconfig29
-rw-r--r--drivers/i2c/chips/Makefile19
-rw-r--r--drivers/i2c/chips/ds1682.c267
-rw-r--r--drivers/i2c/chips/tsl2550.c473
-rw-r--r--drivers/i2c/i2c-boardinfo.c1
-rw-r--r--drivers/i2c/i2c-core.c276
-rw-r--r--drivers/i2c/i2c-dev.c22
-rw-r--r--drivers/i2c/i2c-smbus.c263
65 files changed, 3963 insertions, 1818 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index d7ece131b4f..d06083fdffb 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -5,6 +5,7 @@
menuconfig I2C
tristate "I2C support"
depends on HAS_IOMEM
+ select RT_MUTEXES
---help---
I2C (pronounce: I-square-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus,
@@ -60,9 +61,18 @@ config I2C_HELPER_AUTO
In doubt, say Y.
+config I2C_SMBUS
+ tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
+ help
+ Say Y here if you want support for SMBus extensions to the I2C
+ specification. At the moment, the only supported extension is
+ the SMBus alert protocol.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-smbus.
+
source drivers/i2c/algos/Kconfig
source drivers/i2c/busses/Kconfig
-source drivers/i2c/chips/Kconfig
config I2C_DEBUG_CORE
bool "I2C Core debugging messages"
@@ -87,12 +97,4 @@ config I2C_DEBUG_BUS
a problem with I2C support and want to see more of what is going
on.
-config I2C_DEBUG_CHIP
- bool "I2C Chip debugging messages"
- help
- Say Y here if you want the I2C chip drivers to produce a bunch of
- debug messages to the system log. Select this if you are having
- a problem with I2C support and want to see more of what is going
- on.
-
endif # I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index ba26e6cbe74..a7d9b4be9bb 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,8 +4,9 @@
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
-obj-y += busses/ chips/ algos/
+obj-y += algos/ busses/
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index e25e13980af..a39e6cff86e 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -24,7 +24,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -522,6 +521,12 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
int i, ret;
unsigned short nak_ok;
+ if (adap->pre_xfer) {
+ ret = adap->pre_xfer(i2c_adap);
+ if (ret < 0)
+ return ret;
+ }
+
bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
i2c_start(adap);
for (i = 0; i < num; i++) {
@@ -570,6 +575,9 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
bailout:
bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
i2c_stop(adap);
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
return ret;
}
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 78d42aae008..dcdaf8e675b 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -453,8 +453,6 @@ static int pca_init(struct i2c_adapter *adap)
*/
int raise_fall_time;
- struct i2c_algo_pca_data *pca_data = adap->algo_data;
-
/* Ignore the reset function from the module,
* we can use the parallel bus reset
*/
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 7ce75775ec7..5eebf562ff3 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/i2c.h>
@@ -176,7 +175,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
*/
if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
- return -ENXIO; /* definetly not PCF8584 */
+ return -ENXIO; /* definitely not PCF8584 */
}
/* load own address in S0, effective address is (own << 1) */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e8fe7f169e2..9c6170cd9aa 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -77,7 +77,7 @@ config I2C_AMD8111
will be called i2c-amd8111.
config I2C_I801
- tristate "Intel 82801 (ICH)"
+ tristate "Intel 82801 (ICH/PCH)"
depends on PCI
help
If you say yes to this option, support will be included for the Intel
@@ -97,7 +97,8 @@ config I2C_I801
ICH9
Tolapai
ICH10
- PCH
+ 3400/5 Series (PCH)
+ Cougar Point (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -105,6 +106,8 @@ config I2C_I801
config I2C_ISCH
tristate "Intel SCH SMBus 1.0"
depends on PCI
+ select MFD_CORE
+ select LPC_SCH
help
Say Y here if you want to use SMBus controller on the Intel SCH
based systems.
@@ -418,13 +421,12 @@ config I2C_IXP2000
instead.
config I2C_MPC
- tristate "MPC107/824x/85xx/52xx/86xx"
+ tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC32
help
If you say yes to this option, support will be included for the
- built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx/MPC8641 family processors. The driver may also work on 52xx
- family processors, though interrupts are known not to work.
+ built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
+ MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors.
This driver can also be built as a module. If so, the module
will be called i2c-mpc.
@@ -439,6 +441,13 @@ config I2C_MV64XXX
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_NOMADIK
+ tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
+ depends on PLAT_NOMADIK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
+
config I2C_OCORES
tristate "OpenCores I2C Controller"
depends on EXPERIMENTAL
@@ -564,12 +573,33 @@ config I2C_VERSATILE
This driver can also be built as a module. If so, the module
will be called i2c-versatile.
+config I2C_OCTEON
+ tristate "Cavium OCTEON I2C bus support"
+ depends on CPU_CAVIUM_OCTEON
+ help
+ Say yes if you want to support the I2C serial bus on Cavium
+ OCTEON SOC.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-octeon.
+
+config I2C_XILINX
+ tristate "Xilinx I2C Controller"
+ depends on EXPERIMENTAL && HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ Xilinx I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called xilinx_i2c.
+
comment "External I2C/SMBus adapter drivers"
config I2C_PARPORT
tristate "Parallel port adapter"
depends on PARPORT
select I2C_ALGOBIT
+ select I2C_SMBUS
help
This supports parallel port I2C adapters such as the ones made by
Philips or Velleman, Analog Devices evaluation boards, and more.
@@ -593,6 +623,7 @@ config I2C_PARPORT
config I2C_PARPORT_LIGHT
tristate "Parallel port adapter (light)"
select I2C_ALGOBIT
+ select I2C_SMBUS
help
This supports parallel port I2C adapters such as the ones made by
Philips or Velleman, Analog Devices evaluation boards, and more.
@@ -640,22 +671,6 @@ config I2C_TINY_USB
This driver can also be built as a module. If so, the module
will be called i2c-tiny-usb.
-comment "Graphics adapter I2C/DDC channel drivers"
- depends on PCI
-
-config I2C_VOODOO3
- tristate "Voodoo 3 (DEPRECATED)"
- depends on PCI
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the
- Voodoo 3 I2C interface. This driver is deprecated and you should
- use the tdfxfb driver instead, which additionally provides
- framebuffer support.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-voodoo3.
-
comment "Other I2C/SMBus bus drivers"
config I2C_ACORN
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ff937ac69f5..097236f631e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
@@ -54,6 +55,8 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
+obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
@@ -61,9 +64,6 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
-# Graphics adapter I2C/DDC channel drivers
-obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
-
# Other I2C/SMBus bus drivers
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index d108450df06..bd8f1e4d9e6 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -138,7 +138,7 @@ static unsigned short ali1535_smba;
Note the differences between kernels with the old PCI BIOS interface and
newer kernels with the real PCI interface. In compat.h some things are
defined to make the transition easier. */
-static int ali1535_setup(struct pci_dev *dev)
+static int __devinit ali1535_setup(struct pci_dev *dev)
{
int retval = -ENODEV;
unsigned char temp;
@@ -480,7 +480,7 @@ static struct i2c_adapter ali1535_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id ali1535_ids[] = {
+static const struct pci_device_id ali1535_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ },
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index f70f46582c6..a409cfcf062 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -87,9 +87,9 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
timeout = ALI1563_MAX_TIMEOUT;
- do
+ do {
msleep(1);
- while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
+ } while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, "
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
@@ -157,9 +157,9 @@ static int ali1563_block_start(struct i2c_adapter * a)
outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
timeout = ALI1563_MAX_TIMEOUT;
- do
+ do {
msleep(1);
- while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
+ } while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, "
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
@@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev)
ali1563_shutdown(dev);
}
-static struct pci_device_id __devinitdata ali1563_id_table[] = {
+static const struct pci_device_id ali1563_id_table[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
{},
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index d627fceb790..659f63f5e4a 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(force_addr,
static struct pci_driver ali15x3_driver;
static unsigned short ali15x3_smba;
-static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
{
u16 a;
unsigned char temp;
@@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id ali15x3_ids[] = {
+static const struct pci_device_id ali15x3_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 8f0b90ef8c7..c5a9fa488e7 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -308,7 +308,7 @@ static const char* chipname[] = {
"nVidia nForce", "AMD8111",
};
-static struct pci_device_id amd756_ids[] = {
+static const struct pci_device_id amd756_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
.driver_data = AMD756 },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 5b4ad86ca16..2fbef27b6cd 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/acpi.h>
+#include <linux/slab.h>
#include <asm/io.h>
MODULE_LICENSE("GPL");
@@ -351,7 +352,7 @@ static const struct i2c_algorithm smbus_algorithm = {
};
-static struct pci_device_id amd8111_ids[] = {
+static const struct pci_device_id amd8111_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index b309ac2c3d5..f1e14dd590c 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/i2c.h>
+#include <linux/slab.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/timer.h>
@@ -693,13 +694,13 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
}
/* Set TWI internal clock as 10MHz */
- write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
+ write_CONTROL(iface, ((get_sclk() / 1000 / 1000 + 5) / 10) & 0x7F);
/*
* We will not end up with a CLKDIV=0 because no one will specify
- * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100)
+ * 20kHz SCL or less in Kconfig now. (5 * 1000 / 20 = 250)
*/
- clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ;
+ clkhilow = ((10 * 1000 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) + 1) / 2;
/* Set Twi interface clock as specified */
write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index c89687a1083..4523364e672 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -35,6 +35,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <mach/hardware.h>
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index b444762e9b9..b664ed8bbdb 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -1,5 +1,5 @@
/*
- * Synopsys Designware I2C adapter driver (master only).
+ * Synopsys DesignWare I2C adapter driver (master only).
*
* Based on the TI DAVINCI I2C adapter driver.
*
@@ -36,6 +36,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/slab.h>
/*
* Registers offset
@@ -49,7 +50,20 @@
#define DW_IC_FS_SCL_LCNT 0x20
#define DW_IC_INTR_STAT 0x2c
#define DW_IC_INTR_MASK 0x30
+#define DW_IC_RAW_INTR_STAT 0x34
+#define DW_IC_RX_TL 0x38
+#define DW_IC_TX_TL 0x3c
#define DW_IC_CLR_INTR 0x40
+#define DW_IC_CLR_RX_UNDER 0x44
+#define DW_IC_CLR_RX_OVER 0x48
+#define DW_IC_CLR_TX_OVER 0x4c
+#define DW_IC_CLR_RD_REQ 0x50
+#define DW_IC_CLR_TX_ABRT 0x54
+#define DW_IC_CLR_RX_DONE 0x58
+#define DW_IC_CLR_ACTIVITY 0x5c
+#define DW_IC_CLR_STOP_DET 0x60
+#define DW_IC_CLR_START_DET 0x64
+#define DW_IC_CLR_GEN_CALL 0x68
#define DW_IC_ENABLE 0x6c
#define DW_IC_STATUS 0x70
#define DW_IC_TXFLR 0x74
@@ -64,9 +78,23 @@
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
-#define DW_IC_INTR_TX_EMPTY 0x10
-#define DW_IC_INTR_TX_ABRT 0x40
+#define DW_IC_INTR_RX_UNDER 0x001
+#define DW_IC_INTR_RX_OVER 0x002
+#define DW_IC_INTR_RX_FULL 0x004
+#define DW_IC_INTR_TX_OVER 0x008
+#define DW_IC_INTR_TX_EMPTY 0x010
+#define DW_IC_INTR_RD_REQ 0x020
+#define DW_IC_INTR_TX_ABRT 0x040
+#define DW_IC_INTR_RX_DONE 0x080
+#define DW_IC_INTR_ACTIVITY 0x100
#define DW_IC_INTR_STOP_DET 0x200
+#define DW_IC_INTR_START_DET 0x400
+#define DW_IC_INTR_GEN_CALL 0x800
+
+#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
+ DW_IC_INTR_TX_EMPTY | \
+ DW_IC_INTR_TX_ABRT | \
+ DW_IC_INTR_STOP_DET)
#define DW_IC_STATUS_ACTIVITY 0x1
@@ -96,31 +124,49 @@
#define ABRT_SBYTE_ACKDET 7
#define ABRT_SBYTE_NORSTRT 9
#define ABRT_10B_RD_NORSTRT 10
-#define ARB_MASTER_DIS 11
+#define ABRT_MASTER_DIS 11
#define ARB_LOST 12
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+
+#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+ DW_IC_TX_ABRT_10ADDR1_NOACK | \
+ DW_IC_TX_ABRT_10ADDR2_NOACK | \
+ DW_IC_TX_ABRT_TXDATA_NOACK | \
+ DW_IC_TX_ABRT_GCALL_NOACK)
+
static char *abort_sources[] = {
- [ABRT_7B_ADDR_NOACK] =
+ [ABRT_7B_ADDR_NOACK] =
"slave address not acknowledged (7bit mode)",
- [ABRT_10ADDR1_NOACK] =
+ [ABRT_10ADDR1_NOACK] =
"first address byte not acknowledged (10bit mode)",
- [ABRT_10ADDR2_NOACK] =
+ [ABRT_10ADDR2_NOACK] =
"second address byte not acknowledged (10bit mode)",
- [ABRT_TXDATA_NOACK] =
+ [ABRT_TXDATA_NOACK] =
"data not acknowledged",
- [ABRT_GCALL_NOACK] =
+ [ABRT_GCALL_NOACK] =
"no acknowledgement for a general call",
- [ABRT_GCALL_READ] =
+ [ABRT_GCALL_READ] =
"read after general call",
- [ABRT_SBYTE_ACKDET] =
+ [ABRT_SBYTE_ACKDET] =
"start byte acknowledged",
- [ABRT_SBYTE_NORSTRT] =
+ [ABRT_SBYTE_NORSTRT] =
"trying to send start byte when restart is disabled",
- [ABRT_10B_RD_NORSTRT] =
+ [ABRT_10B_RD_NORSTRT] =
"trying to read when restart is disabled (10bit mode)",
- [ARB_MASTER_DIS] =
+ [ABRT_MASTER_DIS] =
"trying to use disabled adapter",
- [ARB_LOST] =
+ [ARB_LOST] =
"lost arbitration",
};
@@ -129,7 +175,6 @@ static char *abort_sources[] = {
* @dev: driver model device node
* @base: IO registers pointer
* @cmd_complete: tx completion indicator
- * @pump_msg: continue in progress transfers
* @lock: protect this struct and IO registers
* @clk: input reference clock
* @cmd_err: run time hadware error code
@@ -155,27 +200,81 @@ struct dw_i2c_dev {
struct device *dev;
void __iomem *base;
struct completion cmd_complete;
- struct tasklet_struct pump_msg;
struct mutex lock;
struct clk *clk;
int cmd_err;
struct i2c_msg *msgs;
int msgs_num;
int msg_write_idx;
- u16 tx_buf_len;
+ u32 tx_buf_len;
u8 *tx_buf;
int msg_read_idx;
- u16 rx_buf_len;
+ u32 rx_buf_len;
u8 *rx_buf;
int msg_err;
unsigned int status;
- u16 abort_source;
+ u32 abort_source;
int irq;
struct i2c_adapter adapter;
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
};
+static u32
+i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
+{
+ /*
+ * DesignWare I2C core doesn't seem to have solid strategy to meet
+ * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
+ * will result in violation of the tHD;STA spec.
+ */
+ if (cond)
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
+ *
+ * This is based on the DW manuals, and represents an ideal
+ * configuration. The resulting I2C bus speed will be
+ * faster than any of the others.
+ *
+ * If your hardware is free from tHD;STA issue, try this one.
+ */
+ return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+ else
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
+ *
+ * This is just experimental rule; the tHD;STA period turned
+ * out to be proportinal to (_HCNT + 3). With this setting,
+ * we could meet both tHIGH and tHD;STA timing specs.
+ *
+ * If unsure, you'd better to take this alternative.
+ *
+ * The reason why we need to take into account "tf" here,
+ * is the same as described in i2c_dw_scl_lcnt().
+ */
+ return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+}
+
+static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+{
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
+ *
+ * DW I2C core starts counting the SCL CNTs for the LOW period
+ * of the SCL clock (tLOW) as soon as it pulls the SCL line.
+ * In order to meet the tLOW timing spec, we need to take into
+ * account the fall time of SCL signal (tf). Default tf value
+ * should be 0.3 us, for safety.
+ */
+ return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+}
+
/**
* i2c_dw_init() - initialize the designware i2c master hardware
* @dev: device private data
@@ -187,25 +286,49 @@ struct dw_i2c_dev {
static void i2c_dw_init(struct dw_i2c_dev *dev)
{
u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
- u16 ic_con;
+ u32 ic_con, hcnt, lcnt;
/* Disable the adapter */
- writeb(0, dev->base + DW_IC_ENABLE);
+ writel(0, dev->base + DW_IC_ENABLE);
/* set standard and fast speed deviders for high/low periods */
- writew((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */
- dev->base + DW_IC_SS_SCL_HCNT);
- writew((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */
- dev->base + DW_IC_SS_SCL_LCNT);
- writew((input_clock_khz * 6 / 10000)+1, /* fast speed high, 0.6us */
- dev->base + DW_IC_FS_SCL_HCNT);
- writew((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */
- dev->base + DW_IC_FS_SCL_LCNT);
+
+ /* Standard-mode */
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 40, /* tHD;STA = tHIGH = 4.0 us */
+ 3, /* tf = 0.3 us */
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 47, /* tLOW = 4.7 us */
+ 3, /* tf = 0.3 us */
+ 0); /* No offset */
+ writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT);
+ writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT);
+ dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ /* Fast-mode */
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 6, /* tHD;STA = tHIGH = 0.6 us */
+ 3, /* tf = 0.3 us */
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 13, /* tLOW = 1.3 us */
+ 3, /* tf = 0.3 us */
+ 0); /* No offset */
+ writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT);
+ writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT);
+ dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ /* Configure Tx/Rx FIFO threshold levels */
+ writel(dev->tx_fifo_depth - 1, dev->base + DW_IC_TX_TL);
+ writel(0, dev->base + DW_IC_RX_TL);
/* configure the i2c master */
ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
- writew(ic_con, dev->base + DW_IC_CON);
+ writel(ic_con, dev->base + DW_IC_CON);
}
/*
@@ -215,7 +338,7 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
{
int timeout = TIMEOUT;
- while (readb(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
+ while (readl(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
if (timeout <= 0) {
dev_warn(dev->dev, "timeout waiting for bus ready\n");
return -ETIMEDOUT;
@@ -227,106 +350,125 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
return 0;
}
-/*
- * Initiate low level master read/write transaction.
- * This function is called from i2c_dw_xfer when starting a transfer.
- * This function is also called from dw_i2c_pump_msg to continue a transfer
- * that is longer than the size of the TX FIFO.
- */
-static void
-i2c_dw_xfer_msg(struct i2c_adapter *adap)
+static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
{
- struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
struct i2c_msg *msgs = dev->msgs;
- int num = dev->msgs_num;
- u16 ic_con, intr_mask;
- int tx_limit = dev->tx_fifo_depth - readb(dev->base + DW_IC_TXFLR);
- int rx_limit = dev->rx_fifo_depth - readb(dev->base + DW_IC_RXFLR);
- u16 addr = msgs[dev->msg_write_idx].addr;
- u16 buf_len = dev->tx_buf_len;
+ u32 ic_con;
- if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
- /* Disable the adapter */
- writeb(0, dev->base + DW_IC_ENABLE);
+ /* Disable the adapter */
+ writel(0, dev->base + DW_IC_ENABLE);
- /* set the slave (target) address */
- writew(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
+ /* set the slave (target) address */
+ writel(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
- /* if the slave address is ten bit address, enable 10BITADDR */
- ic_con = readw(dev->base + DW_IC_CON);
- if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
- ic_con |= DW_IC_CON_10BITADDR_MASTER;
- else
- ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
- writew(ic_con, dev->base + DW_IC_CON);
+ /* if the slave address is ten bit address, enable 10BITADDR */
+ ic_con = readl(dev->base + DW_IC_CON);
+ if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+ ic_con |= DW_IC_CON_10BITADDR_MASTER;
+ else
+ ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+ writel(ic_con, dev->base + DW_IC_CON);
- /* Enable the adapter */
- writeb(1, dev->base + DW_IC_ENABLE);
- }
+ /* Enable the adapter */
+ writel(1, dev->base + DW_IC_ENABLE);
- for (; dev->msg_write_idx < num; dev->msg_write_idx++) {
- /* if target address has changed, we need to
+ /* Enable interrupts */
+ writel(DW_IC_INTR_DEFAULT_MASK, dev->base + DW_IC_INTR_MASK);
+}
+
+/*
+ * Initiate (and continue) low level master read/write transaction.
+ * This function is only called from i2c_dw_isr, and pumping i2c_msg
+ * messages into the tx buffer. Even if the size of i2c_msg data is
+ * longer than the size of the tx buffer, it handles everything.
+ */
+static void
+i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 intr_mask;
+ int tx_limit, rx_limit;
+ u32 addr = msgs[dev->msg_write_idx].addr;
+ u32 buf_len = dev->tx_buf_len;
+ u8 *buf = dev->tx_buf;;
+
+ intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+ for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
+ /*
+ * if target address has changed, we need to
* reprogram the target address in the i2c
* adapter when we are done with this transfer
*/
- if (msgs[dev->msg_write_idx].addr != addr)
- return;
+ if (msgs[dev->msg_write_idx].addr != addr) {
+ dev_err(dev->dev,
+ "%s: invalid target address\n", __func__);
+ dev->msg_err = -EINVAL;
+ break;
+ }
if (msgs[dev->msg_write_idx].len == 0) {
dev_err(dev->dev,
"%s: invalid message length\n", __func__);
dev->msg_err = -EINVAL;
- return;
+ break;
}
if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
/* new i2c_msg */
- dev->tx_buf = msgs[dev->msg_write_idx].buf;
+ buf = msgs[dev->msg_write_idx].buf;
buf_len = msgs[dev->msg_write_idx].len;
}
+ tx_limit = dev->tx_fifo_depth - readl(dev->base + DW_IC_TXFLR);
+ rx_limit = dev->rx_fifo_depth - readl(dev->base + DW_IC_RXFLR);
+
while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
- writew(0x100, dev->base + DW_IC_DATA_CMD);
+ writel(0x100, dev->base + DW_IC_DATA_CMD);
rx_limit--;
} else
- writew(*(dev->tx_buf++),
- dev->base + DW_IC_DATA_CMD);
+ writel(*buf++, dev->base + DW_IC_DATA_CMD);
tx_limit--; buf_len--;
}
+
+ dev->tx_buf = buf;
+ dev->tx_buf_len = buf_len;
+
+ if (buf_len > 0) {
+ /* more bytes to be written */
+ dev->status |= STATUS_WRITE_IN_PROGRESS;
+ break;
+ } else
+ dev->status &= ~STATUS_WRITE_IN_PROGRESS;
}
- intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT;
- if (buf_len > 0) { /* more bytes to be written */
- intr_mask |= DW_IC_INTR_TX_EMPTY;
- dev->status |= STATUS_WRITE_IN_PROGRESS;
- } else
- dev->status &= ~STATUS_WRITE_IN_PROGRESS;
- writew(intr_mask, dev->base + DW_IC_INTR_MASK);
+ /*
+ * If i2c_msg index search is completed, we don't need TX_EMPTY
+ * interrupt any more.
+ */
+ if (dev->msg_write_idx == dev->msgs_num)
+ intr_mask &= ~DW_IC_INTR_TX_EMPTY;
- dev->tx_buf_len = buf_len;
+ if (dev->msg_err)
+ intr_mask = 0;
+
+ writel(intr_mask, dev->base + DW_IC_INTR_MASK);
}
static void
-i2c_dw_read(struct i2c_adapter *adap)
+i2c_dw_read(struct dw_i2c_dev *dev)
{
- struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
struct i2c_msg *msgs = dev->msgs;
- int num = dev->msgs_num;
- u16 addr = msgs[dev->msg_read_idx].addr;
- int rx_valid = readw(dev->base + DW_IC_RXFLR);
+ int rx_valid;
- for (; dev->msg_read_idx < num; dev->msg_read_idx++) {
- u16 len;
+ for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
+ u32 len;
u8 *buf;
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
continue;
- /* different i2c client, reprogram the i2c adapter */
- if (msgs[dev->msg_read_idx].addr != addr)
- return;
-
if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
len = msgs[dev->msg_read_idx].len;
buf = msgs[dev->msg_read_idx].buf;
@@ -335,8 +477,10 @@ i2c_dw_read(struct i2c_adapter *adap)
buf = dev->rx_buf;
}
+ rx_valid = readl(dev->base + DW_IC_RXFLR);
+
for (; len > 0 && rx_valid > 0; len--, rx_valid--)
- *buf++ = readb(dev->base + DW_IC_DATA_CMD);
+ *buf++ = readl(dev->base + DW_IC_DATA_CMD);
if (len > 0) {
dev->status |= STATUS_READ_IN_PROGRESS;
@@ -348,6 +492,29 @@ i2c_dw_read(struct i2c_adapter *adap)
}
}
+static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
+{
+ unsigned long abort_source = dev->abort_source;
+ int i;
+
+ if (abort_source & DW_IC_TX_ABRT_NOACK) {
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ dev_dbg(dev->dev,
+ "%s: %s\n", __func__, abort_sources[i]);
+ return -EREMOTEIO;
+ }
+
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
+
+ if (abort_source & DW_IC_TX_ARB_LOST)
+ return -EAGAIN;
+ else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
+ return -EINVAL; /* wrong msgs[] data */
+ else
+ return -EIO;
+}
+
/*
* Prepare controller for a transaction and call i2c_dw_xfer_msg
*/
@@ -369,13 +536,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev->msg_read_idx = 0;
dev->msg_err = 0;
dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
ret = i2c_dw_wait_bus_not_busy(dev);
if (ret < 0)
goto done;
/* start the transfers */
- i2c_dw_xfer_msg(adap);
+ i2c_dw_xfer_init(dev);
/* wait for tx to complete */
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
@@ -394,23 +562,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
/* no error */
if (likely(!dev->cmd_err)) {
- /* read rx fifo, and disable the adapter */
- do {
- i2c_dw_read(adap);
- } while (dev->status & STATUS_READ_IN_PROGRESS);
- writeb(0, dev->base + DW_IC_ENABLE);
+ /* Disable the adapter */
+ writel(0, dev->base + DW_IC_ENABLE);
ret = num;
goto done;
}
/* We have an error */
if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
- unsigned long abort_source = dev->abort_source;
- int i;
-
- for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) {
- dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
- }
+ ret = i2c_dw_handle_tx_abort(dev);
+ goto done;
}
ret = -EIO;
@@ -422,21 +583,67 @@ done:
static u32 i2c_dw_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+ return I2C_FUNC_I2C |
+ I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
-static void dw_i2c_pump_msg(unsigned long data)
+static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
- struct dw_i2c_dev *dev = (struct dw_i2c_dev *) data;
- u16 intr_mask;
+ u32 stat;
- i2c_dw_read(&dev->adapter);
- i2c_dw_xfer_msg(&dev->adapter);
+ /*
+ * The IC_INTR_STAT register just indicates "enabled" interrupts.
+ * Ths unmasked raw version of interrupt status bits are available
+ * in the IC_RAW_INTR_STAT register.
+ *
+ * That is,
+ * stat = readl(IC_INTR_STAT);
+ * equals to,
+ * stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
+ *
+ * The raw version might be useful for debugging purposes.
+ */
+ stat = readl(dev->base + DW_IC_INTR_STAT);
+
+ /*
+ * Do not use the IC_CLR_INTR register to clear interrupts, or
+ * you'll miss some interrupts, triggered during the period from
+ * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
+ *
+ * Instead, use the separately-prepared IC_CLR_* registers.
+ */
+ if (stat & DW_IC_INTR_RX_UNDER)
+ readl(dev->base + DW_IC_CLR_RX_UNDER);
+ if (stat & DW_IC_INTR_RX_OVER)
+ readl(dev->base + DW_IC_CLR_RX_OVER);
+ if (stat & DW_IC_INTR_TX_OVER)
+ readl(dev->base + DW_IC_CLR_TX_OVER);
+ if (stat & DW_IC_INTR_RD_REQ)
+ readl(dev->base + DW_IC_CLR_RD_REQ);
+ if (stat & DW_IC_INTR_TX_ABRT) {
+ /*
+ * The IC_TX_ABRT_SOURCE register is cleared whenever
+ * the IC_CLR_TX_ABRT is read. Preserve it beforehand.
+ */
+ dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE);
+ readl(dev->base + DW_IC_CLR_TX_ABRT);
+ }
+ if (stat & DW_IC_INTR_RX_DONE)
+ readl(dev->base + DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ readl(dev->base + DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_STOP_DET)
+ readl(dev->base + DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ readl(dev->base + DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+ readl(dev->base + DW_IC_CLR_GEN_CALL);
- intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT;
- if (dev->status & STATUS_WRITE_IN_PROGRESS)
- intr_mask |= DW_IC_INTR_TX_EMPTY;
- writew(intr_mask, dev->base + DW_IC_INTR_MASK);
+ return stat;
}
/*
@@ -446,20 +653,37 @@ static void dw_i2c_pump_msg(unsigned long data)
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
- u16 stat;
+ u32 stat;
- stat = readw(dev->base + DW_IC_INTR_STAT);
+ stat = i2c_dw_read_clear_intrbits(dev);
dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
+
if (stat & DW_IC_INTR_TX_ABRT) {
- dev->abort_source = readw(dev->base + DW_IC_TX_ABRT_SOURCE);
dev->cmd_err |= DW_IC_ERR_TX_ABRT;
dev->status = STATUS_IDLE;
- } else if (stat & DW_IC_INTR_TX_EMPTY)
- tasklet_schedule(&dev->pump_msg);
- readb(dev->base + DW_IC_CLR_INTR); /* clear interrupts */
- writew(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */
- if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
+ /*
+ * Anytime TX_ABRT is set, the contents of the tx/rx
+ * buffers are flushed. Make sure to skip them.
+ */
+ writel(0, dev->base + DW_IC_INTR_MASK);
+ goto tx_aborted;
+ }
+
+ if (stat & DW_IC_INTR_RX_FULL)
+ i2c_dw_read(dev);
+
+ if (stat & DW_IC_INTR_TX_EMPTY)
+ i2c_dw_xfer_msg(dev);
+
+ /*
+ * No need to modify or disable the interrupt mask here.
+ * i2c_dw_xfer_msg() will take care of it according to
+ * the current transmit status.
+ */
+
+tx_aborted:
+ if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
complete(&dev->cmd_complete);
return IRQ_HANDLED;
@@ -474,8 +698,8 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
{
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
- struct resource *mem, *irq, *ioarea;
- int r;
+ struct resource *mem, *ioarea;
+ int irq, r;
/* NOTE: driver uses the static register mapping */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -484,10 +708,10 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
return -EINVAL;
}
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq) {
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
- return -EINVAL;
+ return irq; /* -ENXIO */
}
ioarea = request_mem_region(mem->start, resource_size(mem),
@@ -504,10 +728,9 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
}
init_completion(&dev->cmd_complete);
- tasklet_init(&dev->pump_msg, dw_i2c_pump_msg, (unsigned long) dev);
mutex_init(&dev->lock);
dev->dev = get_device(&pdev->dev);
- dev->irq = irq->start;
+ dev->irq = irq;
platform_set_drvdata(pdev, dev);
dev->clk = clk_get(&pdev->dev, NULL);
@@ -531,8 +754,8 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
}
i2c_dw_init(dev);
- writew(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
- r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev);
+ writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
+ r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
if (r) {
dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
goto err_iounmap;
@@ -587,7 +810,7 @@ static int __devexit dw_i2c_remove(struct platform_device *pdev)
clk_put(dev->clk);
dev->clk = NULL;
- writeb(0, dev->base + DW_IC_ENABLE);
+ writel(0, dev->base + DW_IC_ENABLE);
free_irq(dev->irq, dev);
kfree(dev);
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 448b4bf35eb..612255614a6 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -29,7 +29,6 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 32104eac8d3..c21077d248a 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -12,6 +12,7 @@
#include <linux/i2c-gpio.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/platform_device.h>
#include <asm/gpio.h>
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
index 87ecace415d..ce87a902c94 100644
--- a/drivers/i2c/busses/i2c-highlander.c
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -19,6 +19,7 @@
#include <linux/completion.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#define SMCR 0x00
#define SMCR_START (1 << 0)
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index bec9b845dd1..c767295ad1f 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = {
.algo_data = &hydra_bit_data,
};
-static struct pci_device_id hydra_ids[] = {
+static const struct pci_device_id hydra_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 55edcfe5b85..299b918455a 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -41,7 +41,8 @@
Tolapai 0x5032 32 hard yes yes yes
ICH10 0x3a30 32 hard yes yes yes
ICH10 0x3a60 32 hard yes yes yes
- PCH 0x3b30 32 hard yes yes yes
+ 3400/5 Series (PCH) 0x3b30 32 hard yes yes yes
+ Cougar Point (PCH) 0x1c22 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -415,9 +416,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
data->block[0] = 32; /* max for SMBus block reads */
}
+ /* Experience has shown that the block buffer can only be used for
+ SMBus (not I2C) block transactions, even though the datasheet
+ doesn't mention this limitation. */
if ((i801_features & FEATURE_BLOCK_BUFFER)
- && !(command == I2C_SMBUS_I2C_BLOCK_DATA
- && read_write == I2C_SMBUS_READ)
+ && command != I2C_SMBUS_I2C_BLOCK_DATA
&& i801_set_block_buffer_mode() == 0)
result = i801_block_transaction_by_block(data, read_write,
hwpec);
@@ -561,7 +564,7 @@ static struct i2c_adapter i801_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id i801_ids[] = {
+static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
@@ -578,6 +581,7 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CPT_SMBUS) },
{ 0, }
};
@@ -707,6 +711,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
case PCI_DEVICE_ID_INTEL_ICH10_4:
case PCI_DEVICE_ID_INTEL_ICH10_5:
case PCI_DEVICE_ID_INTEL_PCH_SMBUS:
+ case PCI_DEVICE_ID_INTEL_CPT_SMBUS:
i801_features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3:
@@ -767,6 +772,9 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
/* set up the sysfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
+ /* Retry up to 3 times on lost arbitration */
+ i801_adapter.retries = 3;
+
snprintf(i801_adapter.name, sizeof(i801_adapter.name),
"SMBus I801 adapter at %04lx", i801_smba);
err = i2c_add_adapter(&i801_adapter);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index e3654d683e1..f7e27b70237 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -47,6 +47,7 @@
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/slab.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -226,7 +227,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
- i2c_imx->stopped = 1;
}
if (cpu_is_mx1()) {
/*
@@ -236,8 +236,10 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
udelay(i2c_imx->disable_delay);
}
- if (!i2c_imx->stopped)
+ if (!i2c_imx->stopped) {
i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx->stopped = 1;
+ }
/* Disable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
@@ -496,22 +498,23 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
}
res_size = resource_size(res);
+
+ if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
+ ret = -EBUSY;
+ goto fail0;
+ }
+
base = ioremap(res->start, res_size);
if (!base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -EIO;
- goto fail0;
+ goto fail1;
}
i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
if (!i2c_imx) {
dev_err(&pdev->dev, "can't allocate interface\n");
ret = -ENOMEM;
- goto fail1;
- }
-
- if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
- ret = -EBUSY;
goto fail2;
}
@@ -582,11 +585,11 @@ fail5:
fail4:
clk_put(i2c_imx->clk);
fail3:
- release_mem_region(i2c_imx->res->start, resource_size(res));
-fail2:
kfree(i2c_imx);
-fail1:
+fail2:
iounmap(base);
+fail1:
+ release_mem_region(res->start, resource_size(res));
fail0:
if (pdata && pdata->exit)
pdata->exit(&pdev->dev);
@@ -618,14 +621,13 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
clk_put(i2c_imx->clk);
- release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
iounmap(i2c_imx->base);
+ release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
kfree(i2c_imx);
return 0;
}
static struct platform_driver i2c_imx_driver = {
- .probe = i2c_imx_probe,
.remove = __exit_p(i2c_imx_remove),
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index a75c75e77b9..5901707fc66 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -56,12 +56,6 @@ iic_cook_addr(struct i2c_msg *msg)
if (msg->flags & I2C_M_RD)
addr |= 1;
- /*
- * Read or Write?
- */
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
-
return addr;
}
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index dba6eb053e2..ddc258edb34 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -27,7 +27,7 @@
*/
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/stddef.h>
@@ -46,12 +46,6 @@
#define SMBHSTDAT1 (7 + sch_smba)
#define SMBBLKDAT (0x20 + sch_smba)
-/* count for request_region */
-#define SMBIOSIZE 64
-
-/* PCI Address Constants */
-#define SMBBA_SCH 0x40
-
/* Other settings */
#define MAX_TIMEOUT 500
@@ -63,7 +57,6 @@
#define SCH_BLOCK_DATA 0x05
static unsigned short sch_smba;
-static struct pci_driver sch_driver;
static struct i2c_adapter sch_adapter;
/*
@@ -256,37 +249,23 @@ static struct i2c_adapter sch_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sch_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, sch_ids);
-
-static int __devinit sch_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
+static int __devinit smbus_sch_probe(struct platform_device *dev)
{
+ struct resource *res;
int retval;
- unsigned int smba;
- pci_read_config_dword(dev, SMBBA_SCH, &smba);
- if (!(smba & (1 << 31))) {
- dev_err(&dev->dev, "SMBus I/O space disabled!\n");
- return -ENODEV;
- }
+ res = platform_get_resource(dev, IORESOURCE_IO, 0);
+ if (!res)
+ return -EBUSY;
- sch_smba = (unsigned short)smba;
- if (sch_smba == 0) {
- dev_err(&dev->dev, "SMBus base address uninitialized!\n");
- return -ENODEV;
- }
- if (acpi_check_region(sch_smba, SMBIOSIZE, sch_driver.name))
- return -ENODEV;
- if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) {
+ if (!request_region(res->start, resource_size(res), dev->name)) {
dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
sch_smba);
return -EBUSY;
}
+
+ sch_smba = res->start;
+
dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
/* set up the sysfs linkage to our parent device */
@@ -298,37 +277,43 @@ static int __devinit sch_probe(struct pci_dev *dev,
retval = i2c_add_adapter(&sch_adapter);
if (retval) {
dev_err(&dev->dev, "Couldn't register adapter!\n");
- release_region(sch_smba, SMBIOSIZE);
+ release_region(res->start, resource_size(res));
sch_smba = 0;
}
return retval;
}
-static void __devexit sch_remove(struct pci_dev *dev)
+static int __devexit smbus_sch_remove(struct platform_device *pdev)
{
+ struct resource *res;
if (sch_smba) {
i2c_del_adapter(&sch_adapter);
- release_region(sch_smba, SMBIOSIZE);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, resource_size(res));
sch_smba = 0;
}
+
+ return 0;
}
-static struct pci_driver sch_driver = {
- .name = "isch_smbus",
- .id_table = sch_ids,
- .probe = sch_probe,
- .remove = __devexit_p(sch_remove),
+static struct platform_driver smbus_sch_driver = {
+ .driver = {
+ .name = "isch_smbus",
+ .owner = THIS_MODULE,
+ },
+ .probe = smbus_sch_probe,
+ .remove = __devexit_p(smbus_sch_remove),
};
static int __init i2c_sch_init(void)
{
- return pci_register_driver(&sch_driver);
+ return platform_driver_register(&smbus_sch_driver);
}
static void __exit i2c_sch_exit(void)
{
- pci_unregister_driver(&sch_driver);
+ platform_driver_unregister(&smbus_sch_driver);
}
MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
@@ -337,3 +322,4 @@ MODULE_LICENSE("GPL");
module_init(i2c_sch_init);
module_exit(i2c_sch_exit);
+MODULE_ALIAS("platform:isch_smbus");
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index c016f7a2c5f..5d8aed5ec21 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/slab.h>
#include <mach/hardware.h> /* Pick up IXP2000-specific bits */
#include <mach/gpio.h>
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index f627001108b..f1321f76378 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/of_i2c.h>
+#include <linux/slab.h>
#include <linux/io.h>
#include <linux/fsl_devices.h>
@@ -31,6 +32,9 @@
#define DRV_NAME "mpc-i2c"
+#define MPC_I2C_CLOCK_LEGACY 0
+#define MPC_I2C_CLOCK_PRESERVE (~0U)
+
#define MPC_I2C_FDR 0x04
#define MPC_I2C_CR 0x08
#define MPC_I2C_SR 0x0c
@@ -66,10 +70,9 @@ struct mpc_i2c_divider {
u16 fdr; /* including dfsrr */
};
-struct mpc_i2c_match_data {
- void (*setclock)(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler);
+struct mpc_i2c_data {
+ void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler);
u32 prescaler;
};
@@ -164,8 +167,8 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
return 0;
}
-#ifdef CONFIG_PPC_MPC52xx
-static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
+#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
{28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
{36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28},
@@ -186,14 +189,15 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
};
-int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
+static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+ int prescaler)
{
const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR);
u32 divider;
int i;
- if (!clock)
+ if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL;
/* Determine divider value */
@@ -215,12 +219,18 @@ int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
return div ? (int)div->fdr : -EINVAL;
}
-static void mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using fdr %d\n",
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
@@ -229,16 +239,52 @@ static void mpc_i2c_setclock_52xx(struct device_node *node,
if (ret >= 0)
dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
}
-#else /* !CONFIG_PPC_MPC52xx */
-static void mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_PPC_MPC512x
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+ struct device_node *node_ctrl;
+ void __iomem *ctrl;
+ const u32 *pval;
+ u32 idx;
+
+ /* Enable I2C interrupts for mpc5121 */
+ node_ctrl = of_find_compatible_node(NULL, NULL,
+ "fsl,mpc5121-i2c-ctrl");
+ if (node_ctrl) {
+ ctrl = of_iomap(node_ctrl, 0);
+ if (ctrl) {
+ /* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */
+ pval = of_get_property(node, "reg", NULL);
+ idx = (*pval & 0xff) / 0x20;
+ setbits32(ctrl, 1 << (24 + idx * 2));
+ iounmap(ctrl);
+ }
+ of_node_put(node_ctrl);
+ }
+
+ /* The clock setup for the 52xx works also fine for the 512x */
+ mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
+}
+#else /* CONFIG_PPC_MPC512x */
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
-#endif /* CONFIG_PPC_MPC52xx*/
+#endif /* CONFIG_PPC_MPC512x */
#ifdef CONFIG_FSL_SOC
-static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
{160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123},
{288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102},
{416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127},
@@ -258,7 +304,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
{49152, 0x011e}, {61440, 0x011f}
};
-u32 mpc_i2c_get_sec_cfg_8xxx(void)
+static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
{
struct device_node *node = NULL;
u32 __iomem *reg;
@@ -287,13 +333,14 @@ u32 mpc_i2c_get_sec_cfg_8xxx(void)
return val;
}
-int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
+static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+ u32 prescaler)
{
const struct mpc_i2c_divider *div = NULL;
u32 divider;
int i;
- if (!clock)
+ if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL;
/* Determine proper divider value */
@@ -320,12 +367,19 @@ int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
return div ? (int)div->fdr : -EINVAL;
}
-static void mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n",
+ readb(i2c->base + MPC_I2C_DFSRR),
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
@@ -338,9 +392,9 @@ static void mpc_i2c_setclock_8xxx(struct device_node *node,
}
#else /* !CONFIG_FSL_SOC */
-static void mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_FSL_SOC */
@@ -494,7 +548,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
{
struct mpc_i2c *i2c;
const u32 *prop;
- u32 clock = 0;
+ u32 clock = MPC_I2C_CLOCK_LEGACY;
int result = 0;
int plen;
@@ -523,21 +577,21 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
}
}
- if (!of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+ if (of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+ clock = MPC_I2C_CLOCK_PRESERVE;
+ } else {
prop = of_get_property(op->node, "clock-frequency", &plen);
if (prop && plen == sizeof(u32))
clock = *prop;
+ }
- if (match->data) {
- struct mpc_i2c_match_data *data =
- (struct mpc_i2c_match_data *)match->data;
- data->setclock(op->node, i2c, clock, data->prescaler);
- } else {
- /* Backwards compatibility */
- if (of_get_property(op->node, "dfsrr", NULL))
- mpc_i2c_setclock_8xxx(op->node, i2c,
- clock, 0);
- }
+ if (match->data) {
+ struct mpc_i2c_data *data = match->data;
+ data->setup(op->node, i2c, clock, data->prescaler);
+ } else {
+ /* Backwards compatibility */
+ if (of_get_property(op->node, "dfsrr", NULL))
+ mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
}
dev_set_drvdata(&op->dev, i2c);
@@ -582,47 +636,42 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
return 0;
};
+static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+ .setup = mpc_i2c_setup_512x,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+ .setup = mpc_i2c_setup_52xx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+ .setup = mpc_i2c_setup_8xxx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+ .setup = mpc_i2c_setup_8xxx,
+ .prescaler = 2,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+ .setup = mpc_i2c_setup_8xxx,
+ .prescaler = 3,
+};
+
static const struct of_device_id mpc_i2c_of_match[] = {
- {.compatible = "mpc5200-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc5200b-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc5200-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc8313-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- },
- },
- {.compatible = "fsl,mpc8543-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- .prescaler = 2,
- },
- },
- {.compatible = "fsl,mpc8544-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- .prescaler = 3,
- },
+ {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, },
+ {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
+ {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
+ {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
/* Backward compatibility */
- },
{.compatible = "fsl-i2c", },
{},
};
-
MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
-
/* Structure for a device driver */
static struct of_platform_driver mpc_i2c_driver = {
.match_table = mpc_i2c_of_match,
@@ -655,5 +704,5 @@ module_exit(fsl_i2c_exit);
MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
- "MPC824x/85xx/52xx processors");
+ "MPC824x/83xx/85xx/86xx/512x/52xx processors");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index bbab0e16663..3623a449908 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -10,6 +10,7 @@
* or implied.
*/
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
@@ -338,9 +339,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
if (msg->flags & I2C_M_RD)
dir = 1;
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- dir ^= 1;
-
if (msg->flags & I2C_M_TEN) {
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
drv_data->addr2 = (u32)msg->addr & 0xff;
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index ec11d1c4e77..4a48dd4ef78 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -56,6 +56,7 @@
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/acpi.h>
+#include <linux/slab.h>
#include <asm/io.h>
MODULE_LICENSE("GPL");
@@ -308,7 +309,7 @@ static struct i2c_algorithm smbus_algorithm = {
};
-static struct pci_device_id nforce2_ids[] = {
+static const struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
new file mode 100644
index 00000000000..a4f8d33fa38
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * I2C master mode controller driver, used in Nomadik 8815
+ * and Ux500 platforms.
+ *
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ * Author: Sachin Verma <sachin.verma@st.com>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/i2c.h>
+
+#define DRIVER_NAME "nmk-i2c"
+
+/* I2C Controller register offsets */
+#define I2C_CR (0x000)
+#define I2C_SCR (0x004)
+#define I2C_HSMCR (0x008)
+#define I2C_MCR (0x00C)
+#define I2C_TFR (0x010)
+#define I2C_SR (0x014)
+#define I2C_RFR (0x018)
+#define I2C_TFTR (0x01C)
+#define I2C_RFTR (0x020)
+#define I2C_DMAR (0x024)
+#define I2C_BRCR (0x028)
+#define I2C_IMSCR (0x02C)
+#define I2C_RISR (0x030)
+#define I2C_MISR (0x034)
+#define I2C_ICR (0x038)
+
+/* Control registers */
+#define I2C_CR_PE (0x1 << 0) /* Peripheral Enable */
+#define I2C_CR_OM (0x3 << 1) /* Operating mode */
+#define I2C_CR_SAM (0x1 << 3) /* Slave addressing mode */
+#define I2C_CR_SM (0x3 << 4) /* Speed mode */
+#define I2C_CR_SGCM (0x1 << 6) /* Slave general call mode */
+#define I2C_CR_FTX (0x1 << 7) /* Flush Transmit */
+#define I2C_CR_FRX (0x1 << 8) /* Flush Receive */
+#define I2C_CR_DMA_TX_EN (0x1 << 9) /* DMA Tx enable */
+#define I2C_CR_DMA_RX_EN (0x1 << 10) /* DMA Rx Enable */
+#define I2C_CR_DMA_SLE (0x1 << 11) /* DMA sync. logic enable */
+#define I2C_CR_LM (0x1 << 12) /* Loopback mode */
+#define I2C_CR_FON (0x3 << 13) /* Filtering on */
+#define I2C_CR_FS (0x3 << 15) /* Force stop enable */
+
+/* Master controller (MCR) register */
+#define I2C_MCR_OP (0x1 << 0) /* Operation */
+#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */
+#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
+#define I2C_MCR_SB (0x1 << 11) /* Extended address */
+#define I2C_MCR_AM (0x3 << 12) /* Address type */
+#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
+#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
+
+/* Status register (SR) */
+#define I2C_SR_OP (0x3 << 0) /* Operation */
+#define I2C_SR_STATUS (0x3 << 2) /* controller status */
+#define I2C_SR_CAUSE (0x7 << 4) /* Abort cause */
+#define I2C_SR_TYPE (0x3 << 7) /* Receive type */
+#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */
+
+/* Interrupt mask set/clear (IMSCR) bits */
+#define I2C_IT_TXFE (0x1 << 0)
+#define I2C_IT_TXFNE (0x1 << 1)
+#define I2C_IT_TXFF (0x1 << 2)
+#define I2C_IT_TXFOVR (0x1 << 3)
+#define I2C_IT_RXFE (0x1 << 4)
+#define I2C_IT_RXFNF (0x1 << 5)
+#define I2C_IT_RXFF (0x1 << 6)
+#define I2C_IT_RFSR (0x1 << 16)
+#define I2C_IT_RFSE (0x1 << 17)
+#define I2C_IT_WTSR (0x1 << 18)
+#define I2C_IT_MTD (0x1 << 19)
+#define I2C_IT_STD (0x1 << 20)
+#define I2C_IT_MAL (0x1 << 24)
+#define I2C_IT_BERR (0x1 << 25)
+#define I2C_IT_MTDWS (0x1 << 28)
+
+#define GEN_MASK(val, mask, sb) (((val) << (sb)) & (mask))
+
+/* some bits in ICR are reserved */
+#define I2C_CLEAR_ALL_INTS 0x131f007f
+
+/* first three msb bits are reserved */
+#define IRQ_MASK(mask) (mask & 0x1fffffff)
+
+/* maximum threshold value */
+#define MAX_I2C_FIFO_THRESHOLD 15
+
+enum i2c_status {
+ I2C_NOP,
+ I2C_ON_GOING,
+ I2C_OK,
+ I2C_ABORT
+};
+
+/* operation */
+enum i2c_operation {
+ I2C_NO_OPERATION = 0xff,
+ I2C_WRITE = 0x00,
+ I2C_READ = 0x01
+};
+
+/* controller response timeout in ms */
+#define I2C_TIMEOUT_MS 500
+
+/**
+ * struct i2c_nmk_client - client specific data
+ * @slave_adr: 7-bit slave address
+ * @count: no. bytes to be transfered
+ * @buffer: client data buffer
+ * @xfer_bytes: bytes transfered till now
+ * @operation: current I2C operation
+ */
+struct i2c_nmk_client {
+ unsigned short slave_adr;
+ unsigned long count;
+ unsigned char *buffer;
+ unsigned long xfer_bytes;
+ enum i2c_operation operation;
+};
+
+/**
+ * struct nmk_i2c_dev - private data structure of the controller
+ * @pdev: parent platform device
+ * @adap: corresponding I2C adapter
+ * @irq: interrupt line for the controller
+ * @virtbase: virtual io memory area
+ * @clk: hardware i2c block clock
+ * @cfg: machine provided controller configuration
+ * @cli: holder of client specific data
+ * @stop: stop condition
+ * @xfer_complete: acknowledge completion for a I2C message
+ * @result: controller propogated result
+ */
+struct nmk_i2c_dev {
+ struct platform_device *pdev;
+ struct i2c_adapter adap;
+ int irq;
+ void __iomem *virtbase;
+ struct clk *clk;
+ struct nmk_i2c_controller cfg;
+ struct i2c_nmk_client cli;
+ int stop;
+ struct completion xfer_complete;
+ int result;
+};
+
+/* controller's abort causes */
+static const char *abort_causes[] = {
+ "no ack received after address transmission",
+ "no ack received during data phase",
+ "ack received after xmission of master code",
+ "master lost arbitration",
+ "slave restarts",
+ "slave reset",
+ "overflow, maxsize is 2047 bytes",
+};
+
+static inline void i2c_set_bit(void __iomem *reg, u32 mask)
+{
+ writel(readl(reg) | mask, reg);
+}
+
+static inline void i2c_clr_bit(void __iomem *reg, u32 mask)
+{
+ writel(readl(reg) & ~mask, reg);
+}
+
+/**
+ * flush_i2c_fifo() - This function flushes the I2C FIFO
+ * @dev: private data of I2C Driver
+ *
+ * This function flushes the I2C Tx and Rx FIFOs. It returns
+ * 0 on successful flushing of FIFO
+ */
+static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
+{
+#define LOOP_ATTEMPTS 10
+ int i;
+ unsigned long timeout;
+
+ /*
+ * flush the transmit and receive FIFO. The flushing
+ * operation takes several cycles before to be completed.
+ * On the completion, the I2C internal logic clears these
+ * bits, until then no one must access Tx, Rx FIFO and
+ * should poll on these bits waiting for the completion.
+ */
+ writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
+
+ for (i = 0; i < LOOP_ATTEMPTS; i++) {
+ timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+
+ while (!time_after(jiffies, timeout)) {
+ if ((readl(dev->virtbase + I2C_CR) &
+ (I2C_CR_FTX | I2C_CR_FRX)) == 0)
+ return 0;
+ }
+ }
+
+ dev_err(&dev->pdev->dev, "flushing operation timed out "
+ "giving up after %d attempts", LOOP_ATTEMPTS);
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * disable_all_interrupts() - Disable all interrupts of this I2c Bus
+ * @dev: private data of I2C Driver
+ */
+static void disable_all_interrupts(struct nmk_i2c_dev *dev)
+{
+ u32 mask = IRQ_MASK(0);
+ writel(mask, dev->virtbase + I2C_IMSCR);
+}
+
+/**
+ * clear_all_interrupts() - Clear all interrupts of I2C Controller
+ * @dev: private data of I2C Driver
+ */
+static void clear_all_interrupts(struct nmk_i2c_dev *dev)
+{
+ u32 mask;
+ mask = IRQ_MASK(I2C_CLEAR_ALL_INTS);
+ writel(mask, dev->virtbase + I2C_ICR);
+}
+
+/**
+ * init_hw() - initialize the I2C hardware
+ * @dev: private data of I2C Driver
+ */
+static int init_hw(struct nmk_i2c_dev *dev)
+{
+ int stat;
+
+ stat = flush_i2c_fifo(dev);
+ if (stat)
+ return stat;
+
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+ disable_all_interrupts(dev);
+
+ clear_all_interrupts(dev);
+
+ dev->cli.operation = I2C_NO_OPERATION;
+
+ return 0;
+}
+
+/* enable peripheral, master mode operation */
+#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
+
+/**
+ * load_i2c_mcr_reg() - load the MCR register
+ * @dev: private data of controller
+ */
+static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev)
+{
+ u32 mcr = 0;
+
+ /* 7-bit address transaction */
+ mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
+ mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
+
+ /* start byte procedure not applied */
+ mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
+
+ /* check the operation, master read/write? */
+ if (dev->cli.operation == I2C_WRITE)
+ mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0);
+ else
+ mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0);
+
+ /* stop or repeated start? */
+ if (dev->stop)
+ mcr |= GEN_MASK(1, I2C_MCR_STOP, 14);
+ else
+ mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14));
+
+ mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15);
+
+ return mcr;
+}
+
+/**
+ * setup_i2c_controller() - setup the controller
+ * @dev: private data of controller
+ */
+static void setup_i2c_controller(struct nmk_i2c_dev *dev)
+{
+ u32 brcr1, brcr2;
+ u32 i2c_clk, div;
+
+ writel(0x0, dev->virtbase + I2C_CR);
+ writel(0x0, dev->virtbase + I2C_HSMCR);
+ writel(0x0, dev->virtbase + I2C_TFTR);
+ writel(0x0, dev->virtbase + I2C_RFTR);
+ writel(0x0, dev->virtbase + I2C_DMAR);
+
+ /*
+ * set the slsu:
+ *
+ * slsu defines the data setup time after SCL clock
+ * stretching in terms of i2c clk cycles. The
+ * needed setup time for the three modes are 250ns,
+ * 100ns, 10ns repectively thus leading to the values
+ * of 14, 6, 2 for a 48 MHz i2c clk.
+ */
+ writel(dev->cfg.slsu << 16, dev->virtbase + I2C_SCR);
+
+ i2c_clk = clk_get_rate(dev->clk);
+
+ /* fallback to std. mode if machine has not provided it */
+ if (dev->cfg.clk_freq == 0)
+ dev->cfg.clk_freq = 100000;
+
+ /*
+ * The spec says, in case of std. mode the divider is
+ * 2 whereas it is 3 for fast and fastplus mode of
+ * operation. TODO - high speed support.
+ */
+ div = (dev->cfg.clk_freq > 100000) ? 3 : 2;
+
+ /*
+ * generate the mask for baud rate counters. The controller
+ * has two baud rate counters. One is used for High speed
+ * operation, and the other is for std, fast mode, fast mode
+ * plus operation. Currently we do not supprt high speed mode
+ * so set brcr1 to 0.
+ */
+ brcr1 = 0 << 16;
+ brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff;
+
+ /* set the baud rate counter register */
+ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+
+ /*
+ * set the speed mode. Currently we support
+ * only standard and fast mode of operation
+ * TODO - support for fast mode plus (upto 1Mb/s)
+ * and high speed (up to 3.4 Mb/s)
+ */
+ if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
+ dev_err(&dev->pdev->dev, "do not support this mode "
+ "defaulting to std. mode\n");
+ brcr2 = i2c_clk/(100000 * 2) & 0xffff;
+ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+ writel(I2C_FREQ_MODE_STANDARD << 4,
+ dev->virtbase + I2C_CR);
+ }
+ writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR);
+
+ /* set the Tx and Rx FIFO threshold */
+ writel(dev->cfg.tft, dev->virtbase + I2C_TFTR);
+ writel(dev->cfg.rft, dev->virtbase + I2C_RFTR);
+}
+
+/**
+ * read_i2c() - Read from I2C client device
+ * @dev: private data of I2C Driver
+ *
+ * This function reads from i2c client device when controller is in
+ * master mode. There is a completion timeout. If there is no transfer
+ * before timeout error is returned.
+ */
+static int read_i2c(struct nmk_i2c_dev *dev)
+{
+ u32 status = 0;
+ u32 mcr;
+ u32 irq_mask = 0;
+ int timeout;
+
+ mcr = load_i2c_mcr_reg(dev);
+ writel(mcr, dev->virtbase + I2C_MCR);
+
+ /* load the current CR value */
+ writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+ dev->virtbase + I2C_CR);
+
+ /* enable the controller */
+ i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+
+ init_completion(&dev->xfer_complete);
+
+ /* enable interrupts by setting the mask */
+ irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
+ I2C_IT_MAL | I2C_IT_BERR);
+
+ if (dev->stop)
+ irq_mask |= I2C_IT_MTD;
+ else
+ irq_mask |= I2C_IT_MTDWS;
+
+ irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+ writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+ dev->virtbase + I2C_IMSCR);
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+
+ if (timeout < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout"
+ "returned %d waiting for event\n", timeout);
+ status = timeout;
+ }
+
+ if (timeout == 0) {
+ /* controler has timedout, re-init the h/w */
+ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
+ (void) init_hw(dev);
+ status = -ETIMEDOUT;
+ }
+
+ return status;
+}
+
+/**
+ * write_i2c() - Write data to I2C client.
+ * @dev: private data of I2C Driver
+ *
+ * This function writes data to I2C client
+ */
+static int write_i2c(struct nmk_i2c_dev *dev)
+{
+ u32 status = 0;
+ u32 mcr;
+ u32 irq_mask = 0;
+ int timeout;
+
+ mcr = load_i2c_mcr_reg(dev);
+
+ writel(mcr, dev->virtbase + I2C_MCR);
+
+ /* load the current CR value */
+ writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+ dev->virtbase + I2C_CR);
+
+ /* enable the controller */
+ i2c_set_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+ init_completion(&dev->xfer_complete);
+
+ /* enable interrupts by settings the masks */
+ irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR |
+ I2C_IT_MAL | I2C_IT_BERR);
+
+ /*
+ * check if we want to transfer a single or multiple bytes, if so
+ * set the MTDWS bit (Master Transaction Done Without Stop)
+ * to start repeated start operation
+ */
+ if (dev->stop)
+ irq_mask |= I2C_IT_MTD;
+ else
+ irq_mask |= I2C_IT_MTDWS;
+
+ irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+ writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+ dev->virtbase + I2C_IMSCR);
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+
+ if (timeout < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout"
+ "returned %d waiting for event\n", timeout);
+ status = timeout;
+ }
+
+ if (timeout == 0) {
+ /* controler has timedout, re-init the h/w */
+ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
+ (void) init_hw(dev);
+ status = -ETIMEDOUT;
+ }
+
+ return status;
+}
+
+/**
+ * nmk_i2c_xfer() - I2C transfer function used by kernel framework
+ * @i2c_adap - Adapter pointer to the controller
+ * @msgs[] - Pointer to data to be written.
+ * @num_msgs - Number of messages to be executed
+ *
+ * This is the function called by the generic kernel i2c_transfer()
+ * or i2c_smbus...() API calls. Note that this code is protected by the
+ * semaphore set in the kernel i2c_transfer() function.
+ *
+ * NOTE:
+ * READ TRANSFER : We impose a restriction of the first message to be the
+ * index message for any read transaction.
+ * - a no index is coded as '0',
+ * - 2byte big endian index is coded as '3'
+ * !!! msg[0].buf holds the actual index.
+ * This is compatible with generic messages of smbus emulator
+ * that send a one byte index.
+ * eg. a I2C transation to read 2 bytes from index 0
+ * idx = 0;
+ * msg[0].addr = client->addr;
+ * msg[0].flags = 0x0;
+ * msg[0].len = 1;
+ * msg[0].buf = &idx;
+ *
+ * msg[1].addr = client->addr;
+ * msg[1].flags = I2C_M_RD;
+ * msg[1].len = 2;
+ * msg[1].buf = rd_buff
+ * i2c_transfer(adap, msg, 2);
+ *
+ * WRITE TRANSFER : The I2C standard interface interprets all data as payload.
+ * If you want to emulate an SMBUS write transaction put the
+ * index as first byte(or first and second) in the payload.
+ * eg. a I2C transation to write 2 bytes from index 1
+ * wr_buff[0] = 0x1;
+ * wr_buff[1] = 0x23;
+ * wr_buff[2] = 0x46;
+ * msg[0].flags = 0x0;
+ * msg[0].len = 3;
+ * msg[0].buf = wr_buff;
+ * i2c_transfer(adap, msg, 1);
+ *
+ * To read or write a block of data (multiple bytes) using SMBUS emulation
+ * please use the i2c_smbus_read_i2c_block_data()
+ * or i2c_smbus_write_i2c_block_data() API
+ */
+static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num_msgs)
+{
+ int status;
+ int i;
+ u32 cause;
+ struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+
+ status = init_hw(dev);
+ if (status)
+ return status;
+
+ /* setup the i2c controller */
+ setup_i2c_controller(dev);
+
+ for (i = 0; i < num_msgs; i++) {
+ if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+ dev_err(&dev->pdev->dev, "10 bit addressing"
+ "not supported\n");
+ return -EINVAL;
+ }
+ dev->cli.slave_adr = msgs[i].addr;
+ dev->cli.buffer = msgs[i].buf;
+ dev->cli.count = msgs[i].len;
+ dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+ dev->result = 0;
+
+ if (msgs[i].flags & I2C_M_RD) {
+ /* it is a read operation */
+ dev->cli.operation = I2C_READ;
+ status = read_i2c(dev);
+ } else {
+ /* write operation */
+ dev->cli.operation = I2C_WRITE;
+ status = write_i2c(dev);
+ }
+ if (status || (dev->result)) {
+ /* get the abort cause */
+ cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7;
+ dev_err(&dev->pdev->dev, "error during I2C"
+ "message xfer: %d\n", cause);
+ dev_err(&dev->pdev->dev, "%s\n",
+ cause >= ARRAY_SIZE(abort_causes)
+ ? "unknown reason" : abort_causes[cause]);
+ return status;
+ }
+ mdelay(1);
+ }
+ /* return the no. messages processed */
+ if (status)
+ return status;
+ else
+ return num_msgs;
+}
+
+/**
+ * disable_interrupts() - disable the interrupts
+ * @dev: private data of controller
+ */
+static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
+{
+ irq = IRQ_MASK(irq);
+ writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq),
+ dev->virtbase + I2C_IMSCR);
+ return 0;
+}
+
+/**
+ * i2c_irq_handler() - interrupt routine
+ * @irq: interrupt number
+ * @arg: data passed to the handler
+ *
+ * This is the interrupt handler for the i2c driver. Currently
+ * it handles the major interrupts like Rx & Tx FIFO management
+ * interrupts, master transaction interrupts, arbitration and
+ * bus error interrupts. The rest of the interrupts are treated as
+ * unhandled.
+ */
+static irqreturn_t i2c_irq_handler(int irq, void *arg)
+{
+ struct nmk_i2c_dev *dev = arg;
+ u32 tft, rft;
+ u32 count;
+ u32 misr;
+ u32 src = 0;
+
+ /* load Tx FIFO and Rx FIFO threshold values */
+ tft = readl(dev->virtbase + I2C_TFTR);
+ rft = readl(dev->virtbase + I2C_RFTR);
+
+ /* read interrupt status register */
+ misr = readl(dev->virtbase + I2C_MISR);
+
+ src = __ffs(misr);
+ switch ((1 << src)) {
+
+ /* Transmit FIFO nearly empty interrupt */
+ case I2C_IT_TXFNE:
+ {
+ if (dev->cli.operation == I2C_READ) {
+ /*
+ * in read operation why do we care for writing?
+ * so disable the Transmit FIFO interrupt
+ */
+ disable_interrupts(dev, I2C_IT_TXFNE);
+ } else {
+ for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2);
+ (count > 0) &&
+ (dev->cli.count != 0);
+ count--) {
+ /* write to the Tx FIFO */
+ writeb(*dev->cli.buffer,
+ dev->virtbase + I2C_TFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+ /*
+ * if done, close the transfer by disabling the
+ * corresponding TXFNE interrupt
+ */
+ if (dev->cli.count == 0)
+ disable_interrupts(dev, I2C_IT_TXFNE);
+ }
+ }
+ break;
+
+ /*
+ * Rx FIFO nearly full interrupt.
+ * This is set when the numer of entries in Rx FIFO is
+ * greater or equal than the threshold value programmed
+ * in RFT
+ */
+ case I2C_IT_RXFNF:
+ for (count = rft; count > 0; count--) {
+ /* Read the Rx FIFO */
+ *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ }
+ dev->cli.count -= rft;
+ dev->cli.xfer_bytes += rft;
+ break;
+
+ /* Rx FIFO full */
+ case I2C_IT_RXFF:
+ for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) {
+ *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ }
+ dev->cli.count -= MAX_I2C_FIFO_THRESHOLD;
+ dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD;
+ break;
+
+ /* Master Transaction Done with/without stop */
+ case I2C_IT_MTD:
+ case I2C_IT_MTDWS:
+ if (dev->cli.operation == I2C_READ) {
+ while (!readl(dev->virtbase + I2C_RISR) & I2C_IT_RXFE) {
+ if (dev->cli.count == 0)
+ break;
+ *dev->cli.buffer =
+ readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+ }
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD);
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
+
+ disable_interrupts(dev,
+ (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
+ | I2C_IT_TXFOVR | I2C_IT_RXFNF
+ | I2C_IT_RXFF | I2C_IT_RXFE));
+
+ if (dev->cli.count) {
+ dev->result = -1;
+ dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
+ "xfered\n", dev->cli.count);
+ (void) init_hw(dev);
+ }
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /* Master Arbitration lost interrupt */
+ case I2C_IT_MAL:
+ dev->result = -1;
+ (void) init_hw(dev);
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /*
+ * Bus Error interrupt.
+ * This happens when an unexpected start/stop condition occurs
+ * during the transaction.
+ */
+ case I2C_IT_BERR:
+ dev->result = -1;
+ /* get the status */
+ if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
+ (void) init_hw(dev);
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR);
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /*
+ * Tx FIFO overrun interrupt.
+ * This is set when a write operation in Tx FIFO is performed and
+ * the Tx FIFO is full.
+ */
+ case I2C_IT_TXFOVR:
+ dev->result = -1;
+ (void) init_hw(dev);
+
+ dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /* unhandled interrupts by this driver - TODO*/
+ case I2C_IT_TXFE:
+ case I2C_IT_TXFF:
+ case I2C_IT_RXFE:
+ case I2C_IT_RFSR:
+ case I2C_IT_RFSE:
+ case I2C_IT_WTSR:
+ case I2C_IT_STD:
+ dev_err(&dev->pdev->dev, "unhandled Interrupt\n");
+ break;
+ default:
+ dev_err(&dev->pdev->dev, "spurious Interrupt..\n");
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C
+ | I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_WORD_DATA
+ | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm nmk_i2c_algo = {
+ .master_xfer = nmk_i2c_xfer,
+ .functionality = nmk_i2c_functionality
+};
+
+static int __devinit nmk_i2c_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+ struct nmk_i2c_controller *pdata =
+ pdev->dev.platform_data;
+ struct nmk_i2c_dev *dev;
+ struct i2c_adapter *adap;
+
+ dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ dev->pdev = pdev;
+ platform_set_drvdata(pdev, dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto err_no_resource;
+ }
+
+ if (request_mem_region(res->start, resource_size(res),
+ DRIVER_NAME "I/O region") == NULL) {
+ ret = -EBUSY;
+ goto err_no_region;
+ }
+
+ dev->virtbase = ioremap(res->start, resource_size(res));
+ if (!dev->virtbase) {
+ ret = -ENOMEM;
+ goto err_no_ioremap;
+ }
+
+ dev->irq = platform_get_irq(pdev, 0);
+ ret = request_irq(dev->irq, i2c_irq_handler, IRQF_DISABLED,
+ DRIVER_NAME, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
+ goto err_irq;
+ }
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(&pdev->dev, "could not get i2c clock\n");
+ ret = PTR_ERR(dev->clk);
+ goto err_no_clk;
+ }
+
+ clk_enable(dev->clk);
+
+ adap = &dev->adap;
+ adap->dev.parent = &pdev->dev;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = &nmk_i2c_algo;
+
+ /* fetch the controller id */
+ adap->nr = pdev->id;
+
+ /* fetch the controller configuration from machine */
+ dev->cfg.clk_freq = pdata->clk_freq;
+ dev->cfg.slsu = pdata->slsu;
+ dev->cfg.tft = pdata->tft;
+ dev->cfg.rft = pdata->rft;
+ dev->cfg.sm = pdata->sm;
+
+ i2c_set_adapdata(adap, dev);
+
+ ret = init_hw(dev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "error in initializing i2c hardware\n");
+ goto err_init_hw;
+ }
+
+ dev_dbg(&pdev->dev, "initialize I2C%d bus on virtual "
+ "base %p\n", pdev->id, dev->virtbase);
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add adapter\n");
+ goto err_add_adap;
+ }
+
+ return 0;
+
+ err_init_hw:
+ clk_disable(dev->clk);
+ err_add_adap:
+ clk_put(dev->clk);
+ err_no_clk:
+ free_irq(dev->irq, dev);
+ err_irq:
+ iounmap(dev->virtbase);
+ err_no_ioremap:
+ release_mem_region(res->start, resource_size(res));
+ err_no_region:
+ platform_set_drvdata(pdev, NULL);
+ err_no_resource:
+ kfree(dev);
+ err_no_mem:
+
+ return ret;
+}
+
+static int __devexit nmk_i2c_remove(struct platform_device *pdev)
+{
+ struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adap);
+ flush_i2c_fifo(dev);
+ disable_all_interrupts(dev);
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+ free_irq(dev->irq, dev);
+ iounmap(dev->virtbase);
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct platform_driver nmk_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+ .probe = nmk_i2c_probe,
+ .remove = __devexit_p(nmk_i2c_remove),
+};
+
+static int __init nmk_i2c_init(void)
+{
+ return platform_driver_register(&nmk_i2c_driver);
+}
+
+static void __exit nmk_i2c_exit(void)
+{
+ platform_driver_unregister(&nmk_i2c_driver);
+}
+
+subsys_initcall(nmk_i2c_init);
+module_exit(nmk_i2c_exit);
+
+MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
+MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 0dabe643ec5..b4ed4ca802e 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/i2c-ocores.h>
+#include <linux/slab.h>
#include <asm/io.h>
struct ocores_i2c {
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
new file mode 100644
index 00000000000..a2481f40ea1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -0,0 +1,652 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 Cavium Networks, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/octeon/octeon.h>
+
+#define DRV_NAME "i2c-octeon"
+
+/* The previous out-of-tree version was implicitly version 1.0. */
+#define DRV_VERSION "2.0"
+
+/* register offsets */
+#define SW_TWSI 0x00
+#define TWSI_INT 0x10
+
+/* Controller command patterns */
+#define SW_TWSI_V 0x8000000000000000ull
+#define SW_TWSI_EOP_TWSI_DATA 0x0C00000100000000ull
+#define SW_TWSI_EOP_TWSI_CTL 0x0C00000200000000ull
+#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C00000300000000ull
+#define SW_TWSI_EOP_TWSI_STAT 0x0C00000300000000ull
+#define SW_TWSI_EOP_TWSI_RST 0x0C00000700000000ull
+#define SW_TWSI_OP_TWSI_CLK 0x0800000000000000ull
+#define SW_TWSI_R 0x0100000000000000ull
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE 0x80
+#define TWSI_CTL_ENAB 0x40
+#define TWSI_CTL_STA 0x20
+#define TWSI_CTL_STP 0x10
+#define TWSI_CTL_IFLG 0x08
+#define TWSI_CTL_AAK 0x04
+
+/* Some status values */
+#define STAT_START 0x08
+#define STAT_RSTART 0x10
+#define STAT_TXADDR_ACK 0x18
+#define STAT_TXDATA_ACK 0x28
+#define STAT_RXADDR_ACK 0x40
+#define STAT_RXDATA_ACK 0x50
+#define STAT_IDLE 0xF8
+
+struct octeon_i2c {
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ int irq;
+ int twsi_freq;
+ int sys_freq;
+ resource_size_t twsi_phys;
+ void __iomem *twsi_base;
+ resource_size_t regsize;
+ struct device *dev;
+};
+
+/**
+ * octeon_i2c_write_sw - write an I2C core register.
+ * @i2c: The struct octeon_i2c.
+ * @eop_reg: Register selector.
+ * @data: Value to be written.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c,
+ u64 eop_reg,
+ u8 data)
+{
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI);
+ do {
+ tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
+ } while ((tmp & SW_TWSI_V) != 0);
+}
+
+/**
+ * octeon_i2c_read_sw - write an I2C core register.
+ * @i2c: The struct octeon_i2c.
+ * @eop_reg: Register selector.
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+{
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI);
+ do {
+ tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
+ } while ((tmp & SW_TWSI_V) != 0);
+
+ return tmp & 0xFF;
+}
+
+/**
+ * octeon_i2c_write_int - write the TWSI_INT register
+ * @i2c: The struct octeon_i2c.
+ * @data: Value to be written.
+ */
+static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+{
+ u64 tmp;
+
+ __raw_writeq(data, i2c->twsi_base + TWSI_INT);
+ tmp = __raw_readq(i2c->twsi_base + TWSI_INT);
+}
+
+/**
+ * octeon_i2c_int_enable - enable the TS interrupt.
+ * @i2c: The struct octeon_i2c.
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, 0x40);
+}
+
+/**
+ * octeon_i2c_int_disable - disable the TS interrupt.
+ * @i2c: The struct octeon_i2c.
+ */
+static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, 0);
+}
+
+/**
+ * octeon_i2c_unblock - unblock the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * If there was a reset while a device was driving 0 to bus,
+ * bus is blocked. We toggle it free manually by some clock
+ * cycles and send a stop.
+ */
+static void octeon_i2c_unblock(struct octeon_i2c *i2c)
+{
+ int i;
+
+ dev_dbg(i2c->dev, "%s\n", __func__);
+ for (i = 0; i < 9; i++) {
+ octeon_i2c_write_int(i2c, 0x0);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0x200);
+ udelay(5);
+ }
+ octeon_i2c_write_int(i2c, 0x300);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0x100);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0x0);
+}
+
+/**
+ * octeon_i2c_isr - the interrupt service routine.
+ * @int: The irq, unused.
+ * @dev_id: Our struct octeon_i2c.
+ */
+static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+ struct octeon_i2c *i2c = dev_id;
+
+ octeon_i2c_int_disable(i2c);
+ wake_up_interruptible(&i2c->queue);
+
+ return IRQ_HANDLED;
+}
+
+
+static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+{
+ return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) != 0;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+ int result;
+
+ octeon_i2c_int_enable(i2c);
+
+ result = wait_event_interruptible_timeout(i2c->queue,
+ octeon_i2c_test_iflg(i2c),
+ i2c->adap.timeout);
+
+ octeon_i2c_int_disable(i2c);
+
+ if (result < 0) {
+ dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
+ return result;
+ } else if (result == 0) {
+ dev_dbg(i2c->dev, "%s: timeout\n", __func__);
+ result = -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/**
+ * octeon_i2c_start - send START to the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
+{
+ u8 data;
+ int result;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_STA);
+
+ result = octeon_i2c_wait(i2c);
+ if (result) {
+ if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == STAT_IDLE) {
+ /*
+ * Controller refused to send start flag May
+ * be a client is holding SDA low - let's try
+ * to free it.
+ */
+ octeon_i2c_unblock(i2c);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_STA);
+
+ result = octeon_i2c_wait(i2c);
+ }
+ if (result)
+ return result;
+ }
+
+ data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if ((data != STAT_START) && (data != STAT_RSTART)) {
+ dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * octeon_i2c_stop - send STOP to the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_stop(struct octeon_i2c *i2c)
+{
+ u8 data;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_STP);
+
+ data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+
+ if (data != STAT_IDLE) {
+ dev_err(i2c->dev, "%s: bad status(0x%x)\n", __func__, data);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * octeon_i2c_write - send data to the bus.
+ * @i2c: The struct octeon_i2c.
+ * @target: Target address.
+ * @data: Pointer to the data to be sent.
+ * @length: Length of the data.
+ *
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+ const u8 *data, int length)
+{
+ int i, result;
+ u8 tmp;
+
+ result = octeon_i2c_start(i2c);
+ if (result)
+ return result;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) {
+ dev_err(i2c->dev,
+ "%s: bad status before write (0x%x)\n",
+ __func__, tmp);
+ return -EIO;
+ }
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+ }
+
+ return 0;
+}
+
+/**
+ * octeon_i2c_read - receive data from the bus.
+ * @i2c: The struct octeon_i2c.
+ * @target: Target address.
+ * @data: Pointer to the location to store the datae .
+ * @length: Length of the data.
+ *
+ * The address is sent over the bus, then the data is read.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
+ u8 *data, int length)
+{
+ int i, result;
+ u8 tmp;
+
+ if (length < 1)
+ return -EINVAL;
+
+ result = octeon_i2c_start(i2c);
+ if (result)
+ return result;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target<<1) | 1);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) {
+ dev_err(i2c->dev,
+ "%s: bad status before read (0x%x)\n",
+ __func__, tmp);
+ return -EIO;
+ }
+
+ if (i+1 < length)
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_AAK);
+ else
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+ }
+ return 0;
+}
+
+/**
+ * octeon_i2c_xfer - The driver's master_xfer function.
+ * @adap: Pointer to the i2c_adapter structure.
+ * @msgs: Pointer to the messages to be processed.
+ * @num: Length of the MSGS array.
+ *
+ * Returns the number of messages processed, or a negative errno on
+ * failure.
+ */
+static int octeon_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_msg *pmsg;
+ int i;
+ int ret = 0;
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+ for (i = 0; ret == 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ dev_dbg(i2c->dev,
+ "Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);
+ if (pmsg->flags & I2C_M_RD)
+ ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ else
+ ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ }
+ octeon_i2c_stop(i2c);
+
+ return (ret != 0) ? ret : num;
+}
+
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm octeon_i2c_algo = {
+ .master_xfer = octeon_i2c_xfer,
+ .functionality = octeon_i2c_functionality,
+};
+
+static struct i2c_adapter octeon_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "OCTEON adapter",
+ .algo = &octeon_i2c_algo,
+ .timeout = 2,
+};
+
+/**
+ * octeon_i2c_setclock - Calculate and set clock divisors.
+ */
+static int __init octeon_i2c_setclock(struct octeon_i2c *i2c)
+{
+ int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+ int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+
+ for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+ /*
+ * An mdiv value of less than 2 seems to not work well
+ * with ds1337 RTCs, so we constrain it to larger
+ * values.
+ */
+ for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
+ /*
+ * For given ndiv and mdiv values check the
+ * two closest thp values.
+ */
+ tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+ tclk *= (1 << ndiv_idx);
+ thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+ for (inc = 0; inc <= 1; inc++) {
+ thp_idx = thp_base + inc;
+ if (thp_idx < 5 || thp_idx > 0xff)
+ continue;
+
+ foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+ foscl = foscl / (1 << ndiv_idx);
+ foscl = foscl / (mdiv_idx + 1) / 10;
+ diff = abs(foscl - i2c->twsi_freq);
+ if (diff < delta_hz) {
+ delta_hz = diff;
+ thp = thp_idx;
+ mdiv = mdiv_idx;
+ ndiv = ndiv_idx;
+ }
+ }
+ }
+ }
+ octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+
+ return 0;
+}
+
+static int __init octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
+{
+ u8 status;
+ int tries;
+
+ /* disable high level controller, enable bus access */
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ /* reset controller */
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+ for (tries = 10; tries; tries--) {
+ udelay(1);
+ status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if (status == STAT_IDLE)
+ return 0;
+ }
+ dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
+ return -EIO;
+}
+
+static int __devinit octeon_i2c_probe(struct platform_device *pdev)
+{
+ int irq, result = 0;
+ struct octeon_i2c *i2c;
+ struct octeon_i2c_data *i2c_data;
+ struct resource *res_mem;
+
+ /* All adaptors have an irq. */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "kzalloc failed\n");
+ result = -ENOMEM;
+ goto out;
+ }
+ i2c->dev = &pdev->dev;
+ i2c_data = pdev->dev.platform_data;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (res_mem == NULL) {
+ dev_err(i2c->dev, "found no memory resource\n");
+ result = -ENXIO;
+ goto fail_region;
+ }
+
+ if (i2c_data == NULL) {
+ dev_err(i2c->dev, "no I2C frequency data\n");
+ result = -ENXIO;
+ goto fail_region;
+ }
+
+ i2c->twsi_phys = res_mem->start;
+ i2c->regsize = resource_size(res_mem);
+ i2c->twsi_freq = i2c_data->i2c_freq;
+ i2c->sys_freq = i2c_data->sys_freq;
+
+ if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) {
+ dev_err(i2c->dev, "request_mem_region failed\n");
+ goto fail_region;
+ }
+ i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize);
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->irq = irq;
+
+ result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto fail_irq;
+ }
+
+ result = octeon_i2c_initlowlevel(i2c);
+ if (result) {
+ dev_err(i2c->dev, "init low level failed\n");
+ goto fail_add;
+ }
+
+ result = octeon_i2c_setclock(i2c);
+ if (result) {
+ dev_err(i2c->dev, "clock init failed\n");
+ goto fail_add;
+ }
+
+ i2c->adap = octeon_i2c_ops;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ result = i2c_add_numbered_adapter(&i2c->adap);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to add adapter\n");
+ goto fail_add;
+ }
+
+ dev_info(i2c->dev, "version %s\n", DRV_VERSION);
+
+ return result;
+
+fail_add:
+ platform_set_drvdata(pdev, NULL);
+ free_irq(i2c->irq, i2c);
+fail_irq:
+ iounmap(i2c->twsi_base);
+ release_mem_region(i2c->twsi_phys, i2c->regsize);
+fail_region:
+ kfree(i2c);
+out:
+ return result;
+};
+
+static int __devexit octeon_i2c_remove(struct platform_device *pdev)
+{
+ struct octeon_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+ free_irq(i2c->irq, i2c);
+ iounmap(i2c->twsi_base);
+ release_mem_region(i2c->twsi_phys, i2c->regsize);
+ kfree(i2c);
+ return 0;
+};
+
+static struct platform_driver octeon_i2c_driver = {
+ .probe = octeon_i2c_probe,
+ .remove = __devexit_p(octeon_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init octeon_i2c_init(void)
+{
+ int rv;
+
+ rv = platform_driver_register(&octeon_i2c_driver);
+ return rv;
+}
+
+static void __exit octeon_i2c_exit(void)
+{
+ platform_driver_unregister(&octeon_i2c_driver);
+}
+
+MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
+
+module_init(octeon_i2c_init);
+module_exit(octeon_i2c_exit);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 827da085813..6bd0f19cd45 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -37,6 +37,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/slab.h>
/* I2C controller revisions */
#define OMAP_I2C_REV_2 0x20
@@ -49,24 +50,24 @@
#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_IE_REG 0x01
+#define OMAP_I2C_STAT_REG 0x02
+#define OMAP_I2C_IV_REG 0x03
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
-#define OMAP_I2C_WE_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
-#define OMAP_I2C_BUFSTAT_REG 0x40
+#define OMAP_I2C_WE_REG 0x03
+#define OMAP_I2C_SYSS_REG 0x04
+#define OMAP_I2C_BUF_REG 0x05
+#define OMAP_I2C_CNT_REG 0x06
+#define OMAP_I2C_DATA_REG 0x07
+#define OMAP_I2C_SYSC_REG 0x08
+#define OMAP_I2C_CON_REG 0x09
+#define OMAP_I2C_OA_REG 0x0a
+#define OMAP_I2C_SA_REG 0x0b
+#define OMAP_I2C_PSC_REG 0x0c
+#define OMAP_I2C_SCLL_REG 0x0d
+#define OMAP_I2C_SCLH_REG 0x0e
+#define OMAP_I2C_SYSTEST_REG 0x0f
+#define OMAP_I2C_BUFSTAT_REG 0x10
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
@@ -161,6 +162,7 @@ struct omap_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
int irq;
+ int reg_shift; /* bit shift for I2C register addresses */
struct clk *iclk; /* Interface clock */
struct clk *fclk; /* Functional clock */
struct completion cmd_complete;
@@ -178,17 +180,23 @@ struct omap_i2c_dev {
unsigned b_hw:1; /* bad h/w fixes */
unsigned idle:1;
u16 iestate; /* Saved interrupt register */
+ u16 pscstate;
+ u16 scllstate;
+ u16 sclhstate;
+ u16 bufstate;
+ u16 syscstate;
+ u16 westate;
};
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
int reg, u16 val)
{
- __raw_writew(val, i2c_dev->base + reg);
+ __raw_writew(val, i2c_dev->base + (reg << i2c_dev->reg_shift));
}
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
{
- return __raw_readw(i2c_dev->base + reg);
+ return __raw_readw(i2c_dev->base + (reg << i2c_dev->reg_shift));
}
static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
@@ -230,7 +238,22 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
clk_enable(dev->iclk);
clk_enable(dev->fclk);
+ if (cpu_is_omap34xx()) {
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ }
dev->idle = 0;
+
+ /*
+ * Don't write to this register if the IE state is 0 as it can
+ * cause deadlock.
+ */
if (dev->iestate)
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
}
@@ -258,13 +281,18 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
static int omap_i2c_init(struct omap_i2c_dev *dev)
{
- u16 psc = 0, scll = 0, sclh = 0;
+ u16 psc = 0, scll = 0, sclh = 0, buf = 0;
u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
unsigned long fclk_rate = 12000000;
unsigned long timeout;
unsigned long internal_clk = 0;
if (dev->rev >= OMAP_I2C_REV_2) {
+ /* Disable I2C controller before soft reset */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+ ~(OMAP_I2C_CON_EN));
+
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
/* For some reason we need to set the EN bit before the
* reset done bit gets set. */
@@ -287,24 +315,22 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
SYSC_AUTOIDLE_MASK);
} else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
- u32 v;
-
- v = SYSC_AUTOIDLE_MASK;
- v |= SYSC_ENAWAKEUP_MASK;
- v |= (SYSC_IDLEMODE_SMART <<
+ dev->syscstate = SYSC_AUTOIDLE_MASK;
+ dev->syscstate |= SYSC_ENAWAKEUP_MASK;
+ dev->syscstate |= (SYSC_IDLEMODE_SMART <<
__ffs(SYSC_SIDLEMODE_MASK));
- v |= (SYSC_CLOCKACTIVITY_FCLK <<
+ dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK <<
__ffs(SYSC_CLOCKACTIVITY_MASK));
- omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v);
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
+ dev->syscstate);
/*
* Enabling all wakup sources to stop I2C freezing on
* WFI instruction.
* REVISIT: Some wkup sources might not be needed.
*/
- omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
- OMAP_I2C_WE_ALL);
-
+ dev->westate = OMAP_I2C_WE_ALL;
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
}
}
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
@@ -394,23 +420,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
- if (dev->fifo_size)
- /* Note: setup required fifo size - 1 */
- omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
- (dev->fifo_size - 1) << 8 | /* RTRSH */
- OMAP_I2C_BUF_RXFIF_CLR |
- (dev->fifo_size - 1) | /* XTRSH */
- OMAP_I2C_BUF_TXFIF_CLR);
+ if (dev->fifo_size) {
+ /* Note: setup required fifo size - 1. RTRSH and XTRSH */
+ buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR |
+ (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR;
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
+ }
/* 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 |
+ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
- (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0));
+ (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
+ if (cpu_is_omap34xx()) {
+ dev->pscstate = psc;
+ dev->scllstate = scll;
+ dev->sclhstate = sclh;
+ dev->bufstate = buf;
+ }
return 0;
}
@@ -820,7 +851,7 @@ static const struct i2c_algorithm omap_i2c_algo = {
.functionality = omap_i2c_func,
};
-static int __init
+static int __devinit
omap_i2c_probe(struct platform_device *pdev)
{
struct omap_i2c_dev *dev;
@@ -895,6 +926,11 @@ omap_i2c_probe(struct platform_device *pdev)
dev->b_hw = 1; /* Enable hardware fixes */
}
+ if (cpu_is_omap7xx())
+ dev->reg_shift = 1;
+ else
+ dev->reg_shift = 2;
+
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 322c5691e38..5f41ec0f72d 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport-light.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
Based on older i2c-velleman.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,10 +27,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
#include <asm/io.h>
#include "i2c-parport.h"
@@ -43,6 +45,10 @@ static u16 base;
module_param(base, ushort, 0);
MODULE_PARM_DESC(base, "Base I/O address");
+static int irq;
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "IRQ (optional)");
+
/* ----- Low-level parallel port access ----------------------------------- */
static inline void port_write(unsigned char p, unsigned char d)
@@ -119,6 +125,16 @@ static struct i2c_adapter parport_adapter = {
.name = "Parallel port adapter (light)",
};
+/* SMBus alert support */
+static struct i2c_smbus_alert_setup alert_data = {
+ .alert_edge_triggered = 1,
+};
+static struct i2c_client *ara;
+static struct lineop parport_ctrl_irq = {
+ .val = (1 << 4),
+ .port = CTRL,
+};
+
static int __devinit i2c_parport_probe(struct platform_device *pdev)
{
int err;
@@ -127,18 +143,39 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
parport_setsda(NULL, 1);
parport_setscl(NULL, 1);
/* Other init if needed (power on...) */
- if (adapter_parm[type].init.val)
+ if (adapter_parm[type].init.val) {
line_set(1, &adapter_parm[type].init);
+ /* Give powered devices some time to settle */
+ msleep(100);
+ }
parport_adapter.dev.parent = &pdev->dev;
err = i2c_bit_add_bus(&parport_adapter);
- if (err)
+ if (err) {
dev_err(&pdev->dev, "Unable to register with I2C\n");
- return err;
+ return err;
+ }
+
+ /* Setup SMBus alert if supported */
+ if (adapter_parm[type].smbus_alert && irq) {
+ alert_data.irq = irq;
+ ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data);
+ if (ara)
+ line_set(1, &parport_ctrl_irq);
+ else
+ dev_warn(&pdev->dev, "Failed to register ARA client\n");
+ }
+
+ return 0;
}
static int __devexit i2c_parport_remove(struct platform_device *pdev)
{
+ if (ara) {
+ line_set(0, &parport_ctrl_irq);
+ i2c_unregister_device(ara);
+ ara = NULL;
+ }
i2c_del_adapter(&parport_adapter);
/* Un-init if needed (power off...) */
@@ -205,6 +242,9 @@ static int __init i2c_parport_init(void)
if (!request_region(base, 3, DRVNAME))
return -EBUSY;
+ if (irq != 0)
+ pr_info(DRVNAME ": using irq %d\n", irq);
+
if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 0d8998610c7..846583ed476 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
Based on older i2c-philips-par.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,9 +27,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/parport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
+#include <linux/slab.h>
#include "i2c-parport.h"
/* ----- Device list ------------------------------------------------------ */
@@ -38,6 +41,8 @@ struct i2c_par {
struct pardevice *pdev;
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo_data;
+ struct i2c_smbus_alert_setup alert_data;
+ struct i2c_client *ara;
struct i2c_par *next;
};
@@ -143,6 +148,19 @@ static struct i2c_algo_bit_data parport_algo_data = {
/* ----- I2c and parallel port call-back functions and structures --------- */
+void i2c_parport_irq(void *data)
+{
+ struct i2c_par *adapter = data;
+ struct i2c_client *ara = adapter->ara;
+
+ if (ara) {
+ dev_dbg(&ara->dev, "SMBus alert received\n");
+ i2c_handle_smbus_alert(ara);
+ } else
+ dev_dbg(&adapter->adapter.dev,
+ "SMBus alert received but no ARA client!\n");
+}
+
static void i2c_parport_attach (struct parport *port)
{
struct i2c_par *adapter;
@@ -154,8 +172,9 @@ static void i2c_parport_attach (struct parport *port)
}
pr_debug("i2c-parport: attaching to %s\n", port->name);
+ parport_disable_irq(port);
adapter->pdev = parport_register_device(port, "i2c-parport",
- NULL, NULL, NULL, PARPORT_FLAG_EXCL, NULL);
+ NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
if (!adapter->pdev) {
printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
goto ERROR0;
@@ -185,14 +204,29 @@ static void i2c_parport_attach (struct parport *port)
parport_setsda(port, 1);
parport_setscl(port, 1);
/* Other init if needed (power on...) */
- if (adapter_parm[type].init.val)
+ if (adapter_parm[type].init.val) {
line_set(port, 1, &adapter_parm[type].init);
+ /* Give powered devices some time to settle */
+ msleep(100);
+ }
if (i2c_bit_add_bus(&adapter->adapter) < 0) {
printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
goto ERROR1;
}
+ /* Setup SMBus alert if supported */
+ if (adapter_parm[type].smbus_alert) {
+ adapter->alert_data.alert_edge_triggered = 1;
+ adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
+ &adapter->alert_data);
+ if (adapter->ara)
+ parport_enable_irq(port);
+ else
+ printk(KERN_WARNING "i2c-parport: Failed to register "
+ "ARA client\n");
+ }
+
/* Add the new adapter to the list */
adapter->next = adapter_list;
adapter_list = adapter;
@@ -213,6 +247,10 @@ static void i2c_parport_detach (struct parport *port)
for (prev = NULL, adapter = adapter_list; adapter;
prev = adapter, adapter = adapter->next) {
if (adapter->pdev->port == port) {
+ if (adapter->ara) {
+ parport_disable_irq(port);
+ i2c_unregister_device(adapter->ara);
+ }
i2c_del_adapter(&adapter->adapter);
/* Un-init if needed (power off...) */
diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h
index ed69d846cb9..a9f66816546 100644
--- a/drivers/i2c/busses/i2c-parport.h
+++ b/drivers/i2c/busses/i2c-parport.h
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.h I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@ struct adapter_parm {
struct lineop getsda;
struct lineop getscl;
struct lineop init;
+ unsigned int smbus_alert:1;
};
static struct adapter_parm adapter_parm[] = {
@@ -73,6 +74,7 @@ static struct adapter_parm adapter_parm[] = {
.setscl = { 0x01, DATA, 1 },
.getsda = { 0x10, STAT, 1 },
.init = { 0xf0, DATA, 0 },
+ .smbus_alert = 1,
},
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
{
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index adf0fbb902f..d3d4a4b43a1 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -24,6 +24,7 @@
#include <linux/sched.h>
#include <linux/i2c.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#include <asm/io.h>
static struct pci_driver pasemi_smb_driver;
@@ -400,7 +401,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev)
kfree(smbus);
}
-static struct pci_device_id pasemi_smb_ids[] = {
+static const struct pci_device_id pasemi_smb_ids[] = {
{ PCI_DEVICE(0x1959, 0xa003) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index 0ed68e2ccd2..f7346a9bd95 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -75,7 +75,7 @@ static int pca_isa_waitforcompletion(void *pd)
unsigned long timeout;
if (irq > -1) {
- ret = wait_event_interruptible_timeout(pca_wait,
+ ret = wait_event_timeout(pca_wait,
pca_isa_readbyte(pd, I2C_PCA_CON)
& I2C_PCA_CON_SI, pca_isa_ops.timeout);
} else {
@@ -96,7 +96,7 @@ static void pca_isa_resetchip(void *pd)
}
static irqreturn_t pca_handler(int this_irq, void *dev_id) {
- wake_up_interruptible(&pca_wait);
+ wake_up(&pca_wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index c4df9d411cd..5b2213df5ed 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -84,7 +84,7 @@ static int i2c_pca_pf_waitforcompletion(void *pd)
unsigned long timeout;
if (i2c->irq) {
- ret = wait_event_interruptible_timeout(i2c->wait,
+ ret = wait_event_timeout(i2c->wait,
i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
& I2C_PCA_CON_SI, i2c->adap.timeout);
} else {
@@ -122,7 +122,7 @@ static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
return IRQ_NONE;
- wake_up_interruptible(&i2c->wait);
+ wake_up(&i2c->wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 1e245e9cad3..ee9da6fcf69 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -324,12 +324,12 @@ static int piix4_transaction(void)
else
msleep(1);
- while ((timeout++ < MAX_TIMEOUT) &&
+ while ((++timeout < MAX_TIMEOUT) &&
((temp = inb_p(SMBHSTSTS)) & 0x01))
msleep(1);
/* If the SMBus is still busy, we give up */
- if (timeout >= MAX_TIMEOUT) {
+ if (timeout == MAX_TIMEOUT) {
dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT;
}
@@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id piix4_ids[] = {
+static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index fbab6846ae6..247103372a0 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -20,15 +20,16 @@
#include <linux/platform_device.h>
#include <linux/i2c-pnx.h>
#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
#include <mach/hardware.h>
#include <mach/i2c.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)
{
@@ -50,22 +51,21 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
return (timeout <= 0);
}
-static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *data = adap->algo_data;
- struct timer_list *timer = &data->mif.timer;
- int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+ struct timer_list *timer = &alg_data->mif.timer;
+ unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
if (expires <= 1)
expires = 2;
del_timer_sync(timer);
- dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
+ dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
jiffies, expires);
timer->expires = jiffies + expires;
- timer->data = (unsigned long)adap;
+ timer->data = (unsigned long)&alg_data;
add_timer(timer);
}
@@ -77,34 +77,34 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
*
* Generate a START signal in the desired mode.
*/
-static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
+static int i2c_pnx_start(unsigned char slave_addr,
+ struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
- dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__,
+ dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__,
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);
+ dev_err(&alg_data->adapter.dev,
+ "%s: Invalid slave address %x. Only 7-bit addresses are supported\n",
+ alg_data->adapter.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)));
+ dev_err(&alg_data->adapter.dev,
+ "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
+ alg_data->adapter.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);
+ dev_err(&alg_data->adapter.dev,
+ "%s: Arbitration failure. Slave addr = %02x\n",
+ alg_data->adapter.name, slave_addr);
return -EIO;
}
@@ -115,14 +115,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__,
+ dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__,
(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", __func__);
+ dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__);
return 0;
}
@@ -133,13 +133,12 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
*
* Generate a STOP signal to terminate the master transaction.
*/
-static void i2c_pnx_stop(struct i2c_adapter *adap)
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
{
- 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",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
/* Write a STOP bit to TX FIFO */
@@ -153,7 +152,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
timeout--;
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
}
@@ -163,36 +162,29 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
*
* Sends one byte of data to the slave
*/
-static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 val;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, 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", __func__,
- val, alg_data->mif.len + 1);
+ dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n",
+ __func__, 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");
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
}
/* Disable master interrupts */
iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -201,14 +193,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
del_timer_sync(&alg_data->mif.timer);
- dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine.\n",
__func__);
complete(&alg_data->mif.complete);
}
} else if (alg_data->mif.len == 0) {
/* zero-sized transfer */
- i2c_pnx_stop(adap);
+ i2c_pnx_stop(alg_data);
/* Disable master interrupts. */
iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -217,13 +210,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
/* Stop timer. */
del_timer_sync(&alg_data->mif.timer);
- dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
- "zero-xfer.\n", __func__);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine after zero-xfer.\n",
+ __func__);
complete(&alg_data->mif.complete);
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
return 0;
@@ -235,28 +229,23 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
*
* Reads one byte data from the slave
*/
-static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
{
- 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",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, 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", __func__);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Write dummy data to fill Rx-fifo...\n",
+ __func__);
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)
@@ -281,16 +270,16 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
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", __func__, val,
- alg_data->mif.len);
+ dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n",
+ __func__, 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");
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
/* Disable master interrupts */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -304,7 +293,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
}
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
return 0;
@@ -312,11 +301,11 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
{
+ struct i2c_pnx_algo_data *alg_data = dev_id;
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",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): mstat = %x mctrl = %x, mode = %d\n",
__func__,
ioread32(I2C_REG_STS(alg_data)),
ioread32(I2C_REG_CTL(alg_data)),
@@ -339,10 +328,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
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",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Slave did not acknowledge, generating a STOP.\n",
__func__);
- i2c_pnx_stop(adap);
+ i2c_pnx_stop(alg_data);
/* Disable master interrupts. */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -368,9 +357,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
*/
if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
- i2c_pnx_master_xmit(adap);
+ i2c_pnx_master_xmit(alg_data);
} else if (alg_data->mif.mode == I2C_SMBUS_READ) {
- i2c_pnx_master_rcv(adap);
+ i2c_pnx_master_rcv(alg_data);
}
}
}
@@ -379,7 +368,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
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",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): exiting, stat = %x ctrl = %x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)),
ioread32(I2C_REG_CTL(alg_data)));
@@ -388,14 +378,13 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
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;
+ struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)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)));
+ dev_err(&alg_data->adapter.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));
@@ -409,15 +398,14 @@ static void i2c_pnx_timeout(unsigned long data)
complete(&alg_data->mif.complete);
}
-static inline void bus_reset_if_active(struct i2c_adapter *adap)
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
{
- 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,
+ dev_err(&alg_data->adapter.dev,
"%s: Bus is still active after xfer. Reset it...\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
@@ -451,10 +439,11 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
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",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): entering: %d messages, stat = %04x.\n",
__func__, num, ioread32(I2C_REG_STS(alg_data)));
- bus_reset_if_active(adap);
+ bus_reset_if_active(alg_data);
/* Process transactions in a loop. */
for (i = 0; rc >= 0 && i < num; i++) {
@@ -464,9 +453,9 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
addr = pmsg->addr;
if (pmsg->flags & I2C_M_TEN) {
- dev_err(&adap->dev,
+ dev_err(&alg_data->adapter.dev,
"%s: 10 bits addr not supported!\n",
- adap->name);
+ alg_data->adapter.name);
rc = -EINVAL;
break;
}
@@ -478,11 +467,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
alg_data->mif.ret = 0;
alg_data->last = (i == num - 1);
- dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__,
- alg_data->mif.mode,
- alg_data->mif.len);
+ dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+ __func__, alg_data->mif.mode, alg_data->mif.len);
- i2c_pnx_arm_timer(adap);
+ i2c_pnx_arm_timer(alg_data);
/* initialize the completion var */
init_completion(&alg_data->mif.complete);
@@ -493,7 +481,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
I2C_REG_CTL(alg_data));
/* Put start-code and slave-address on the bus. */
- rc = i2c_pnx_start(addr, adap);
+ rc = i2c_pnx_start(addr, alg_data);
if (rc < 0)
break;
@@ -502,31 +490,32 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (!(rc = alg_data->mif.ret))
completed++;
- dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Complete, return code = %d.\n",
__func__, 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,
+ dev_dbg(&alg_data->adapter.dev,
"%s: TDI still set... clearing now.\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(stat, I2C_REG_STS(alg_data));
}
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
- dev_dbg(&adap->dev,
+ dev_dbg(&alg_data->adapter.dev,
"%s: AFI still set... clearing now.\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(stat, I2C_REG_STS(alg_data));
}
}
- bus_reset_if_active(adap);
+ bus_reset_if_active(alg_data);
/* Cleanup to be sure... */
alg_data->mif.buf = NULL;
alg_data->mif.len = 0;
- dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
if (completed != num)
@@ -545,69 +534,92 @@ static struct i2c_algorithm pnx_algorithm = {
.functionality = i2c_pnx_func,
};
+#ifdef CONFIG_PM
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);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ /* FIXME: shouldn't this be clk_disable? */
+ clk_enable(alg_data->clk);
+
+ return 0;
}
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);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ return clk_enable(alg_data->clk);
}
+#else
+#define i2c_pnx_controller_suspend NULL
+#define i2c_pnx_controller_resume NULL
+#endif
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;
+ unsigned long freq;
struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
- if (!i2c_pnx || !i2c_pnx->adapter) {
+ if (!i2c_pnx || !i2c_pnx->name) {
dev_err(&pdev->dev, "%s: no platform data supplied\n",
__func__);
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\n", freq_mhz);
+ alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
+ if (!alg_data) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
}
- i2c_pnx->adapter->algo = &pnx_algorithm;
+ platform_set_drvdata(pdev, alg_data);
+
+ strlcpy(alg_data->adapter.name, i2c_pnx->name,
+ sizeof(alg_data->adapter.name));
+ alg_data->adapter.dev.parent = &pdev->dev;
+ alg_data->adapter.algo = &pnx_algorithm;
+ alg_data->adapter.algo_data = alg_data;
+ alg_data->adapter.nr = pdev->id;
+ alg_data->i2c_pnx = i2c_pnx;
+
+ alg_data->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(alg_data->clk)) {
+ ret = PTR_ERR(alg_data->clk);
+ goto out_drvdata;
+ }
- 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;
+ alg_data->mif.timer.data = (unsigned long)alg_data;
/* Register I/O resource */
- if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE,
+ if (!request_mem_region(i2c_pnx->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);
+ i2c_pnx->base);
ret = -ENODEV;
- goto out_drvdata;
+ goto out_clkget;
}
- if (!(alg_data->ioaddr =
- (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) {
+ alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ if (!alg_data->ioaddr) {
dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
ret = -ENOMEM;
goto out_release;
}
- i2c_pnx->set_clock_run(pdev);
+ ret = clk_enable(alg_data->clk);
+ if (ret)
+ goto out_unmap;
+
+ freq = clk_get_rate(alg_data->clk);
/*
* Clock Divisor High This value is the number of system clocks
@@ -620,44 +632,47 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
* the deglitching filter length.
*/
- tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ tmp = ((freq / 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;
+ goto out_clock;
}
init_completion(&alg_data->mif.complete);
- ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
- 0, pdev->name, i2c_pnx->adapter);
+ ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+ 0, pdev->name, alg_data);
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);
+ ret = i2c_add_numbered_adapter(&alg_data->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);
+ alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
return 0;
out_irq:
- free_irq(alg_data->irq, i2c_pnx->adapter);
+ free_irq(i2c_pnx->irq, alg_data);
out_clock:
- i2c_pnx->set_clock_stop(pdev);
+ clk_disable(alg_data->clk);
out_unmap:
- iounmap((void *)alg_data->ioaddr);
+ iounmap(alg_data->ioaddr);
out_release:
- release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+out_clkget:
+ clk_put(alg_data->clk);
out_drvdata:
+ kfree(alg_data);
+err_kzalloc:
platform_set_drvdata(pdev, NULL);
out:
return ret;
@@ -665,15 +680,16 @@ out:
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;
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+ struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
- free_irq(alg_data->irq, i2c_pnx->adapter);
- i2c_del_adapter(adap);
- i2c_pnx->set_clock_stop(pdev);
- iounmap((void *)alg_data->ioaddr);
- release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ free_irq(i2c_pnx->irq, alg_data);
+ i2c_del_adapter(&alg_data->adapter);
+ clk_disable(alg_data->clk);
+ iounmap(alg_data->ioaddr);
+ release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ clk_put(alg_data->clk);
+ kfree(alg_data);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 3c9d71f6018..b289ec99eeb 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
int rc = 0;
int read = (read_write == I2C_SMBUS_READ);
int addrdir = (addr << 1) | read;
+ int mode, subsize, len;
+ u32 subaddr;
+ u8 *buf;
u8 local[2];
- rc = pmac_i2c_open(bus, 0);
- if (rc)
- return rc;
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+ mode = pmac_i2c_mode_std;
+ subsize = 0;
+ subaddr = 0;
+ } else {
+ mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+ subsize = 1;
+ subaddr = command;
+ }
switch (size) {
case I2C_SMBUS_QUICK:
- rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+ buf = NULL;
+ len = 0;
break;
case I2C_SMBUS_BYTE:
- rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
- break;
case I2C_SMBUS_BYTE_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+ buf = &data->byte;
+ len = 1;
break;
case I2C_SMBUS_WORD_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
if (!read) {
local[0] = data->word & 0xff;
local[1] = (data->word >> 8) & 0xff;
}
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
- if (rc == 0 && read) {
- data->word = ((u16)local[1]) << 8;
- data->word |= local[0];
- }
+ buf = local;
+ len = 2;
break;
/* Note that these are broken vs. the expected smbus API where
@@ -105,28 +95,49 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
* a repeat start/addr phase (but not stop in between)
*/
case I2C_SMBUS_BLOCK_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
- data->block[0] + 1);
-
+ buf = data->block;
+ len = data->block[0] + 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command,
- &data->block[1], data->block[0]);
+ buf = &data->block[1];
+ len = data->block[0];
break;
default:
- rc = -EINVAL;
+ return -EINVAL;
+ }
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+ return rc;
+ }
+
+ rc = pmac_i2c_setmode(bus, mode);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ mode, rc);
+ goto bail;
}
+
+ rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+ if (rc) {
+ if (rc == -ENXIO)
+ dev_dbg(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, "
+ "err %d\n", addrdir >> 1, size, rc);
+ else
+ dev_err(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, "
+ "err %d\n", addrdir >> 1, size, rc);
+ goto bail;
+ }
+
+ if (size == I2C_SMBUS_WORD_DATA && read) {
+ data->word = ((u16)local[1]) << 8;
+ data->word |= local[0];
+ }
+
bail:
pmac_i2c_close(bus);
return rc;
@@ -146,20 +157,39 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
+ if (num != 1) {
+ dev_err(&adap->dev,
+ "Multi-message I2C transactions not supported\n");
+ return -EOPNOTSUPP;
+ }
+
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
addrdir = (msgs->addr << 1) | read;
- if (msgs->flags & I2C_M_REV_DIR_ADDR)
- addrdir ^= 1;
rc = pmac_i2c_open(bus, 0);
- if (rc)
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
return rc;
+ }
rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ pmac_i2c_mode_std, rc);
goto bail;
+ }
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ if (rc < 0) {
+ if (rc == -ENXIO)
+ dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to",
+ addrdir >> 1, rc);
+ else
+ dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to",
+ addrdir >> 1, rc);
+ }
bail:
pmac_i2c_close(bus);
return rc < 0 ? rc : 1;
@@ -183,19 +213,16 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
static int __devexit i2c_powermac_remove(struct platform_device *dev)
{
struct i2c_adapter *adapter = platform_get_drvdata(dev);
- struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
int rc;
rc = i2c_del_adapter(adapter);
- pmac_i2c_detach_adapter(bus, adapter);
- i2c_set_adapdata(adapter, NULL);
/* We aren't that prepared to deal with this... */
if (rc)
printk(KERN_WARNING
"i2c-powermac.c: Failed to remove bus %s !\n",
adapter->name);
platform_set_drvdata(dev, NULL);
- kfree(adapter);
+ memset(adapter, 0, sizeof(*adapter));
return 0;
}
@@ -206,12 +233,12 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
struct pmac_i2c_bus *bus = dev->dev.platform_data;
struct device_node *parent = NULL;
struct i2c_adapter *adapter;
- char name[32];
const char *basename;
int rc;
if (bus == NULL)
return -EINVAL;
+ adapter = pmac_i2c_get_adapter(bus);
/* Ok, now we need to make up a name for the interface that will
* match what we used to do in the past, that is basically the
@@ -237,29 +264,22 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
default:
return -EINVAL;
}
- snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+ snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+ pmac_i2c_get_channel(bus));
of_node_put(parent);
- adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
- if (adapter == NULL) {
- printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
- return -ENOMEM;
- }
platform_set_drvdata(dev, adapter);
- strcpy(adapter->name, name);
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
- pmac_i2c_attach_adapter(bus, adapter);
rc = i2c_add_adapter(adapter);
if (rc) {
printk(KERN_ERR "i2c-powermac: Adapter %s registration "
- "failed\n", name);
- i2c_set_adapdata(adapter, NULL);
- pmac_i2c_detach_adapter(bus, adapter);
+ "failed\n", adapter->name);
+ memset(adapter, 0, sizeof(*adapter));
}
- printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+ printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
if (!strncmp(basename, "uni-n", 5)) {
struct device_node *np;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 049555777f6..14d249f5ed3 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -12,7 +12,7 @@
*
* History:
* Apr 2002: Initial version [CS]
- * Jun 2002: Properly seperated algo/adap [FB]
+ * Jun 2002: Properly separated algo/adap [FB]
* Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
* Jan 2003: added limited signal handling [Kai-Uwe Bloem]
* Sep 2004: Major rework to ensure efficient bus handling [RMK]
@@ -33,6 +33,7 @@
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -1155,7 +1156,7 @@ static int i2c_pxa_resume_noirq(struct device *dev)
return 0;
}
-static struct dev_pm_ops i2c_pxa_dev_pm_ops = {
+static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
.suspend_noirq = i2c_pxa_suspend_noirq,
.resume_noirq = i2c_pxa_resume_noirq,
};
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 96aafb91b69..d27072b2249 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -34,6 +34,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
+#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -967,7 +968,7 @@ static int s3c24xx_i2c_resume(struct device *dev)
return 0;
}
-static struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
+static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
.resume = s3c24xx_i2c_resume,
};
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index b4a55d407bf..388cbdc96db 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -33,6 +33,7 @@ struct acpi_smbus_cmi {
u8 cap_info:1;
u8 cap_read:1;
u8 cap_write:1;
+ struct smbus_methods_t *methods;
};
static const struct smbus_methods_t smbus_methods = {
@@ -41,10 +42,19 @@ static const struct smbus_methods_t smbus_methods = {
.mt_sbw = "_SBW",
};
+/* Some IBM BIOSes omit the leading underscore */
+static const struct smbus_methods_t ibm_smbus_methods = {
+ .mt_info = "SBI_",
+ .mt_sbr = "SBR_",
+ .mt_sbw = "SBW_",
+};
+
static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
- {"SMBUS01", 0},
+ {"SMBUS01", (kernel_ulong_t)&smbus_methods},
+ {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
{"", 0}
};
+MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
#define ACPI_SMBUS_STATUS_OK 0x00
#define ACPI_SMBUS_STATUS_FAIL 0x07
@@ -150,11 +160,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
if (read_write == I2C_SMBUS_READ) {
protocol |= ACPI_SMBUS_PRTCL_READ;
- method = smbus_methods.mt_sbr;
+ method = smbus_cmi->methods->mt_sbr;
input.count = 3;
} else {
protocol |= ACPI_SMBUS_PRTCL_WRITE;
- method = smbus_methods.mt_sbw;
+ method = smbus_cmi->methods->mt_sbw;
input.count = 5;
}
@@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
union acpi_object *obj;
acpi_status status;
- if (!strcmp(name, smbus_methods.mt_info)) {
+ if (!strcmp(name, smbus_cmi->methods->mt_info)) {
status = acpi_evaluate_object(smbus_cmi->handle,
- smbus_methods.mt_info,
+ smbus_cmi->methods->mt_info,
NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
- smbus_methods.mt_info, status));
+ smbus_cmi->methods->mt_info, status));
return -EIO;
}
@@ -319,9 +329,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
kfree(buffer.pointer);
smbus_cmi->cap_info = 1;
- } else if (!strcmp(name, smbus_methods.mt_sbr))
+ } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
smbus_cmi->cap_read = 1;
- else if (!strcmp(name, smbus_methods.mt_sbw))
+ else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
smbus_cmi->cap_write = 1;
else
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
@@ -349,6 +359,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
static int acpi_smbus_cmi_add(struct acpi_device *device)
{
struct acpi_smbus_cmi *smbus_cmi;
+ const struct acpi_device_id *id;
smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
if (!smbus_cmi)
@@ -362,8 +373,13 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
smbus_cmi->cap_read = 0;
smbus_cmi->cap_write = 0;
+ for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
+ if (!strcmp(id->id, acpi_device_hid(device)))
+ smbus_cmi->methods =
+ (struct smbus_methods_t *) id->driver_data;
+
acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
- acpi_smbus_cmi_query_methods, smbus_cmi, NULL);
+ acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
if (smbus_cmi->cap_info == 0)
goto err;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 86a9d4e8147..ffb405d7c6f 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -31,6 +31,7 @@
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/slab.h>
/* Transmit operation: */
/* */
@@ -647,7 +648,7 @@ static int sh_mobile_i2c_runtime_nop(struct device *dev)
return 0;
}
-static struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
+static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
.runtime_suspend = sh_mobile_i2c_runtime_nop,
.runtime_resume = sh_mobile_i2c_runtime_nop,
};
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
index 6407f47bda8..78b06107342 100644
--- a/drivers/i2c/busses/i2c-simtec.c
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 139f0c7f12a..55a71370c79 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -142,7 +142,7 @@ static void sis5595_write(u8 reg, u8 data)
outb(data, sis5595_base + SMB_DAT);
}
-static int sis5595_setup(struct pci_dev *SIS5595_dev)
+static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
{
u16 a;
u8 val;
@@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sis5595_ids[] __devinitdata = {
+static const struct pci_device_id sis5595_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 70ca41e90e5..2309c7f1bde 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -389,7 +389,7 @@ static u32 sis630_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static int sis630_setup(struct pci_dev *sis630_dev)
+static int __devinit sis630_setup(struct pci_dev *sis630_dev)
{
unsigned char b;
struct pci_dev *dummy = NULL;
@@ -468,7 +468,7 @@ static struct i2c_adapter sis630_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sis630_ids[] __devinitdata = {
+static const struct pci_device_id sis630_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
{ 0, }
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 1649963b00d..d43d8f8943d 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sis96x_ids[] = {
+static const struct pci_device_id sis96x_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
index d2728a28a8d..1f5b38be73b 100644
--- a/drivers/i2c/busses/i2c-stu300.c
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/slab.h>
/* the name of this kernel module */
#define NAME "stu300"
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 1b7b2af9403..0c770eabe85 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -35,6 +35,10 @@ module_param_array(chip_addr, ushort, NULL, S_IRUGO);
MODULE_PARM_DESC(chip_addr,
"Chip addresses (up to 10, between 0x03 and 0x77)");
+static unsigned long functionality = ~0UL;
+module_param(functionality, ulong, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(functionality, "Override functionality bitfield");
+
struct stub_chip {
u8 pointer;
u16 words[256]; /* Byte operations use the LSB as per SMBus
@@ -48,7 +52,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size, union i2c_smbus_data * data)
{
s32 ret;
- int i;
+ int i, len;
struct stub_chip *chip = NULL;
/* Search for the right chip */
@@ -118,6 +122,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
ret = 0;
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = data->block[0];
+ if (read_write == I2C_SMBUS_WRITE) {
+ for (i = 0; i < len; i++) {
+ chip->words[command + i] &= 0xff00;
+ chip->words[command + i] |= data->block[1 + i];
+ }
+ dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+ "wrote %d bytes at 0x%02x.\n",
+ addr, len, command);
+ } else {
+ for (i = 0; i < len; i++) {
+ data->block[1 + i] =
+ chip->words[command + i] & 0xff;
+ }
+ dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+ "read %d bytes at 0x%02x.\n",
+ addr, len, command);
+ }
+
+ ret = 0;
+ break;
+
default:
dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
ret = -EOPNOTSUPP;
@@ -129,8 +156,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
static u32 stub_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK) & functionality;
}
static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index b1c050ff311..d03b04002f0 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -13,6 +13,8 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -30,11 +32,13 @@
#define CMD_I2C_IO_BEGIN (1<<0)
#define CMD_I2C_IO_END (1<<1)
-/* i2c bit delay, default is 10us -> 100kHz */
-static int delay = 10;
-module_param(delay, int, 0);
-MODULE_PARM_DESC(delay, "bit delay in microseconds, "
- "e.g. 10 for 100kHz (default is 100kHz)");
+/* i2c bit delay, default is 10us -> 100kHz max
+ (in practice, due to additional delays in the i2c bitbanging
+ code this results in a i2c clock of about 50kHz) */
+static unsigned short delay = 10;
+module_param(delay, ushort, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds "
+ "(default is 10us for 100kHz max)");
static int usb_read(struct i2c_adapter *adapter, int cmd,
int value, int index, void *data, int len);
@@ -109,7 +113,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
static u32 usb_func(struct i2c_adapter *adapter)
{
- u32 func;
+ __le32 func;
/* get functionality from adapter */
if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
@@ -118,7 +122,7 @@ static u32 usb_func(struct i2c_adapter *adapter)
return 0;
}
- return func;
+ return le32_to_cpu(func);
}
/* This is the actual algorithm we define */
@@ -136,7 +140,7 @@ static const struct i2c_algorithm usb_algorithm = {
* Future Technology Devices International Ltd., later a pair was
* bought from EZPrototypes
*/
-static struct usb_device_id i2c_tiny_usb_table [] = {
+static const struct usb_device_id i2c_tiny_usb_table[] = {
{ USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
{ USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
{ } /* Terminating entry */
@@ -216,8 +220,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
"i2c-tiny-usb at bus %03d device %03d",
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
- if (usb_write(&dev->adapter, CMD_SET_DELAY,
- cpu_to_le16(delay), 0, NULL, 0) != 0) {
+ if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
dev_err(&dev->adapter.dev,
"failure setting delay to %dus\n", delay);
retval = -EIO;
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
index 70de8216346..5c473833d94 100644
--- a/drivers/i2c/busses/i2c-versatile.c
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -14,6 +14,7 @@
#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <asm/io.h>
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 8b24f192103..de78283bddb 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = {
};
-static struct pci_device_id vt586b_ids[] __devinitdata = {
+static const struct pci_device_id vt586b_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index e4b1543015a..d57292e5dae 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -165,10 +165,10 @@ static int vt596_transaction(u8 size)
do {
msleep(1);
temp = inb_p(SMBHSTSTS);
- } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
+ } while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
- if (timeout >= MAX_TIMEOUT) {
+ if (timeout == MAX_TIMEOUT) {
result = -ETIMEDOUT;
dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
}
@@ -444,7 +444,7 @@ release_region:
return error;
}
-static struct pci_device_id vt596_ids[] = {
+static const struct pci_device_id vt596_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
.driver_data = SMBBA1 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
deleted file mode 100644
index 7663d57833a..00000000000
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
- Ralph Metzler <rjkm@thp.uni-koeln.de>, and
- Mark D. Studebaker <mdsxyz123@yahoo.com>
-
- Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
- Simon Vogl
-
- 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.
-*/
-
-/* This interfaces to the I2C bus of the Voodoo3 to gain access to
- the BT869 and possibly other I2C devices. */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-/* the only registers we use */
-#define REG 0x78
-#define REG2 0x70
-
-/* bit locations in the register */
-#define DDC_ENAB 0x00040000
-#define DDC_SCL_OUT 0x00080000
-#define DDC_SDA_OUT 0x00100000
-#define DDC_SCL_IN 0x00200000
-#define DDC_SDA_IN 0x00400000
-#define I2C_ENAB 0x00800000
-#define I2C_SCL_OUT 0x01000000
-#define I2C_SDA_OUT 0x02000000
-#define I2C_SCL_IN 0x04000000
-#define I2C_SDA_IN 0x08000000
-
-/* initialization states */
-#define INIT2 0x2
-#define INIT3 0x4
-
-/* delays */
-#define CYCLE_DELAY 10
-#define TIMEOUT (HZ / 2)
-
-
-static void __iomem *ioaddr;
-
-/* The voo GPIO registers don't have individual masks for each bit
- so we always have to read before writing. */
-
-static void bit_vooi2c_setscl(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= I2C_SCL_OUT;
- else
- r &= ~I2C_SCL_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static void bit_vooi2c_setsda(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= I2C_SDA_OUT;
- else
- r &= ~I2C_SDA_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-/* The GPIO pins are open drain, so the pins always remain outputs.
- We rely on the i2c-algo-bit routines to set the pins high before
- reading the input from other chips. */
-
-static int bit_vooi2c_getscl(void *data)
-{
- return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
-}
-
-static int bit_vooi2c_getsda(void *data)
-{
- return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
-}
-
-static void bit_vooddc_setscl(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= DDC_SCL_OUT;
- else
- r &= ~DDC_SCL_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static void bit_vooddc_setsda(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= DDC_SDA_OUT;
- else
- r &= ~DDC_SDA_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static int bit_vooddc_getscl(void *data)
-{
- return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
-}
-
-static int bit_vooddc_getsda(void *data)
-{
- return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
-}
-
-static int config_v3(struct pci_dev *dev)
-{
- unsigned long cadr;
-
- /* map Voodoo3 memory */
- cadr = dev->resource[0].start;
- cadr &= PCI_BASE_ADDRESS_MEM_MASK;
- ioaddr = ioremap_nocache(cadr, 0x1000);
- if (ioaddr) {
- writel(0x8160, ioaddr + REG2);
- writel(0xcffc0020, ioaddr + REG);
- dev_info(&dev->dev, "Using Banshee/Voodoo3 I2C device at %p\n", ioaddr);
- return 0;
- }
- return -ENODEV;
-}
-
-static struct i2c_algo_bit_data voo_i2c_bit_data = {
- .setsda = bit_vooi2c_setsda,
- .setscl = bit_vooi2c_setscl,
- .getsda = bit_vooi2c_getsda,
- .getscl = bit_vooi2c_getscl,
- .udelay = CYCLE_DELAY,
- .timeout = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_i2c_adapter = {
- .owner = THIS_MODULE,
- .name = "I2C Voodoo3/Banshee adapter",
- .algo_data = &voo_i2c_bit_data,
-};
-
-static struct i2c_algo_bit_data voo_ddc_bit_data = {
- .setsda = bit_vooddc_setsda,
- .setscl = bit_vooddc_setscl,
- .getsda = bit_vooddc_getsda,
- .getscl = bit_vooddc_getscl,
- .udelay = CYCLE_DELAY,
- .timeout = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_ddc_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_DDC,
- .name = "DDC Voodoo3/Banshee adapter",
- .algo_data = &voo_ddc_bit_data,
-};
-
-static struct pci_device_id voodoo3_ids[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3) },
- { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE) },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE (pci, voodoo3_ids);
-
-static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- int retval;
-
- retval = config_v3(dev);
- if (retval)
- return retval;
-
- /* set up the sysfs linkage to our parent device */
- voodoo3_i2c_adapter.dev.parent = &dev->dev;
- voodoo3_ddc_adapter.dev.parent = &dev->dev;
-
- retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
- if (retval)
- return retval;
- retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
- if (retval)
- i2c_del_adapter(&voodoo3_i2c_adapter);
- return retval;
-}
-
-static void __devexit voodoo3_remove(struct pci_dev *dev)
-{
- i2c_del_adapter(&voodoo3_i2c_adapter);
- i2c_del_adapter(&voodoo3_ddc_adapter);
- iounmap(ioaddr);
-}
-
-static struct pci_driver voodoo3_driver = {
- .name = "voodoo3_smbus",
- .id_table = voodoo3_ids,
- .probe = voodoo3_probe,
- .remove = __devexit_p(voodoo3_remove),
-};
-
-static int __init i2c_voodoo3_init(void)
-{
- return pci_register_driver(&voodoo3_driver);
-}
-
-static void __exit i2c_voodoo3_exit(void)
-{
- pci_unregister_driver(&voodoo3_driver);
-}
-
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
- "Philip Edelbrock <phil@netroedge.com>, "
- "Ralph Metzler <rjkm@thp.uni-koeln.de>, "
- "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_voodoo3_init);
-module_exit(i2c_voodoo3_exit);
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
new file mode 100644
index 00000000000..a9c419e075a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -0,0 +1,826 @@
+/*
+ * i2c-xiic.c
+ * Copyright (c) 2002-2007 Xilinx Inc.
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *
+ * This code was implemented by Mocean Laboratories AB when porting linux
+ * to the automotive development board Russellville. The copyright holder
+ * as seen in the header is Intel corporation.
+ * Mocean Laboratories forked off the GNU/Linux platform work into a
+ * separate company called Pelagicore AB, which commited the code to the
+ * kernel.
+ */
+
+/* Supports:
+ * Xilinx IIC
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-xiic.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define DRIVER_NAME "xiic-i2c"
+
+enum xilinx_i2c_state {
+ STATE_DONE,
+ STATE_ERROR,
+ STATE_START
+};
+
+/**
+ * struct xiic_i2c - Internal representation of the XIIC I2C bus
+ * @base: Memory base of the HW registers
+ * @wait: Wait queue for callers
+ * @adap: Kernel adapter representation
+ * @tx_msg: Messages from above to be sent
+ * @lock: Mutual exclusion
+ * @tx_pos: Current pos in TX message
+ * @nmsgs: Number of messages in tx_msg
+ * @state: See STATE_
+ * @rx_msg: Current RX message
+ * @rx_pos: Position within current RX message
+ */
+struct xiic_i2c {
+ void __iomem *base;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *tx_msg;
+ spinlock_t lock;
+ unsigned int tx_pos;
+ unsigned int nmsgs;
+ enum xilinx_i2c_state state;
+ struct i2c_msg *rx_msg;
+ int rx_pos;
+};
+
+
+#define XIIC_MSB_OFFSET 0
+#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
+
+/*
+ * Register offsets in bytes from RegisterBase. Three is added to the
+ * base offset to access LSB (IBM style) of the word
+ */
+#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */
+#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */
+#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */
+#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */
+#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */
+#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
+#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
+#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */
+#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
+#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */
+
+/* Control Register masks */
+#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
+#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
+#define XIIC_CR_MSMS_MASK 0x04 /* Master starts Txing=1 */
+#define XIIC_CR_DIR_IS_TX_MASK 0x08 /* Dir of tx. Txing=1 */
+#define XIIC_CR_NO_ACK_MASK 0x10 /* Tx Ack. NO ack = 1 */
+#define XIIC_CR_REPEATED_START_MASK 0x20 /* Repeated start = 1 */
+#define XIIC_CR_GENERAL_CALL_MASK 0x40 /* Gen Call enabled = 1 */
+
+/* Status Register masks */
+#define XIIC_SR_GEN_CALL_MASK 0x01 /* 1=a mstr issued a GC */
+#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x02 /* 1=when addr as slave */
+#define XIIC_SR_BUS_BUSY_MASK 0x04 /* 1 = bus is busy */
+#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x08 /* 1=Dir: mstr <-- slave */
+#define XIIC_SR_TX_FIFO_FULL_MASK 0x10 /* 1 = Tx FIFO full */
+#define XIIC_SR_RX_FIFO_FULL_MASK 0x20 /* 1 = Rx FIFO full */
+#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x40 /* 1 = Rx FIFO empty */
+#define XIIC_SR_TX_FIFO_EMPTY_MASK 0x80 /* 1 = Tx FIFO empty */
+
+/* Interrupt Status Register masks Interrupt occurs when... */
+#define XIIC_INTR_ARB_LOST_MASK 0x01 /* 1 = arbitration lost */
+#define XIIC_INTR_TX_ERROR_MASK 0x02 /* 1=Tx error/msg complete */
+#define XIIC_INTR_TX_EMPTY_MASK 0x04 /* 1 = Tx FIFO/reg empty */
+#define XIIC_INTR_RX_FULL_MASK 0x08 /* 1=Rx FIFO/reg=OCY level */
+#define XIIC_INTR_BNB_MASK 0x10 /* 1 = Bus not busy */
+#define XIIC_INTR_AAS_MASK 0x20 /* 1 = when addr as slave */
+#define XIIC_INTR_NAAS_MASK 0x40 /* 1 = not addr as slave */
+#define XIIC_INTR_TX_HALF_MASK 0x80 /* 1 = TX FIFO half empty */
+
+/* The following constants specify the depth of the FIFOs */
+#define IIC_RX_FIFO_DEPTH 16 /* Rx fifo capacity */
+#define IIC_TX_FIFO_DEPTH 16 /* Tx fifo capacity */
+
+/* The following constants specify groups of interrupts that are typically
+ * enabled or disables at the same time
+ */
+#define XIIC_TX_INTERRUPTS \
+(XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)
+
+#define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS)
+
+/* The following constants are used with the following macros to specify the
+ * operation, a read or write operation.
+ */
+#define XIIC_READ_OPERATION 1
+#define XIIC_WRITE_OPERATION 0
+
+/*
+ * Tx Fifo upper bit masks.
+ */
+#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
+#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
+
+/*
+ * The following constants define the register offsets for the Interrupt
+ * registers. There are some holes in the memory map for reserved addresses
+ * to allow other registers to be added and still match the memory map of the
+ * interrupt controller registers
+ */
+#define XIIC_DGIER_OFFSET 0x1C /* Device Global Interrupt Enable Register */
+#define XIIC_IISR_OFFSET 0x20 /* Interrupt Status Register */
+#define XIIC_IIER_OFFSET 0x28 /* Interrupt Enable Register */
+#define XIIC_RESETR_OFFSET 0x40 /* Reset Register */
+
+#define XIIC_RESET_MASK 0xAUL
+
+/*
+ * The following constant is used for the device global interrupt enable
+ * register, to enable all interrupts for the device, this is the only bit
+ * in the register
+ */
+#define XIIC_GINTR_ENABLE_MASK 0x80000000UL
+
+#define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
+#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
+
+static void xiic_start_xfer(struct xiic_i2c *i2c);
+static void __xiic_start_xfer(struct xiic_i2c *i2c);
+
+static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg);
+}
+
+static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg);
+}
+
+static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
+{
+ iowrite16(value, i2c->base + reg);
+}
+
+static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
+{
+ iowrite32(value, i2c->base + reg);
+}
+
+static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
+{
+ return ioread32(i2c->base + reg);
+}
+
+static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask);
+}
+
+static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask);
+}
+
+static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask);
+}
+
+static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
+{
+ xiic_irq_clr(i2c, mask);
+ xiic_irq_en(i2c, mask);
+}
+
+static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
+{
+ u8 sr;
+ for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+ !(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
+ sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
+ xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+}
+
+static void xiic_reinit(struct xiic_i2c *i2c)
+{
+ xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+ /* Set receive Fifo depth to maximum (zero based). */
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1);
+
+ /* Reset Tx Fifo. */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK);
+
+ /* Enable IIC Device, remove Tx Fifo reset & disable general call. */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
+
+ /* make sure RX fifo is empty */
+ xiic_clear_rx_fifo(i2c);
+
+ /* Enable interrupts */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK);
+}
+
+static void xiic_deinit(struct xiic_i2c *i2c)
+{
+ u8 cr;
+
+ xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+ /* Disable IIC Device. */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
+}
+
+static void xiic_read_rx(struct xiic_i2c *i2c)
+{
+ u8 bytes_in_fifo;
+ int i;
+
+ bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, bytes in fifo: %d, msg: %d"
+ ", SR: 0x%x, CR: 0x%x\n",
+ __func__, bytes_in_fifo, xiic_rx_space(i2c),
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+ if (bytes_in_fifo > xiic_rx_space(i2c))
+ bytes_in_fifo = xiic_rx_space(i2c);
+
+ for (i = 0; i < bytes_in_fifo; i++)
+ i2c->rx_msg->buf[i2c->rx_pos++] =
+ xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET,
+ (xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ?
+ IIC_RX_FIFO_DEPTH - 1 : xiic_rx_space(i2c) - 1);
+}
+
+static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
+{
+ /* return the actual space left in the FIFO */
+ return IIC_TX_FIFO_DEPTH - xiic_getreg8(i2c, XIIC_TFO_REG_OFFSET) - 1;
+}
+
+static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
+{
+ u8 fifo_space = xiic_tx_fifo_space(i2c);
+ int len = xiic_tx_space(i2c);
+
+ len = (len > fifo_space) ? fifo_space : len;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n",
+ __func__, len, fifo_space);
+
+ while (len--) {
+ u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
+ if ((xiic_tx_space(i2c) == 0) && (i2c->nmsgs == 1)) {
+ /* last message in transfer -> STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+ dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ } else
+ xiic_setreg8(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+}
+
+static void xiic_wakeup(struct xiic_i2c *i2c, int code)
+{
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ i2c->state = code;
+ wake_up(&i2c->wait);
+}
+
+static void xiic_process(struct xiic_i2c *i2c)
+{
+ u32 pend, isr, ier;
+ u32 clr = 0;
+
+ /* Get the interrupt Status from the IPIF. There is no clearing of
+ * interrupts in the IPIF. Interrupts must be cleared at the source.
+ * To find which interrupts are pending; AND interrupts pending with
+ * interrupts masked.
+ */
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ pend = isr & ier;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, IER: 0x%x, ISR: 0x%x, "
+ "pend: 0x%x, SR: 0x%x, msg: %p, nmsgs: %d\n",
+ __func__, ier, isr, pend, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ i2c->tx_msg, i2c->nmsgs);
+
+ /* Do not processes a devices interrupts if the device has no
+ * interrupts pending
+ */
+ if (!pend)
+ return;
+
+ /* Service requesting interrupt */
+ if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
+ ((pend & XIIC_INTR_TX_ERROR_MASK) &&
+ !(pend & XIIC_INTR_RX_FULL_MASK))) {
+ /* bus arbritration lost, or...
+ * Transmit error _OR_ RX completed
+ * if this happens when RX_FULL is not set
+ * this is probably a TX error
+ */
+
+ dev_dbg(i2c->adap.dev.parent, "%s error\n", __func__);
+
+ /* dynamic mode seem to suffer from problems if we just flushes
+ * fifos and the next message is a TX with len 0 (only addr)
+ * reset the IP instead of just flush fifos
+ */
+ xiic_reinit(i2c);
+
+ if (i2c->tx_msg)
+ xiic_wakeup(i2c, STATE_ERROR);
+
+ } else if (pend & XIIC_INTR_RX_FULL_MASK) {
+ /* Receive register/FIFO is full */
+
+ clr = XIIC_INTR_RX_FULL_MASK;
+ if (!i2c->rx_msg) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s unexpexted RX IRQ\n", __func__);
+ xiic_clear_rx_fifo(i2c);
+ goto out;
+ }
+
+ xiic_read_rx(i2c);
+ if (xiic_rx_space(i2c) == 0) {
+ /* this is the last part of the message */
+ i2c->rx_msg = NULL;
+
+ /* also clear TX error if there (RX complete) */
+ clr |= (isr & XIIC_INTR_TX_ERROR_MASK);
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s end of message, nmsgs: %d\n",
+ __func__, i2c->nmsgs);
+
+ /* send next message if this wasn't the last,
+ * otherwise the transfer will be finialise when
+ * receiving the bus not busy interrupt
+ */
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ dev_dbg(i2c->adap.dev.parent,
+ "%s will start next...\n", __func__);
+
+ __xiic_start_xfer(i2c);
+ }
+ }
+ } else if (pend & XIIC_INTR_BNB_MASK) {
+ /* IIC bus has transitioned to not busy */
+ clr = XIIC_INTR_BNB_MASK;
+
+ /* The bus is not busy, disable BusNotBusy interrupt */
+ xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+
+ if (!i2c->tx_msg)
+ goto out;
+
+ if ((i2c->nmsgs == 1) && !i2c->rx_msg &&
+ xiic_tx_space(i2c) == 0)
+ xiic_wakeup(i2c, STATE_DONE);
+ else
+ xiic_wakeup(i2c, STATE_ERROR);
+
+ } else if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
+ /* Transmit register/FIFO is empty or ½ empty */
+
+ clr = pend &
+ (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK);
+
+ if (!i2c->tx_msg) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s unexpexted TX IRQ\n", __func__);
+ goto out;
+ }
+
+ xiic_fill_tx_fifo(i2c);
+
+ /* current message sent and there is space in the fifo */
+ if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s end of message sent, nmsgs: %d\n",
+ __func__, i2c->nmsgs);
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ __xiic_start_xfer(i2c);
+ } else {
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s Got TX IRQ but no more to do...\n",
+ __func__);
+ }
+ } else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
+ /* current frame is sent and is last,
+ * make sure to disable tx half
+ */
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+ } else {
+ /* got IRQ which is not acked */
+ dev_err(i2c->adap.dev.parent, "%s Got unexpected IRQ\n",
+ __func__);
+ clr = pend;
+ }
+out:
+ dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
+
+ xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
+}
+
+static int xiic_bus_busy(struct xiic_i2c *i2c)
+{
+ u8 sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+
+ return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0;
+}
+
+static int xiic_busy(struct xiic_i2c *i2c)
+{
+ int tries = 3;
+ int err;
+
+ if (i2c->tx_msg)
+ return -EBUSY;
+
+ /* for instance if previous transfer was terminated due to TX error
+ * it might be that the bus is on it's way to become available
+ * give it at most 3 ms to wake
+ */
+ err = xiic_bus_busy(i2c);
+ while (err && tries--) {
+ mdelay(1);
+ err = xiic_bus_busy(i2c);
+ }
+
+ return err;
+}
+
+static void xiic_start_recv(struct xiic_i2c *i2c)
+{
+ u8 rx_watermark;
+ struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
+
+ /* Clear and enable Rx full interrupt. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+
+ /* we want to get all but last byte, because the TX_ERROR IRQ is used
+ * to inidicate error ACK on the address, and negative ack on the last
+ * received byte, so to not mix them receive all but last.
+ * In the case where there is only one byte to receive
+ * we can check if ERROR and RX full is set at the same time
+ */
+ rx_watermark = msg->len;
+ if (rx_watermark > IIC_RX_FIFO_DEPTH)
+ rx_watermark = IIC_RX_FIFO_DEPTH;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
+
+ if (!(msg->flags & I2C_M_NOSTART))
+ /* write the address */
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ (msg->addr << 1) | XIIC_READ_OPERATION |
+ XIIC_TX_DYN_START_MASK);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+ if (i2c->nmsgs == 1)
+ /* very last, enable bus not busy as well */
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+ /* the message is tx:ed */
+ i2c->tx_pos = msg->len;
+}
+
+static void xiic_start_send(struct xiic_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->tx_msg;
+
+ xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK);
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d, "
+ "ISR: 0x%x, CR: 0x%x\n",
+ __func__, msg, msg->len, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ /* write the address */
+ u16 data = ((msg->addr << 1) & 0xfe) | XIIC_WRITE_OPERATION |
+ XIIC_TX_DYN_START_MASK;
+ if ((i2c->nmsgs == 1) && msg->len == 0)
+ /* no data and last message -> add STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+
+ xiic_fill_tx_fifo(i2c);
+
+ /* Clear any pending Tx empty, Tx Error and then enable them. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK);
+}
+
+static irqreturn_t xiic_isr(int irq, void *dev_id)
+{
+ struct xiic_i2c *i2c = dev_id;
+
+ spin_lock(&i2c->lock);
+ /* disable interrupts globally */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0);
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__);
+
+ xiic_process(i2c);
+
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+ spin_unlock(&i2c->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void __xiic_start_xfer(struct xiic_i2c *i2c)
+{
+ int first = 1;
+ int fifo_space = xiic_tx_fifo_space(i2c);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
+ __func__, i2c->tx_msg, fifo_space);
+
+ if (!i2c->tx_msg)
+ return;
+
+ i2c->rx_pos = 0;
+ i2c->tx_pos = 0;
+ i2c->state = STATE_START;
+ while ((fifo_space >= 2) && (first || (i2c->nmsgs > 1))) {
+ if (!first) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ i2c->tx_pos = 0;
+ } else
+ first = 0;
+
+ if (i2c->tx_msg->flags & I2C_M_RD) {
+ /* we dont date putting several reads in the FIFO */
+ xiic_start_recv(i2c);
+ return;
+ } else {
+ xiic_start_send(i2c);
+ if (xiic_tx_space(i2c) != 0) {
+ /* the message could not be completely sent */
+ break;
+ }
+ }
+
+ fifo_space = xiic_tx_fifo_space(i2c);
+ }
+
+ /* there are more messages or the current one could not be completely
+ * put into the FIFO, also enable the half empty interrupt
+ */
+ if (i2c->nmsgs > 1 || xiic_tx_space(i2c))
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_HALF_MASK);
+
+}
+
+static void xiic_start_xfer(struct xiic_i2c *i2c)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ xiic_reinit(i2c);
+ /* disable interrupts globally */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ __xiic_start_xfer(i2c);
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+}
+
+static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct xiic_i2c *i2c = i2c_get_adapdata(adap);
+ int err;
+
+ dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__,
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET));
+
+ err = xiic_busy(i2c);
+ if (err)
+ return err;
+
+ i2c->tx_msg = msgs;
+ i2c->nmsgs = num;
+
+ xiic_start_xfer(i2c);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ))
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+ else {
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ return -ETIMEDOUT;
+ }
+}
+
+static u32 xiic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm xiic_algorithm = {
+ .master_xfer = xiic_xfer,
+ .functionality = xiic_func,
+};
+
+static struct i2c_adapter xiic_adapter = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &xiic_algorithm,
+};
+
+
+static int __devinit xiic_i2c_probe(struct platform_device *pdev)
+{
+ struct xiic_i2c *i2c;
+ struct xiic_i2c_platform_data *pdata;
+ struct resource *res;
+ int ret, irq;
+ u8 i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto resource_missing;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ goto resource_missing;
+
+ pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
+ if (!pdata)
+ return -EINVAL;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+
+ i2c->base = ioremap(res->start, resource_size(res));
+ if (!i2c->base) {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = xiic_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+
+ xiic_reinit(i2c);
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+ ret = request_irq(irq, xiic_isr, 0, pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ goto add_adapter_failed;
+ }
+
+ /* add in known devices to the bus */
+ for (i = 0; i < pdata->num_devices; i++)
+ i2c_new_device(&i2c->adap, pdata->devices + i);
+
+ return 0;
+
+add_adapter_failed:
+ free_irq(irq, i2c);
+request_irq_failed:
+ xiic_deinit(i2c);
+ iounmap(i2c->base);
+map_failed:
+ release_mem_region(res->start, resource_size(res));
+request_mem_failed:
+ kfree(i2c);
+
+ return ret;
+resource_missing:
+ dev_err(&pdev->dev, "IRQ or Memory resource is missing\n");
+ return -ENOENT;
+}
+
+static int __devexit xiic_i2c_remove(struct platform_device* pdev)
+{
+ struct xiic_i2c *i2c = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+
+ xiic_deinit(i2c);
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_irq(platform_get_irq(pdev, 0), i2c);
+
+ iounmap(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(i2c);
+
+ return 0;
+}
+
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:"DRIVER_NAME);
+
+static struct platform_driver xiic_i2c_driver = {
+ .probe = xiic_i2c_probe,
+ .remove = __devexit_p(xiic_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init xiic_i2c_init(void)
+{
+ return platform_driver_register(&xiic_i2c_driver);
+}
+
+static void __exit xiic_i2c_exit(void)
+{
+ platform_driver_unregister(&xiic_i2c_driver);
+}
+
+module_init(xiic_i2c_init);
+module_exit(xiic_i2c_exit);
+
+MODULE_AUTHOR("info@mocean-labs.com");
+MODULE_DESCRIPTION("Xilinx I2C bus driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index cf994bd01d9..684395b6f3e 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
#include <asm/io.h>
#include <linux/scx200.h>
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
deleted file mode 100644
index f9618f4d4e4..00000000000
--- a/drivers/i2c/chips/Kconfig
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Miscellaneous I2C chip drivers configuration
-#
-# *** DEPRECATED! Do not add new entries! See Makefile ***
-#
-
-menu "Miscellaneous I2C Chip support"
-
-config DS1682
- tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
- depends on EXPERIMENTAL
- help
- If you say yes here you get support for Dallas Semiconductor
- DS1682 Total Elapsed Time Recorder.
-
- This driver can also be built as a module. If so, the module
- will be called ds1682.
-
-config SENSORS_TSL2550
- tristate "Taos TSL2550 ambient light sensor"
- depends on EXPERIMENTAL
- help
- If you say yes here you get support for the Taos TSL2550
- ambient light sensor.
-
- This driver can also be built as a module. If so, the module
- will be called tsl2550.
-
-endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
deleted file mode 100644
index 749cf360629..00000000000
--- a/drivers/i2c/chips/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Makefile for miscellaneous I2C chip drivers.
-#
-# Do not add new drivers to this directory! It is DEPRECATED.
-#
-# Device drivers are better grouped according to the functionality they
-# implement rather than to the bus they are connected to. In particular:
-# * Hardware monitoring chip drivers go to drivers/hwmon
-# * RTC chip drivers go to drivers/rtc
-# * I/O expander drivers go to drivers/gpio
-#
-
-obj-$(CONFIG_DS1682) += ds1682.o
-obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
-
-ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
-
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
deleted file mode 100644
index f3ee4a1abb7..00000000000
--- a/drivers/i2c/chips/ds1682.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Dallas Semiconductor DS1682 Elapsed Time Recorder device driver
- *
- * Written by: Grant Likely <grant.likely@secretlab.ca>
- *
- * Copyright (C) 2007 Secret Lab Technologies 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.
- */
-
-/*
- * The DS1682 elapsed timer recorder is a simple device that implements
- * one elapsed time counter, one event counter, an alarm signal and 10
- * bytes of general purpose EEPROM.
- *
- * This driver provides access to the DS1682 counters and user data via
- * the sysfs. The following attributes are added to the device node:
- * elapsed_time (u32): Total elapsed event time in ms resolution
- * alarm_time (u32): When elapsed time exceeds the value in alarm_time,
- * then the alarm pin is asserted.
- * event_count (u16): number of times the event pin has gone low.
- * eeprom (u8[10]): general purpose EEPROM
- *
- * Counter registers and user data are both read/write unless the device
- * has been write protected. This driver does not support turning off write
- * protection. Once write protection is turned on, it is impossible to
- * turn it off again, so I have left the feature out of this driver to avoid
- * accidental enabling, but it is trivial to add write protect support.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/sysfs.h>
-#include <linux/ctype.h>
-#include <linux/hwmon-sysfs.h>
-
-/* Device registers */
-#define DS1682_REG_CONFIG 0x00
-#define DS1682_REG_ALARM 0x01
-#define DS1682_REG_ELAPSED 0x05
-#define DS1682_REG_EVT_CNTR 0x09
-#define DS1682_REG_EEPROM 0x0b
-#define DS1682_REG_RESET 0x1d
-#define DS1682_REG_WRITE_DISABLE 0x1e
-#define DS1682_REG_WRITE_MEM_DISABLE 0x1f
-
-#define DS1682_EEPROM_SIZE 10
-
-/*
- * Generic counter attributes
- */
-static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
- struct i2c_client *client = to_i2c_client(dev);
- __le32 val = 0;
- int rc;
-
- dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);
-
- /* Read the register */
- rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,
- (u8 *) & val);
- if (rc < 0)
- return -EIO;
-
- /* Special case: the 32 bit regs are time values with 1/4s
- * resolution, scale them up to milliseconds */
- if (sattr->nr == 4)
- return sprintf(buf, "%llu\n",
- ((unsigned long long)le32_to_cpu(val)) * 250);
-
- /* Format the output string and return # of bytes */
- return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
-}
-
-static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
- struct i2c_client *client = to_i2c_client(dev);
- char *endp;
- u64 val;
- __le32 val_le;
- int rc;
-
- dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);
-
- /* Decode input */
- val = simple_strtoull(buf, &endp, 0);
- if (buf == endp) {
- dev_dbg(dev, "input string not a number\n");
- return -EINVAL;
- }
-
- /* Special case: the 32 bit regs are time values with 1/4s
- * resolution, scale input down to quarter-seconds */
- if (sattr->nr == 4)
- do_div(val, 250);
-
- /* write out the value */
- val_le = cpu_to_le32(val);
- rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,
- (u8 *) & val_le);
- if (rc < 0) {
- dev_err(dev, "register write failed; reg=0x%x, size=%i\n",
- sattr->index, sattr->nr);
- return -EIO;
- }
-
- return count;
-}
-
-/*
- * Simple register attributes
- */
-static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,
- ds1682_store, 4, DS1682_REG_ELAPSED);
-static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,
- ds1682_store, 4, DS1682_REG_ALARM);
-static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,
- ds1682_store, 2, DS1682_REG_EVT_CNTR);
-
-static const struct attribute_group ds1682_group = {
- .attrs = (struct attribute *[]) {
- &sensor_dev_attr_elapsed_time.dev_attr.attr,
- &sensor_dev_attr_alarm_time.dev_attr.attr,
- &sensor_dev_attr_event_count.dev_attr.attr,
- NULL,
- },
-};
-
-/*
- * User data attribute
- */
-static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
-{
- struct i2c_client *client = kobj_to_i2c_client(kobj);
- int rc;
-
- dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",
- buf, off, count);
-
- if (off >= DS1682_EEPROM_SIZE)
- return 0;
-
- if (off + count > DS1682_EEPROM_SIZE)
- count = DS1682_EEPROM_SIZE - off;
-
- rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,
- count, buf);
- if (rc < 0)
- return -EIO;
-
- return count;
-}
-
-static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
-{
- struct i2c_client *client = kobj_to_i2c_client(kobj);
-
- dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",
- buf, off, count);
-
- if (off >= DS1682_EEPROM_SIZE)
- return -ENOSPC;
-
- if (off + count > DS1682_EEPROM_SIZE)
- count = DS1682_EEPROM_SIZE - off;
-
- /* Write out to the device */
- if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,
- count, buf) < 0)
- return -EIO;
-
- return count;
-}
-
-static struct bin_attribute ds1682_eeprom_attr = {
- .attr = {
- .name = "eeprom",
- .mode = S_IRUGO | S_IWUSR,
- },
- .size = DS1682_EEPROM_SIZE,
- .read = ds1682_eeprom_read,
- .write = ds1682_eeprom_write,
-};
-
-/*
- * Called when a ds1682 device is matched with this driver
- */
-static int ds1682_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int rc;
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_I2C_BLOCK)) {
- dev_err(&client->dev, "i2c bus does not support the ds1682\n");
- rc = -ENODEV;
- goto exit;
- }
-
- rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);
- if (rc)
- goto exit;
-
- rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
- if (rc)
- goto exit_bin_attr;
-
- return 0;
-
- exit_bin_attr:
- sysfs_remove_group(&client->dev.kobj, &ds1682_group);
- exit:
- return rc;
-}
-
-static int ds1682_remove(struct i2c_client *client)
-{
- sysfs_remove_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
- sysfs_remove_group(&client->dev.kobj, &ds1682_group);
- return 0;
-}
-
-static const struct i2c_device_id ds1682_id[] = {
- { "ds1682", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ds1682_id);
-
-static struct i2c_driver ds1682_driver = {
- .driver = {
- .name = "ds1682",
- },
- .probe = ds1682_probe,
- .remove = ds1682_remove,
- .id_table = ds1682_id,
-};
-
-static int __init ds1682_init(void)
-{
- return i2c_add_driver(&ds1682_driver);
-}
-
-static void __exit ds1682_exit(void)
-{
- i2c_del_driver(&ds1682_driver);
-}
-
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
-MODULE_LICENSE("GPL");
-
-module_init(ds1682_init);
-module_exit(ds1682_exit);
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
deleted file mode 100644
index a0702f36a72..00000000000
--- a/drivers/i2c/chips/tsl2550.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * tsl2550.c - Linux kernel modules for ambient light sensor
- *
- * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
- * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
- *
- * 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/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-#define TSL2550_DRV_NAME "tsl2550"
-#define DRIVER_VERSION "1.2"
-
-/*
- * Defines
- */
-
-#define TSL2550_POWER_DOWN 0x00
-#define TSL2550_POWER_UP 0x03
-#define TSL2550_STANDARD_RANGE 0x18
-#define TSL2550_EXTENDED_RANGE 0x1d
-#define TSL2550_READ_ADC0 0x43
-#define TSL2550_READ_ADC1 0x83
-
-/*
- * Structs
- */
-
-struct tsl2550_data {
- struct i2c_client *client;
- struct mutex update_lock;
-
- unsigned int power_state : 1;
- unsigned int operating_mode : 1;
-};
-
-/*
- * Global data
- */
-
-static const u8 TSL2550_MODE_RANGE[2] = {
- TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
-};
-
-/*
- * Management functions
- */
-
-static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
-{
- struct tsl2550_data *data = i2c_get_clientdata(client);
-
- int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
-
- data->operating_mode = mode;
-
- return ret;
-}
-
-static int tsl2550_set_power_state(struct i2c_client *client, int state)
-{
- struct tsl2550_data *data = i2c_get_clientdata(client);
- int ret;
-
- if (state == 0)
- ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
- else {
- ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
-
- /* On power up we should reset operating mode also... */
- tsl2550_set_operating_mode(client, data->operating_mode);
- }
-
- data->power_state = state;
-
- return ret;
-}
-
-static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
-{
- int ret;
-
- ret = i2c_smbus_read_byte_data(client, cmd);
- if (ret < 0)
- return ret;
- if (!(ret & 0x80))
- return -EAGAIN;
- return ret & 0x7f; /* remove the "valid" bit */
-}
-
-/*
- * LUX calculation
- */
-
-#define TSL2550_MAX_LUX 1846
-
-static const u8 ratio_lut[] = {
- 100, 100, 100, 100, 100, 100, 100, 100,
- 100, 100, 100, 100, 100, 100, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 98, 98, 98, 98, 98,
- 98, 98, 97, 97, 97, 97, 97, 96,
- 96, 96, 96, 95, 95, 95, 94, 94,
- 93, 93, 93, 92, 92, 91, 91, 90,
- 89, 89, 88, 87, 87, 86, 85, 84,
- 83, 82, 81, 80, 79, 78, 77, 75,
- 74, 73, 71, 69, 68, 66, 64, 62,
- 60, 58, 56, 54, 52, 49, 47, 44,
- 42, 41, 40, 40, 39, 39, 38, 38,
- 37, 37, 37, 36, 36, 36, 35, 35,
- 35, 35, 34, 34, 34, 34, 33, 33,
- 33, 33, 32, 32, 32, 32, 32, 31,
- 31, 31, 31, 31, 30, 30, 30, 30,
- 30,
-};
-
-static const u16 count_lut[] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 18, 20, 22, 24, 26, 28, 30,
- 32, 34, 36, 38, 40, 42, 44, 46,
- 49, 53, 57, 61, 65, 69, 73, 77,
- 81, 85, 89, 93, 97, 101, 105, 109,
- 115, 123, 131, 139, 147, 155, 163, 171,
- 179, 187, 195, 203, 211, 219, 227, 235,
- 247, 263, 279, 295, 311, 327, 343, 359,
- 375, 391, 407, 423, 439, 455, 471, 487,
- 511, 543, 575, 607, 639, 671, 703, 735,
- 767, 799, 831, 863, 895, 927, 959, 991,
- 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
- 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
- 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
- 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
-};
-
-/*
- * This function is described into Taos TSL2550 Designer's Notebook
- * pages 2, 3.
- */
-static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
-{
- unsigned int lux;
-
- /* Look up count from channel values */
- u16 c0 = count_lut[ch0];
- u16 c1 = count_lut[ch1];
-
- /*
- * Calculate ratio.
- * Note: the "128" is a scaling factor
- */
- u8 r = 128;
-
- /* Avoid division by 0 and count 1 cannot be greater than count 0 */
- if (c1 <= c0)
- if (c0) {
- r = c1 * 128 / c0;
-
- /* Calculate LUX */
- lux = ((c0 - c1) * ratio_lut[r]) / 256;
- } else
- lux = 0;
- else
- return -EAGAIN;
-
- /* LUX range check */
- return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
-}
-
-/*
- * SysFS support
- */
-
-static ssize_t tsl2550_show_power_state(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
-
- return sprintf(buf, "%u\n", data->power_state);
-}
-
-static ssize_t tsl2550_store_power_state(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct tsl2550_data *data = i2c_get_clientdata(client);
- unsigned long val = simple_strtoul(buf, NULL, 10);
- int ret;
-
- if (val < 0 || val > 1)
- return -EINVAL;
-
- mutex_lock(&data->update_lock);
- ret = tsl2550_set_power_state(client, val);
- mutex_unlock(&data->update_lock);
-
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
- tsl2550_show_power_state, tsl2550_store_power_state);
-
-static ssize_t tsl2550_show_operating_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
-
- return sprintf(buf, "%u\n", data->operating_mode);
-}
-
-static ssize_t tsl2550_store_operating_mode(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct tsl2550_data *data = i2c_get_clientdata(client);
- unsigned long val = simple_strtoul(buf, NULL, 10);
- int ret;
-
- if (val < 0 || val > 1)
- return -EINVAL;
-
- if (data->power_state == 0)
- return -EBUSY;
-
- mutex_lock(&data->update_lock);
- ret = tsl2550_set_operating_mode(client, val);
- mutex_unlock(&data->update_lock);
-
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
- tsl2550_show_operating_mode, tsl2550_store_operating_mode);
-
-static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
-{
- struct tsl2550_data *data = i2c_get_clientdata(client);
- u8 ch0, ch1;
- int ret;
-
- ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
- if (ret < 0)
- return ret;
- ch0 = ret;
-
- ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
- if (ret < 0)
- return ret;
- ch1 = ret;
-
- /* Do the job */
- ret = tsl2550_calculate_lux(ch0, ch1);
- if (ret < 0)
- return ret;
- if (data->operating_mode == 1)
- ret *= 5;
-
- return sprintf(buf, "%d\n", ret);
-}
-
-static ssize_t tsl2550_show_lux1_input(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct tsl2550_data *data = i2c_get_clientdata(client);
- int ret;
-
- /* No LUX data if not operational */
- if (!data->power_state)
- return -EBUSY;
-
- mutex_lock(&data->update_lock);
- ret = __tsl2550_show_lux(client, buf);
- mutex_unlock(&data->update_lock);
-
- return ret;
-}
-
-static DEVICE_ATTR(lux1_input, S_IRUGO,
- tsl2550_show_lux1_input, NULL);
-
-static struct attribute *tsl2550_attributes[] = {
- &dev_attr_power_state.attr,
- &dev_attr_operating_mode.attr,
- &dev_attr_lux1_input.attr,
- NULL
-};
-
-static const struct attribute_group tsl2550_attr_group = {
- .attrs = tsl2550_attributes,
-};
-
-/*
- * Initialization function
- */
-
-static int tsl2550_init_client(struct i2c_client *client)
-{
- struct tsl2550_data *data = i2c_get_clientdata(client);
- int err;
-
- /*
- * Probe the chip. To do so we try to power up the device and then to
- * read back the 0x03 code
- */
- err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
- if (err < 0)
- return err;
- if (err != TSL2550_POWER_UP)
- return -ENODEV;
- data->power_state = 1;
-
- /* Set the default operating mode */
- err = i2c_smbus_write_byte(client,
- TSL2550_MODE_RANGE[data->operating_mode]);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-/*
- * I2C init/probing/exit functions
- */
-
-static struct i2c_driver tsl2550_driver;
-static int __devinit tsl2550_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct tsl2550_data *data;
- int *opmode, err = 0;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
- | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
- err = -EIO;
- goto exit;
- }
-
- data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
- data->client = client;
- i2c_set_clientdata(client, data);
-
- /* Check platform data */
- opmode = client->dev.platform_data;
- if (opmode) {
- if (*opmode < 0 || *opmode > 1) {
- dev_err(&client->dev, "invalid operating_mode (%d)\n",
- *opmode);
- err = -EINVAL;
- goto exit_kfree;
- }
- data->operating_mode = *opmode;
- } else
- data->operating_mode = 0; /* default mode is standard */
- dev_info(&client->dev, "%s operating mode\n",
- data->operating_mode ? "extended" : "standard");
-
- mutex_init(&data->update_lock);
-
- /* Initialize the TSL2550 chip */
- err = tsl2550_init_client(client);
- if (err)
- goto exit_kfree;
-
- /* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
- if (err)
- goto exit_kfree;
-
- dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
-
- return 0;
-
-exit_kfree:
- kfree(data);
-exit:
- return err;
-}
-
-static int __devexit tsl2550_remove(struct i2c_client *client)
-{
- sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
-
- /* Power down the device */
- tsl2550_set_power_state(client, 0);
-
- kfree(i2c_get_clientdata(client));
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
-{
- return tsl2550_set_power_state(client, 0);
-}
-
-static int tsl2550_resume(struct i2c_client *client)
-{
- return tsl2550_set_power_state(client, 1);
-}
-
-#else
-
-#define tsl2550_suspend NULL
-#define tsl2550_resume NULL
-
-#endif /* CONFIG_PM */
-
-static const struct i2c_device_id tsl2550_id[] = {
- { "tsl2550", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tsl2550_id);
-
-static struct i2c_driver tsl2550_driver = {
- .driver = {
- .name = TSL2550_DRV_NAME,
- .owner = THIS_MODULE,
- },
- .suspend = tsl2550_suspend,
- .resume = tsl2550_resume,
- .probe = tsl2550_probe,
- .remove = __devexit_p(tsl2550_remove),
- .id_table = tsl2550_id,
-};
-
-static int __init tsl2550_init(void)
-{
- return i2c_add_driver(&tsl2550_driver);
-}
-
-static void __exit tsl2550_exit(void)
-{
- i2c_del_driver(&tsl2550_driver);
-}
-
-MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
-MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
-
-module_init(tsl2550_init);
-module_exit(tsl2550_exit);
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index a26a34a0664..7e6a63b5716 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
+#include <linux/slab.h>
#include <linux/rwsem.h>
#include "i2c-core.h"
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 29650435514..3202a86f420 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -34,6 +34,7 @@
#include <linux/hardirq.h>
#include <linux/irqflags.h>
#include <linux/rwsem.h>
+#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include "i2c-core.h"
@@ -155,6 +156,81 @@ static void i2c_device_shutdown(struct device *dev)
driver->shutdown(client);
}
+#ifdef CONFIG_SUSPEND
+static int i2c_device_pm_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm;
+
+ if (!dev->driver)
+ return 0;
+ pm = dev->driver->pm;
+ if (!pm || !pm->suspend)
+ return 0;
+ return pm->suspend(dev);
+}
+
+static int i2c_device_pm_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm;
+
+ if (!dev->driver)
+ return 0;
+ pm = dev->driver->pm;
+ if (!pm || !pm->resume)
+ return 0;
+ return pm->resume(dev);
+}
+#else
+#define i2c_device_pm_suspend NULL
+#define i2c_device_pm_resume NULL
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int i2c_device_runtime_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm;
+
+ if (!dev->driver)
+ return 0;
+ pm = dev->driver->pm;
+ if (!pm || !pm->runtime_suspend)
+ return 0;
+ return pm->runtime_suspend(dev);
+}
+
+static int i2c_device_runtime_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm;
+
+ if (!dev->driver)
+ return 0;
+ pm = dev->driver->pm;
+ if (!pm || !pm->runtime_resume)
+ return 0;
+ return pm->runtime_resume(dev);
+}
+
+static int i2c_device_runtime_idle(struct device *dev)
+{
+ const struct dev_pm_ops *pm = NULL;
+ int ret;
+
+ if (dev->driver)
+ pm = dev->driver->pm;
+ if (pm && pm->runtime_idle) {
+ ret = pm->runtime_idle(dev);
+ if (ret)
+ return ret;
+ }
+
+ return pm_runtime_suspend(dev);
+}
+#else
+#define i2c_device_runtime_suspend NULL
+#define i2c_device_runtime_resume NULL
+#define i2c_device_runtime_idle NULL
+#endif
+
static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
{
struct i2c_client *client = i2c_verify_client(dev);
@@ -219,6 +295,14 @@ static const struct attribute_group *i2c_dev_attr_groups[] = {
NULL
};
+static const struct dev_pm_ops i2c_device_pm_ops = {
+ .suspend = i2c_device_pm_suspend,
+ .resume = i2c_device_pm_resume,
+ .runtime_suspend = i2c_device_runtime_suspend,
+ .runtime_resume = i2c_device_runtime_resume,
+ .runtime_idle = i2c_device_runtime_idle,
+};
+
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
@@ -227,6 +311,7 @@ struct bus_type i2c_bus_type = {
.shutdown = i2c_device_shutdown,
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
+ .pm = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
@@ -558,11 +643,9 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
up_read(&__i2c_board_lock);
}
-static int i2c_do_add_adapter(struct device_driver *d, void *data)
+static int i2c_do_add_adapter(struct i2c_driver *driver,
+ struct i2c_adapter *adap)
{
- struct i2c_driver *driver = to_i2c_driver(d);
- struct i2c_adapter *adap = data;
-
/* Detect supported devices on that bus, and instantiate them */
i2c_detect(adap, driver);
@@ -574,6 +657,11 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data)
return 0;
}
+static int __process_new_adapter(struct device_driver *d, void *data)
+{
+ return i2c_do_add_adapter(to_i2c_driver(d), data);
+}
+
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0, dummy;
@@ -584,7 +672,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list;
}
- mutex_init(&adap->bus_lock);
+ rt_mutex_init(&adap->bus_lock);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
@@ -614,7 +702,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
/* Notify drivers */
mutex_lock(&core_lock);
dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
- i2c_do_add_adapter);
+ __process_new_adapter);
mutex_unlock(&core_lock);
return 0;
@@ -715,10 +803,9 @@ retry:
}
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
-static int i2c_do_del_adapter(struct device_driver *d, void *data)
+static int i2c_do_del_adapter(struct i2c_driver *driver,
+ struct i2c_adapter *adapter)
{
- struct i2c_driver *driver = to_i2c_driver(d);
- struct i2c_adapter *adapter = data;
struct i2c_client *client, *_n;
int res;
@@ -750,6 +837,11 @@ static int __unregister_client(struct device *dev, void *dummy)
return 0;
}
+static int __process_removed_adapter(struct device_driver *d, void *data)
+{
+ return i2c_do_del_adapter(to_i2c_driver(d), data);
+}
+
/**
* i2c_del_adapter - unregister I2C adapter
* @adap: the adapter being unregistered
@@ -777,7 +869,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
/* Tell drivers about this removal */
mutex_lock(&core_lock);
res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
- i2c_do_del_adapter);
+ __process_removed_adapter);
mutex_unlock(&core_lock);
if (res)
return res;
@@ -801,6 +893,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
adap->dev.parent);
#endif
+ /* device name is gone after device_unregister */
+ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+
/* clean up the sysfs representation */
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
@@ -813,8 +908,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
- dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
-
/* Clear the device structure in case this adapter is ever going to be
added again */
memset(&adap->dev, 0, sizeof(adap->dev));
@@ -826,22 +919,11 @@ EXPORT_SYMBOL(i2c_del_adapter);
/* ------------------------------------------------------------------------- */
-static int __attach_adapter(struct device *dev, void *data)
+static int __process_new_driver(struct device *dev, void *data)
{
- struct i2c_adapter *adapter;
- struct i2c_driver *driver = data;
-
if (dev->type != &i2c_adapter_type)
return 0;
- adapter = to_i2c_adapter(dev);
-
- i2c_detect(adapter, driver);
-
- /* Legacy drivers scan i2c busses directly */
- if (driver->attach_adapter)
- driver->attach_adapter(adapter);
-
- return 0;
+ return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}
/*
@@ -873,40 +955,18 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
mutex_lock(&core_lock);
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
+ bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
mutex_unlock(&core_lock);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
-static int __detach_adapter(struct device *dev, void *data)
+static int __process_removed_driver(struct device *dev, void *data)
{
- struct i2c_adapter *adapter;
- struct i2c_driver *driver = data;
- struct i2c_client *client, *_n;
-
if (dev->type != &i2c_adapter_type)
return 0;
- adapter = to_i2c_adapter(dev);
-
- /* Remove the devices we created ourselves as the result of hardware
- * probing (using a driver's detect method) */
- list_for_each_entry_safe(client, _n, &driver->clients, detected) {
- dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
- client->name, client->addr);
- list_del(&client->detected);
- i2c_unregister_device(client);
- }
-
- if (driver->detach_adapter) {
- if (driver->detach_adapter(adapter))
- dev_err(&adapter->dev,
- "detach_adapter failed for driver [%s]\n",
- driver->driver.name);
- }
-
- return 0;
+ return i2c_do_del_adapter(data, to_i2c_adapter(dev));
}
/**
@@ -917,7 +977,7 @@ static int __detach_adapter(struct device *dev, void *data)
void i2c_del_driver(struct i2c_driver *driver)
{
mutex_lock(&core_lock);
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
+ bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver);
mutex_unlock(&core_lock);
driver_unregister(&driver->driver);
@@ -1092,12 +1152,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif
if (in_atomic() || irqs_disabled()) {
- ret = mutex_trylock(&adap->bus_lock);
+ ret = rt_mutex_trylock(&adap->bus_lock);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
- mutex_lock_nested(&adap->bus_lock, adap->level);
+ rt_mutex_lock(&adap->bus_lock);
}
/* Retry automatically on arbitration loss */
@@ -1109,7 +1169,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
- mutex_unlock(&adap->bus_lock);
+ rt_mutex_unlock(&adap->bus_lock);
return ret;
} else {
@@ -1123,7 +1183,7 @@ EXPORT_SYMBOL(i2c_transfer);
* i2c_master_send - issue a single I2C message in master transmit mode
* @client: Handle to slave device
* @buf: Data that will be written to the slave
- * @count: How many bytes to write
+ * @count: How many bytes to write, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes written.
*/
@@ -1150,7 +1210,7 @@ EXPORT_SYMBOL(i2c_master_send);
* i2c_master_recv - issue a single I2C message in master receive mode
* @client: Handle to slave device
* @buf: Where to store data read from slave
- * @count: How many bytes to read
+ * @count: How many bytes to read, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes read.
*/
@@ -1180,7 +1240,7 @@ EXPORT_SYMBOL(i2c_master_recv);
* ----------------------------------------------------
*/
-static int i2c_detect_address(struct i2c_client *temp_client, int kind,
+static int i2c_detect_address(struct i2c_client *temp_client,
struct i2c_driver *driver)
{
struct i2c_board_info info;
@@ -1199,22 +1259,18 @@ static int i2c_detect_address(struct i2c_client *temp_client, int kind,
if (i2c_check_addr(adapter, addr))
return 0;
- /* Make sure there is something at this address, unless forced */
- if (kind < 0) {
- if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
- I2C_SMBUS_QUICK, NULL) < 0)
- return 0;
+ /* Make sure there is something at this address */
+ if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0)
+ return 0;
- /* prevent 24RF08 corruption */
- if ((addr & ~0x0f) == 0x50)
- i2c_smbus_xfer(adapter, addr, 0, 0, 0,
- I2C_SMBUS_QUICK, NULL);
- }
+ /* Prevent 24RF08 corruption */
+ if ((addr & ~0x0f) == 0x50)
+ i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL);
/* Finally call the custom detection function */
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = addr;
- err = driver->detect(temp_client, kind, &info);
+ err = driver->detect(temp_client, &info);
if (err) {
/* -ENODEV is returned if the detection fails. We catch it
here as this isn't an error. */
@@ -1244,13 +1300,13 @@ static int i2c_detect_address(struct i2c_client *temp_client, int kind,
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
- const struct i2c_client_address_data *address_data;
+ const unsigned short *address_list;
struct i2c_client *temp_client;
int i, err = 0;
int adap_id = i2c_adapter_id(adapter);
- address_data = driver->address_data;
- if (!driver->detect || !address_data)
+ address_list = driver->address_list;
+ if (!driver->detect || !address_list)
return 0;
/* Set up a temporary client to help detect callback */
@@ -1259,40 +1315,13 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
return -ENOMEM;
temp_client->adapter = adapter;
- /* Force entries are done first, and are not affected by ignore
- entries */
- if (address_data->forces) {
- const unsigned short * const *forces = address_data->forces;
- int kind;
-
- for (kind = 0; forces[kind]; kind++) {
- for (i = 0; forces[kind][i] != I2C_CLIENT_END;
- i += 2) {
- if (forces[kind][i] == adap_id
- || forces[kind][i] == ANY_I2C_BUS) {
- dev_dbg(&adapter->dev, "found force "
- "parameter for adapter %d, "
- "addr 0x%02x, kind %d\n",
- adap_id, forces[kind][i + 1],
- kind);
- temp_client->addr = forces[kind][i + 1];
- err = i2c_detect_address(temp_client,
- kind, driver);
- if (err)
- goto exit_free;
- }
- }
- }
- }
-
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
goto exit_free;
/* Stop here if we can't use SMBUS_QUICK */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
- if (address_data->probe[0] == I2C_CLIENT_END
- && address_data->normal_i2c[0] == I2C_CLIENT_END)
+ if (address_list[0] == I2C_CLIENT_END)
goto exit_free;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
@@ -1301,48 +1330,11 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
goto exit_free;
}
- /* Probe entries are done second, and are not affected by ignore
- entries either */
- for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
- if (address_data->probe[i] == adap_id
- || address_data->probe[i] == ANY_I2C_BUS) {
- dev_dbg(&adapter->dev, "found probe parameter for "
- "adapter %d, addr 0x%02x\n", adap_id,
- address_data->probe[i + 1]);
- temp_client->addr = address_data->probe[i + 1];
- err = i2c_detect_address(temp_client, -1, driver);
- if (err)
- goto exit_free;
- }
- }
-
- /* Normal entries are done last, unless shadowed by an ignore entry */
- for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
- int j, ignore;
-
- ignore = 0;
- for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
- j += 2) {
- if ((address_data->ignore[j] == adap_id ||
- address_data->ignore[j] == ANY_I2C_BUS)
- && address_data->ignore[j + 1]
- == address_data->normal_i2c[i]) {
- dev_dbg(&adapter->dev, "found ignore "
- "parameter for adapter %d, "
- "addr 0x%02x\n", adap_id,
- address_data->ignore[j + 1]);
- ignore = 1;
- break;
- }
- }
- if (ignore)
- continue;
-
+ for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
- "addr 0x%02x\n", adap_id,
- address_data->normal_i2c[i]);
- temp_client->addr = address_data->normal_i2c[i];
- err = i2c_detect_address(temp_client, -1, driver);
+ "addr 0x%02x\n", adap_id, address_list[i]);
+ temp_client->addr = address_list[i];
+ err = i2c_detect_address(temp_client, driver);
if (err)
goto exit_free;
}
@@ -1913,7 +1905,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
if (adapter->algo->smbus_xfer) {
- mutex_lock(&adapter->bus_lock);
+ rt_mutex_lock(&adapter->bus_lock);
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
@@ -1927,7 +1919,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout))
break;
}
- mutex_unlock(&adapter->bus_lock);
+ rt_mutex_unlock(&adapter->bus_lock);
} else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command, protocol, data);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 7e13d2df9af..f4110aa4960 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -34,7 +34,6 @@
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
-#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
@@ -445,20 +444,14 @@ static int i2cdev_open(struct inode *inode, struct file *file)
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
- int ret = 0;
- lock_kernel();
i2c_dev = i2c_dev_get_by_minor(minor);
- if (!i2c_dev) {
- ret = -ENODEV;
- goto out;
- }
+ if (!i2c_dev)
+ return -ENODEV;
adap = i2c_get_adapter(i2c_dev->adap->nr);
- if (!adap) {
- ret = -ENODEV;
- goto out;
- }
+ if (!adap)
+ return -ENODEV;
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
@@ -470,8 +463,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
@@ -479,9 +471,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
client->adapter = adap;
file->private_data = client;
-out:
- unlock_kernel();
- return ret;
+ return 0;
}
static int i2cdev_release(struct inode *inode, struct file *file)
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
new file mode 100644
index 00000000000..a24e0bfe920
--- /dev/null
+++ b/drivers/i2c/i2c-smbus.c
@@ -0,0 +1,263 @@
+/*
+ * i2c-smbus.c - SMBus extensions to the I2C protocol
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/slab.h>
+
+struct i2c_smbus_alert {
+ unsigned int alert_edge_triggered:1;
+ int irq;
+ struct work_struct alert;
+ struct i2c_client *ara; /* Alert response address */
+};
+
+struct alert_data {
+ unsigned short addr;
+ u8 flag:1;
+};
+
+/* If this is the alerting device, notify its driver */
+static int smbus_do_alert(struct device *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct alert_data *data = addrp;
+
+ if (!client || client->addr != data->addr)
+ return 0;
+ if (client->flags & I2C_CLIENT_TEN)
+ return 0;
+
+ /*
+ * Drivers should either disable alerts, or provide at least
+ * a minimal handler. Lock so client->driver won't change.
+ */
+ device_lock(dev);
+ if (client->driver) {
+ if (client->driver->alert)
+ client->driver->alert(client, data->flag);
+ else
+ dev_warn(&client->dev, "no driver alert()!\n");
+ } else
+ dev_dbg(&client->dev, "alert with no driver\n");
+ device_unlock(dev);
+
+ /* Stop iterating after we find the device */
+ return -EBUSY;
+}
+
+/*
+ * The alert IRQ handler needs to hand work off to a task which can issue
+ * SMBus calls, because those sleeping calls can't be made in IRQ context.
+ */
+static void smbus_alert(struct work_struct *work)
+{
+ struct i2c_smbus_alert *alert;
+ struct i2c_client *ara;
+ unsigned short prev_addr = 0; /* Not a valid address */
+
+ alert = container_of(work, struct i2c_smbus_alert, alert);
+ ara = alert->ara;
+
+ for (;;) {
+ s32 status;
+ struct alert_data data;
+
+ /*
+ * Devices with pending alerts reply in address order, low
+ * to high, because of slave transmit arbitration. After
+ * responding, an SMBus device stops asserting SMBALERT#.
+ *
+ * Note that SMBus 2.0 reserves 10-bit addresess for future
+ * use. We neither handle them, nor try to use PEC here.
+ */
+ status = i2c_smbus_read_byte(ara);
+ if (status < 0)
+ break;
+
+ data.flag = status & 1;
+ data.addr = status >> 1;
+
+ if (data.addr == prev_addr) {
+ dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
+ "0x%02x, skipping\n", data.addr);
+ break;
+ }
+ dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
+ data.addr, data.flag);
+
+ /* Notify driver for the device which issued the alert */
+ device_for_each_child(&ara->adapter->dev, &data,
+ smbus_do_alert);
+ prev_addr = data.addr;
+ }
+
+ /* We handled all alerts; re-enable level-triggered IRQs */
+ if (!alert->alert_edge_triggered)
+ enable_irq(alert->irq);
+}
+
+static irqreturn_t smbalert_irq(int irq, void *d)
+{
+ struct i2c_smbus_alert *alert = d;
+
+ /* Disable level-triggered IRQs until we handle them */
+ if (!alert->alert_edge_triggered)
+ disable_irq_nosync(irq);
+
+ schedule_work(&alert->alert);
+ return IRQ_HANDLED;
+}
+
+/* Setup SMBALERT# infrastructure */
+static int smbalert_probe(struct i2c_client *ara,
+ const struct i2c_device_id *id)
+{
+ struct i2c_smbus_alert_setup *setup = ara->dev.platform_data;
+ struct i2c_smbus_alert *alert;
+ struct i2c_adapter *adapter = ara->adapter;
+ int res;
+
+ alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL);
+ if (!alert)
+ return -ENOMEM;
+
+ alert->alert_edge_triggered = setup->alert_edge_triggered;
+ alert->irq = setup->irq;
+ INIT_WORK(&alert->alert, smbus_alert);
+ alert->ara = ara;
+
+ if (setup->irq > 0) {
+ res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
+ 0, "smbus_alert", alert);
+ if (res) {
+ kfree(alert);
+ return res;
+ }
+ }
+
+ i2c_set_clientdata(ara, alert);
+ dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
+ setup->alert_edge_triggered ? "edge" : "level");
+
+ return 0;
+}
+
+/* IRQ resource is managed so it is freed automatically */
+static int smbalert_remove(struct i2c_client *ara)
+{
+ struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
+
+ cancel_work_sync(&alert->alert);
+
+ i2c_set_clientdata(ara, NULL);
+ kfree(alert);
+ return 0;
+}
+
+static const struct i2c_device_id smbalert_ids[] = {
+ { "smbus_alert", 0 },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, smbalert_ids);
+
+static struct i2c_driver smbalert_driver = {
+ .driver = {
+ .name = "smbus_alert",
+ },
+ .probe = smbalert_probe,
+ .remove = smbalert_remove,
+ .id_table = smbalert_ids,
+};
+
+/**
+ * i2c_setup_smbus_alert - Setup SMBus alert support
+ * @adapter: the target adapter
+ * @setup: setup data for the SMBus alert handler
+ * Context: can sleep
+ *
+ * Setup handling of the SMBus alert protocol on a given I2C bus segment.
+ *
+ * Handling can be done either through our IRQ handler, or by the
+ * adapter (from its handler, periodic polling, or whatever).
+ *
+ * NOTE that if we manage the IRQ, we *MUST* know if it's level or
+ * edge triggered in order to hand it to the workqueue correctly.
+ * If triggering the alert seems to wedge the system, you probably
+ * should have said it's level triggered.
+ *
+ * This returns the ara client, which should be saved for later use with
+ * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
+ * to indicate an error.
+ */
+struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
+ struct i2c_smbus_alert_setup *setup)
+{
+ struct i2c_board_info ara_board_info = {
+ I2C_BOARD_INFO("smbus_alert", 0x0c),
+ .platform_data = setup,
+ };
+
+ return i2c_new_device(adapter, &ara_board_info);
+}
+EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
+
+/**
+ * i2c_handle_smbus_alert - Handle an SMBus alert
+ * @ara: the ARA client on the relevant adapter
+ * Context: can't sleep
+ *
+ * Helper function to be called from an I2C bus driver's interrupt
+ * handler. It will schedule the alert work, in turn calling the
+ * corresponding I2C device driver's alert function.
+ *
+ * It is assumed that ara is a valid i2c client previously returned by
+ * i2c_setup_smbus_alert().
+ */
+int i2c_handle_smbus_alert(struct i2c_client *ara)
+{
+ struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
+
+ return schedule_work(&alert->alert);
+}
+EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
+
+static int __init i2c_smbus_init(void)
+{
+ return i2c_add_driver(&smbalert_driver);
+}
+
+static void __exit i2c_smbus_exit(void)
+{
+ i2c_del_driver(&smbalert_driver);
+}
+
+module_init(i2c_smbus_init);
+module_exit(i2c_smbus_exit);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("SMBus protocol extensions support");
+MODULE_LICENSE("GPL");