aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorroot <root@artemis.panaceas.org>2015-12-25 04:40:36 +0000
committerroot <root@artemis.panaceas.org>2015-12-25 04:40:36 +0000
commit849369d6c66d3054688672f97d31fceb8e8230fb (patch)
tree6135abc790ca67dedbe07c39806591e70eda81ce /drivers/i2c
downloadlinux-3.0.35-kobo-849369d6c66d3054688672f97d31fceb8e8230fb.tar.gz
linux-3.0.35-kobo-849369d6c66d3054688672f97d31fceb8e8230fb.tar.bz2
linux-3.0.35-kobo-849369d6c66d3054688672f97d31fceb8e8230fb.zip
initial_commit
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/Kconfig113
-rw-r--r--drivers/i2c/Makefile13
-rw-r--r--drivers/i2c/algos/Kconfig17
-rw-r--r--drivers/i2c/algos/Makefile9
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c667
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c563
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c441
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.h76
-rw-r--r--drivers/i2c/busses/Kconfig880
-rw-r--r--drivers/i2c/busses/Makefile86
-rw-r--r--drivers/i2c/busses/i2c-acorn.c97
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c540
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c448
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c533
-rw-r--r--drivers/i2c/busses/i2c-amd756-s4882.c262
-rw-r--r--drivers/i2c/busses/i2c-amd756.c430
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c505
-rw-r--r--drivers/i2c/busses/i2c-at91.c327
-rw-r--r--drivers/i2c/busses/i2c-au1550.c497
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c797
-rw-r--r--drivers/i2c/busses/i2c-cpm.c745
-rw-r--r--drivers/i2c/busses/i2c-davinci.c830
-rw-r--r--drivers/i2c/busses/i2c-designware.c847
-rw-r--r--drivers/i2c/busses/i2c-diolan-u2c.c535
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c940
-rw-r--r--drivers/i2c/busses/i2c-elektor.c347
-rw-r--r--drivers/i2c/busses/i2c-gpio.c225
-rw-r--r--drivers/i2c/busses/i2c-highlander.c498
-rw-r--r--drivers/i2c/busses/i2c-hydra.c178
-rw-r--r--drivers/i2c/busses/i2c-i801.c946
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c829
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.h123
-rw-r--r--drivers/i2c/busses/i2c-imx.c700
-rw-r--r--drivers/i2c/busses/i2c-intel-mid.c1135
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c545
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h107
-rw-r--r--drivers/i2c/busses/i2c-isch.c325
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c168
-rw-r--r--drivers/i2c/busses/i2c-mpc.c734
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c631
-rw-r--r--drivers/i2c/busses/i2c-mxs.c419
-rw-r--r--drivers/i2c/busses/i2c-nforce2-s4985.c257
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c468
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c1064
-rw-r--r--drivers/i2c/busses/i2c-nuc900.c708
-rw-r--r--drivers/i2c/busses/i2c-ocores.c427
-rw-r--r--drivers/i2c/busses/i2c-octeon.c652
-rw-r--r--drivers/i2c/busses/i2c-omap.c1197
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c281
-rw-r--r--drivers/i2c/busses/i2c-parport.c306
-rw-r--r--drivers/i2c/busses/i2c-parport.h110
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c433
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c229
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c305
-rw-r--r--drivers/i2c/busses/i2c-piix4.c563
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c656
-rw-r--r--drivers/i2c/busses/i2c-pnx.c733
-rw-r--r--drivers/i2c/busses/i2c-powermac.c341
-rw-r--r--drivers/i2c/busses/i2c-puv3.c306
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c176
-rw-r--r--drivers/i2c/busses/i2c-pxa.c1258
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1040
-rw-r--r--drivers/i2c/busses/i2c-s6000.c407
-rw-r--r--drivers/i2c/busses/i2c-s6000.h79
-rw-r--r--drivers/i2c/busses/i2c-scmi.c445
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c577
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c739
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c198
-rw-r--r--drivers/i2c/busses/i2c-simtec.c189
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c434
-rw-r--r--drivers/i2c/busses/i2c-sis630.c533
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c344
-rw-r--r--drivers/i2c/busses/i2c-stu300.c1057
-rw-r--r--drivers/i2c/busses/i2c-stub.c222
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c331
-rw-r--r--drivers/i2c/busses/i2c-tegra.c735
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c284
-rw-r--r--drivers/i2c/busses/i2c-versatile.c160
-rw-r--r--drivers/i2c/busses/i2c-via.c180
-rw-r--r--drivers/i2c/busses/i2c-viapro.c508
-rw-r--r--drivers/i2c/busses/i2c-xiic.c826
-rw-r--r--drivers/i2c/busses/scx200_acb.c618
-rw-r--r--drivers/i2c/busses/scx200_i2c.c131
-rw-r--r--drivers/i2c/i2c-boardinfo.c92
-rw-r--r--drivers/i2c/i2c-core.c2124
-rw-r--r--drivers/i2c/i2c-core.h33
-rw-r--r--drivers/i2c/i2c-dev.c656
-rw-r--r--drivers/i2c/i2c-mux.c164
-rw-r--r--drivers/i2c/i2c-smbus.c262
-rw-r--r--drivers/i2c/muxes/Kconfig40
-rw-r--r--drivers/i2c/muxes/Makefile8
-rw-r--r--drivers/i2c/muxes/gpio-i2cmux.c184
-rw-r--r--drivers/i2c/muxes/pca9541.c411
-rw-r--r--drivers/i2c/muxes/pca954x.c302
94 files changed, 43891 insertions, 0 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
new file mode 100644
index 00000000..30f06e95
--- /dev/null
+++ b/drivers/i2c/Kconfig
@@ -0,0 +1,113 @@
+#
+# I2C subsystem configuration
+#
+
+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,
+ or System Management Bus is a subset of the I2C protocol. More
+ information is contained in the directory <file:Documentation/i2c/>,
+ especially in the file called "summary" there.
+
+ Both I2C and SMBus are supported here. You will need this for
+ hardware sensors support, and also for Video For Linux support.
+
+ If you want I2C support, you should say Y here and also to the
+ specific driver for your bus adapter(s) below.
+
+ This I2C support can also be built as a module. If so, the module
+ will be called i2c-core.
+
+if I2C
+
+config I2C_BOARDINFO
+ boolean
+ default y
+
+config I2C_COMPAT
+ boolean "Enable compatibility bits for old user-space"
+ default y
+ help
+ Say Y here if you intend to run lm-sensors 3.1.1 or older, or any
+ other user-space package which expects i2c adapters to be class
+ devices. If you don't know, say Y.
+
+config I2C_CHARDEV
+ tristate "I2C device interface"
+ help
+ Say Y here to use i2c-* device files, usually found in the /dev
+ directory on your system. They make it possible to have user-space
+ programs use the I2C bus. Information on how to do this is
+ contained in the file <file:Documentation/i2c/dev-interface>.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-dev.
+
+config I2C_MUX
+ tristate "I2C bus multiplexing support"
+ depends on EXPERIMENTAL
+ help
+ Say Y here if you want the I2C core to support the ability to
+ handle multiplexed I2C bus topologies, by presenting each
+ multiplexed segment as a I2C adapter.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-mux.
+
+source drivers/i2c/muxes/Kconfig
+
+config I2C_HELPER_AUTO
+ bool "Autoselect pertinent helper modules"
+ default y
+ help
+ Some I2C bus drivers require so-called "I2C algorithm" modules
+ to work. These are basically software-only abstractions of generic
+ I2C interfaces. This option will autoselect them so that you don't
+ have to care.
+
+ Unselect this only if you need to enable additional helper
+ modules, for example for use with external I2C bus drivers.
+
+ 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
+
+config I2C_DEBUG_CORE
+ bool "I2C Core debugging messages"
+ help
+ Say Y here if you want the I2C core 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.
+
+config I2C_DEBUG_ALGO
+ bool "I2C Algorithm debugging messages"
+ help
+ Say Y here if you want the I2C algorithm 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.
+
+config I2C_DEBUG_BUS
+ bool "I2C Bus debugging messages"
+ help
+ Say Y here if you want the I2C bus 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
new file mode 100644
index 00000000..beee6b2d
--- /dev/null
+++ b/drivers/i2c/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the i2c core.
+#
+
+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-$(CONFIG_I2C_MUX) += i2c-mux.o
+obj-y += algos/ busses/ muxes/
+
+ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
+CFLAGS_i2c-core.o := -Wno-deprecated-declarations
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
new file mode 100644
index 00000000..f1cfe7e5
--- /dev/null
+++ b/drivers/i2c/algos/Kconfig
@@ -0,0 +1,17 @@
+#
+# I2C algorithm drivers configuration
+#
+
+menu "I2C Algorithms"
+ visible if !I2C_HELPER_AUTO
+
+config I2C_ALGOBIT
+ tristate "I2C bit-banging interfaces"
+
+config I2C_ALGOPCF
+ tristate "I2C PCF 8584 interfaces"
+
+config I2C_ALGOPCA
+ tristate "I2C PCA 9564 interfaces"
+
+endmenu
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
new file mode 100644
index 00000000..215303f6
--- /dev/null
+++ b/drivers/i2c/algos/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the i2c algorithms
+#
+
+obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
+obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
+obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
+
+ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
new file mode 100644
index 00000000..f2ce8c36
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -0,0 +1,667 @@
+/* -------------------------------------------------------------------------
+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
+ * -------------------------------------------------------------------------
+ * Copyright (C) 1995-2000 Simon G. Vogl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ------------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+ <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+
+/* ----- global defines ----------------------------------------------- */
+
+#ifdef DEBUG
+#define bit_dbg(level, dev, format, args...) \
+ do { \
+ if (i2c_debug >= level) \
+ dev_dbg(dev, format, ##args); \
+ } while (0)
+#else
+#define bit_dbg(level, dev, format, args...) \
+ do {} while (0)
+#endif /* DEBUG */
+
+/* ----- global variables --------------------------------------------- */
+
+static int bit_test; /* see if the line-setting functions work */
+module_param(bit_test, bool, 0);
+MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+
+#ifdef DEBUG
+static int i2c_debug = 1;
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose");
+#endif
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define setsda(adap, val) adap->setsda(adap->data, val)
+#define setscl(adap, val) adap->setscl(adap->data, val)
+#define getsda(adap) adap->getsda(adap->data)
+#define getscl(adap) adap->getscl(adap->data)
+
+static inline void sdalo(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+}
+
+static inline void sdahi(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap, 1);
+ udelay((adap->udelay + 1) / 2);
+}
+
+static inline void scllo(struct i2c_algo_bit_data *adap)
+{
+ setscl(adap, 0);
+ udelay(adap->udelay / 2);
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static int sclhi(struct i2c_algo_bit_data *adap)
+{
+ unsigned long start;
+
+ setscl(adap, 1);
+
+ /* Not all adapters have scl sense line... */
+ if (!adap->getscl)
+ goto done;
+
+ start = jiffies;
+ while (!getscl(adap)) {
+ /* This hw knows how to read the clock line, so we wait
+ * until it actually gets high. This is safer as some
+ * chips may hold it low ("clock stretching") while they
+ * are processing data internally.
+ */
+ if (time_after(jiffies, start + adap->timeout)) {
+ /* Test one last time, as we may have been preempted
+ * between last check and timeout test.
+ */
+ if (getscl(adap))
+ break;
+ return -ETIMEDOUT;
+ }
+ cond_resched();
+ }
+#ifdef DEBUG
+ if (jiffies != start && i2c_debug >= 3)
+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+ "high\n", jiffies - start);
+#endif
+
+done:
+ udelay(adap->udelay);
+ return 0;
+}
+
+
+/* --- other auxiliary functions -------------------------------------- */
+static void i2c_start(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl, sda are high */
+ setsda(adap, 0);
+ udelay(adap->udelay);
+ scllo(adap);
+}
+
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl is low */
+ sdahi(adap);
+ sclhi(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
+ scllo(adap);
+}
+
+
+static void i2c_stop(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl is low */
+ sdalo(adap);
+ sclhi(adap);
+ setsda(adap, 1);
+ udelay(adap->udelay);
+}
+
+
+
+/* send a byte without start cond., look for arbitration,
+ check ackn. from slave */
+/* returns:
+ * 1 if the device acknowledged
+ * 0 if the device did not ack
+ * -ETIMEDOUT if an error occurred (while raising the scl line)
+ */
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+{
+ int i;
+ int sb;
+ int ack;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ for (i = 7; i >= 0; i--) {
+ sb = (c >> i) & 1;
+ setsda(adap, sb);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timed out */
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at bit #%d\n", (int)c, i);
+ return -ETIMEDOUT;
+ }
+ /* FIXME do arbitration here:
+ * if (sb && !getsda(adap)) -> ouch! Get out of here.
+ *
+ * Report a unique code, so higher level code can retry
+ * the whole (combined) message and *NOT* issue STOP.
+ */
+ scllo(adap);
+ }
+ sdahi(adap);
+ if (sclhi(adap) < 0) { /* timeout */
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at ack\n", (int)c);
+ return -ETIMEDOUT;
+ }
+
+ /* read ack: SDA should be pulled down by slave, or it may
+ * NAK (usually to report problems with the data we wrote).
+ */
+ ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+ ack ? "A" : "NA");
+
+ scllo(adap);
+ return ack;
+ /* assert: scl is low (sda undef) */
+}
+
+
+static int i2c_inb(struct i2c_adapter *i2c_adap)
+{
+ /* read byte via i2c port, without start/stop sequence */
+ /* acknowledge is sent in i2c_read. */
+ int i;
+ unsigned char indata = 0;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ sdahi(adap);
+ for (i = 0; i < 8; i++) {
+ if (sclhi(adap) < 0) { /* timeout */
+ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+ "#%d\n", 7 - i);
+ return -ETIMEDOUT;
+ }
+ indata *= 2;
+ if (getsda(adap))
+ indata |= 0x01;
+ setscl(adap, 0);
+ udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
+ }
+ /* assert: scl is low */
+ return indata;
+}
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_adapter *i2c_adap)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ const char *name = i2c_adap->name;
+ int scl, sda, ret;
+
+ if (adap->pre_xfer) {
+ ret = adap->pre_xfer(i2c_adap);
+ if (ret < 0)
+ return -ENODEV;
+ }
+
+ if (adap->getscl == NULL)
+ pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (!scl || !sda) {
+ printk(KERN_WARNING "%s: bus seems to be busy\n", name);
+ goto bailout;
+ }
+
+ sdalo(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (sda) {
+ printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+ goto bailout;
+ }
+ if (!scl) {
+ printk(KERN_WARNING "%s: SCL unexpected low "
+ "while pulling SDA low!\n", name);
+ goto bailout;
+ }
+
+ sdahi(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (!sda) {
+ printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+ goto bailout;
+ }
+ if (!scl) {
+ printk(KERN_WARNING "%s: SCL unexpected low "
+ "while pulling SDA high!\n", name);
+ goto bailout;
+ }
+
+ scllo(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 0 : getscl(adap);
+ if (scl) {
+ printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+ goto bailout;
+ }
+ if (!sda) {
+ printk(KERN_WARNING "%s: SDA unexpected low "
+ "while pulling SCL low!\n", name);
+ goto bailout;
+ }
+
+ sclhi(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (!scl) {
+ printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+ goto bailout;
+ }
+ if (!sda) {
+ printk(KERN_WARNING "%s: SDA unexpected low "
+ "while pulling SCL high!\n", name);
+ goto bailout;
+ }
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
+
+ pr_info("%s: Test OK\n", name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
+
+ return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+/* try_address tries to contact a chip for a number of
+ * times before it gives up.
+ * return values:
+ * 1 chip answered
+ * 0 chip did not answer
+ * -x transmission error
+ */
+static int try_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ int i, ret = 0;
+
+ for (i = 0; i <= retries; i++) {
+ ret = i2c_outb(i2c_adap, addr);
+ if (ret == 1 || i == retries)
+ break;
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+ i2c_stop(adap);
+ udelay(adap->udelay);
+ yield();
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ i2c_start(adap);
+ }
+ if (i && ret)
+ bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+ "0x%02x: %s\n", i + 1,
+ addr & 1 ? "read from" : "write to", addr >> 1,
+ ret == 1 ? "success" : "failed, timeout?");
+ return ret;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ const unsigned char *temp = msg->buf;
+ int count = msg->len;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ int retval;
+ int wrcount = 0;
+
+ while (count > 0) {
+ retval = i2c_outb(i2c_adap, *temp);
+
+ /* OK/ACK; or ignored NAK */
+ if ((retval > 0) || (nak_ok && (retval == 0))) {
+ count--;
+ temp++;
+ wrcount++;
+
+ /* A slave NAKing the master means the slave didn't like
+ * something about the data it saw. For example, maybe
+ * the SMBus PEC was wrong.
+ */
+ } else if (retval == 0) {
+ dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+ return -EIO;
+
+ /* Timeout; or (someday) lost arbitration
+ *
+ * FIXME Lost ARB implies retrying the transaction from
+ * the first message, after the "winning" master issues
+ * its STOP. As a rule, upper layer code has no reason
+ * to know or care about this ... it is *NOT* an error.
+ */
+ } else {
+ dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+ retval);
+ return retval;
+ }
+ }
+ return wrcount;
+}
+
+static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: sda is high */
+ if (is_ack) /* send ack */
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timeout */
+ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
+ return -ETIMEDOUT;
+ }
+ scllo(adap);
+ return 0;
+}
+
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ int inval;
+ int rdcount = 0; /* counts bytes read */
+ unsigned char *temp = msg->buf;
+ int count = msg->len;
+ const unsigned flags = msg->flags;
+
+ while (count > 0) {
+ inval = i2c_inb(i2c_adap);
+ if (inval >= 0) {
+ *temp = inval;
+ rdcount++;
+ } else { /* read timed out */
+ break;
+ }
+
+ temp++;
+ count--;
+
+ /* Some SMBus transactions require that we receive the
+ transaction length as the first read byte. */
+ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
+ if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+ if (!(flags & I2C_M_NO_RD_ACK))
+ acknak(i2c_adap, 0);
+ dev_err(&i2c_adap->dev, "readbytes: invalid "
+ "block length (%d)\n", inval);
+ return -EREMOTEIO;
+ }
+ /* The original count value accounts for the extra
+ bytes, that is, either 1 for a regular transaction,
+ or 2 for a PEC transaction. */
+ count += inval;
+ msg->len += inval;
+ }
+
+ bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+ inval,
+ (flags & I2C_M_NO_RD_ACK)
+ ? "(no ack/nak)"
+ : (count ? "A" : "NA"));
+
+ if (!(flags & I2C_M_NO_RD_ACK)) {
+ inval = acknak(i2c_adap, count);
+ if (inval < 0)
+ return inval;
+ }
+ }
+ return rdcount;
+}
+
+/* doAddress initiates the transfer by generating the start condition (in
+ * try_address) and transmits the address in the necessary format to handle
+ * reads, writes as well as 10bit-addresses.
+ * returns:
+ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
+ * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
+ * -ETIMEDOUT, for example if the lines are stuck...)
+ */
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ unsigned short flags = msg->flags;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ unsigned char addr;
+ int ret, retries;
+
+ retries = nak_ok ? 0 : i2c_adap->retries;
+
+ if (flags & I2C_M_TEN) {
+ /* a ten bit address */
+ addr = 0xf0 | ((msg->addr >> 7) & 0x06);
+ bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
+ /* try extended address code...*/
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ dev_err(&i2c_adap->dev,
+ "died at extended address code\n");
+ return -EREMOTEIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(i2c_adap, msg->addr & 0xff);
+ if ((ret != 1) && !nak_ok) {
+ /* the chip did not ack / xmission error occurred */
+ dev_err(&i2c_adap->dev, "died at 2nd address code\n");
+ return -EREMOTEIO;
+ }
+ if (flags & I2C_M_RD) {
+ bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+ "start condition\n");
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ dev_err(&i2c_adap->dev,
+ "died at repeated address code\n");
+ return -EREMOTEIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = msg->addr << 1;
+ if (flags & I2C_M_RD)
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok)
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int bit_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_msg *pmsg;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ 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++) {
+ pmsg = &msgs[i];
+ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ if (i) {
+ bit_dbg(3, &i2c_adap->dev, "emitting "
+ "repeated start condition\n");
+ i2c_repstart(adap);
+ }
+ ret = bit_doAddress(i2c_adap, pmsg);
+ if ((ret != 0) && !nak_ok) {
+ bit_dbg(1, &i2c_adap->dev, "NAK from "
+ "device addr 0x%02x msg #%d\n",
+ msgs[i].addr, i);
+ goto bailout;
+ }
+ }
+ if (pmsg->flags & I2C_M_RD) {
+ /* read bytes into buffer*/
+ ret = readbytes(i2c_adap, pmsg);
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ goto bailout;
+ }
+ } else {
+ /* write bytes from buffer */
+ ret = sendbytes(i2c_adap, pmsg);
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ goto bailout;
+ }
+ }
+ }
+ ret = i;
+
+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;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm i2c_bit_algo = {
+ .master_xfer = bit_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __i2c_bit_add_bus(struct i2c_adapter *adap,
+ int (*add_adapter)(struct i2c_adapter *))
+{
+ struct i2c_algo_bit_data *bit_adap = adap->algo_data;
+ int ret;
+
+ if (bit_test) {
+ ret = test_bus(adap);
+ if (ret < 0)
+ return -ENODEV;
+ }
+
+ /* register new adapter to i2c module... */
+ adap->algo = &i2c_bit_algo;
+ adap->retries = 3;
+
+ ret = add_adapter(adap);
+ if (ret < 0)
+ return ret;
+
+ /* Complain if SCL can't be read */
+ if (bit_adap->getscl == NULL) {
+ dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+ dev_warn(&adap->dev, "Bus may be unreliable\n");
+ }
+ return 0;
+}
+
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+ return __i2c_bit_add_bus(adap, i2c_add_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_bus);
+
+int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
+{
+ return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
+
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
new file mode 100644
index 00000000..4ca9cf9c
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -0,0 +1,563 @@
+/*
+ * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
+ * Copyright (C) 2004 Arcom Control Systems
+ * Copyright (C) 2008 Pengutronix
+ *
+ * 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/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+
+#define DEB1(fmt, args...) do { if (i2c_debug >= 1) \
+ printk(KERN_DEBUG fmt, ## args); } while (0)
+#define DEB2(fmt, args...) do { if (i2c_debug >= 2) \
+ printk(KERN_DEBUG fmt, ## args); } while (0)
+#define DEB3(fmt, args...) do { if (i2c_debug >= 3) \
+ printk(KERN_DEBUG fmt, ## args); } while (0)
+
+static int i2c_debug;
+
+#define pca_outw(adap, reg, val) adap->write_byte(adap->data, reg, val)
+#define pca_inw(adap, reg) adap->read_byte(adap->data, reg)
+
+#define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
+#define pca_clock(adap) adap->i2c_clock
+#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
+#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
+#define pca_wait(adap) adap->wait_for_completion(adap->data)
+#define pca_reset(adap) adap->reset_chip(adap->data)
+
+static void pca9665_reset(void *pd)
+{
+ struct i2c_algo_pca_data *adap = pd;
+ pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
+ pca_outw(adap, I2C_PCA_IND, 0xA5);
+ pca_outw(adap, I2C_PCA_IND, 0x5A);
+}
+
+/*
+ * Generate a start condition on the i2c bus.
+ *
+ * returns after the start condition has occurred
+ */
+static int pca_start(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== START\n");
+ sta |= I2C_PCA_CON_STA;
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+ return pca_wait(adap);
+}
+
+/*
+ * Generate a repeated start condition on the i2c bus
+ *
+ * return after the repeated start condition has occurred
+ */
+static int pca_repeated_start(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== REPEATED START\n");
+ sta |= I2C_PCA_CON_STA;
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+ return pca_wait(adap);
+}
+
+/*
+ * Generate a stop condition on the i2c bus
+ *
+ * returns after the stop condition has been generated
+ *
+ * STOPs do not generate an interrupt or set the SI flag, since the
+ * part returns the idle state (0xf8). Hence we don't need to
+ * pca_wait here.
+ */
+static void pca_stop(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== STOP\n");
+ sta |= I2C_PCA_CON_STO;
+ sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+}
+
+/*
+ * Send the slave address and R/W bit
+ *
+ * returns after the address has been sent
+ */
+static int pca_address(struct i2c_algo_pca_data *adap,
+ struct i2c_msg *msg)
+{
+ int sta = pca_get_con(adap);
+ int addr;
+
+ addr = ((0x7f & msg->addr) << 1);
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+ DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
+ msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
+
+ pca_outw(adap, I2C_PCA_DAT, addr);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+
+ return pca_wait(adap);
+}
+
+/*
+ * Transmit a byte.
+ *
+ * Returns after the byte has been transmitted
+ */
+static int pca_tx_byte(struct i2c_algo_pca_data *adap,
+ __u8 b)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== WRITE %#04x\n", b);
+ pca_outw(adap, I2C_PCA_DAT, b);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+
+ return pca_wait(adap);
+}
+
+/*
+ * Receive a byte
+ *
+ * returns immediately.
+ */
+static void pca_rx_byte(struct i2c_algo_pca_data *adap,
+ __u8 *b, int ack)
+{
+ *b = pca_inw(adap, I2C_PCA_DAT);
+ DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
+}
+
+/*
+ * Setup ACK or NACK for next received byte and wait for it to arrive.
+ *
+ * Returns after next byte has arrived.
+ */
+static int pca_rx_ack(struct i2c_algo_pca_data *adap,
+ int ack)
+{
+ int sta = pca_get_con(adap);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA);
+
+ if (ack)
+ sta |= I2C_PCA_CON_AA;
+
+ pca_set_con(adap, sta);
+ return pca_wait(adap);
+}
+
+static int pca_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *msg = NULL;
+ int curmsg;
+ int numbytes = 0;
+ int state;
+ int ret;
+ int completed = 1;
+ unsigned long timeout = jiffies + i2c_adap->timeout;
+
+ while ((state = pca_status(adap)) != 0xf8) {
+ if (time_before(jiffies, timeout)) {
+ msleep(10);
+ } else {
+ dev_dbg(&i2c_adap->dev, "bus is not idle. status is "
+ "%#04x\n", state);
+ return -EAGAIN;
+ }
+ }
+
+ DEB1("{{{ XFER %d messages\n", num);
+
+ if (i2c_debug >= 2) {
+ for (curmsg = 0; curmsg < num; curmsg++) {
+ int addr, i;
+ msg = &msgs[curmsg];
+
+ addr = (0x7f & msg->addr) ;
+
+ if (msg->flags & I2C_M_RD)
+ printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
+ curmsg, msg->len, addr, (addr << 1) | 1);
+ else {
+ printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s",
+ curmsg, msg->len, addr, addr << 1,
+ msg->len == 0 ? "" : ", ");
+ for (i = 0; i < msg->len; i++)
+ printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", ");
+ printk("]\n");
+ }
+ }
+ }
+
+ curmsg = 0;
+ ret = -EREMOTEIO;
+ while (curmsg < num) {
+ state = pca_status(adap);
+
+ DEB3("STATE is 0x%02x\n", state);
+ msg = &msgs[curmsg];
+
+ switch (state) {
+ case 0xf8: /* On reset or stop the bus is idle */
+ completed = pca_start(adap);
+ break;
+
+ case 0x08: /* A START condition has been transmitted */
+ case 0x10: /* A repeated start condition has been transmitted */
+ completed = pca_address(adap, msg);
+ break;
+
+ case 0x18: /* SLA+W has been transmitted; ACK has been received */
+ case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
+ if (numbytes < msg->len) {
+ completed = pca_tx_byte(adap,
+ msg->buf[numbytes]);
+ numbytes++;
+ break;
+ }
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ completed = pca_repeated_start(adap);
+ break;
+
+ case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after SLA+W\n");
+ pca_stop(adap);
+ goto out;
+
+ case 0x40: /* SLA+R has been transmitted; ACK has been received */
+ completed = pca_rx_ack(adap, msg->len > 1);
+ break;
+
+ case 0x50: /* Data bytes has been received; ACK has been returned */
+ if (numbytes < msg->len) {
+ pca_rx_byte(adap, &msg->buf[numbytes], 1);
+ numbytes++;
+ completed = pca_rx_ack(adap,
+ numbytes < msg->len - 1);
+ break;
+ }
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ completed = pca_repeated_start(adap);
+ break;
+
+ case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after SLA+R\n");
+ pca_stop(adap);
+ goto out;
+
+ case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after data byte\n");
+ pca_stop(adap);
+ goto out;
+
+ case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
+ DEB2("Arbitration lost\n");
+ /*
+ * The PCA9564 data sheet (2006-09-01) says "A
+ * START condition will be transmitted when the
+ * bus becomes free (STOP or SCL and SDA high)"
+ * when the STA bit is set (p. 11).
+ *
+ * In case this won't work, try pca_reset()
+ * instead.
+ */
+ pca_start(adap);
+ goto out;
+
+ case 0x58: /* Data byte has been received; NOT ACK has been returned */
+ if (numbytes == msg->len - 1) {
+ pca_rx_byte(adap, &msg->buf[numbytes], 0);
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ completed = pca_repeated_start(adap);
+ } else {
+ DEB2("NOT ACK sent after data byte received. "
+ "Not final byte. numbytes %d. len %d\n",
+ numbytes, msg->len);
+ pca_stop(adap);
+ goto out;
+ }
+ break;
+ case 0x70: /* Bus error - SDA stuck low */
+ DEB2("BUS ERROR - SDA Stuck low\n");
+ pca_reset(adap);
+ goto out;
+ case 0x90: /* Bus error - SCL stuck low */
+ DEB2("BUS ERROR - SCL Stuck low\n");
+ pca_reset(adap);
+ goto out;
+ case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
+ DEB2("BUS ERROR - Illegal START or STOP\n");
+ pca_reset(adap);
+ goto out;
+ default:
+ dev_err(&i2c_adap->dev, "unhandled SIO state 0x%02x\n", state);
+ break;
+ }
+
+ if (!completed)
+ goto out;
+ }
+
+ ret = curmsg;
+ out:
+ DEB1("}}} transferred %d/%d messages. "
+ "status is %#04x. control is %#04x\n",
+ curmsg, num, pca_status(adap),
+ pca_get_con(adap));
+ return ret;
+}
+
+static u32 pca_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm pca_algo = {
+ .master_xfer = pca_xfer,
+ .functionality = pca_func,
+};
+
+static unsigned int pca_probe_chip(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pca_data *pca_data = adap->algo_data;
+ /* The trick here is to check if there is an indirect register
+ * available. If there is one, we will read the value we first
+ * wrote on I2C_PCA_IADR. Otherwise, we will read the last value
+ * we wrote on I2C_PCA_ADR
+ */
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
+ pca_outw(pca_data, I2C_PCA_IND, 0xAA);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ITO);
+ pca_outw(pca_data, I2C_PCA_IND, 0x00);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
+ if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {
+ printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name);
+ return I2C_PCA_CHIP_9665;
+ } else {
+ printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name);
+ return I2C_PCA_CHIP_9564;
+ }
+}
+
+static int pca_init(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pca_data *pca_data = adap->algo_data;
+
+ adap->algo = &pca_algo;
+
+ if (pca_probe_chip(adap) == I2C_PCA_CHIP_9564) {
+ static int freqs[] = {330, 288, 217, 146, 88, 59, 44, 36};
+ int clock;
+
+ if (pca_data->i2c_clock > 7) {
+ switch (pca_data->i2c_clock) {
+ case 330000:
+ pca_data->i2c_clock = I2C_PCA_CON_330kHz;
+ break;
+ case 288000:
+ pca_data->i2c_clock = I2C_PCA_CON_288kHz;
+ break;
+ case 217000:
+ pca_data->i2c_clock = I2C_PCA_CON_217kHz;
+ break;
+ case 146000:
+ pca_data->i2c_clock = I2C_PCA_CON_146kHz;
+ break;
+ case 88000:
+ pca_data->i2c_clock = I2C_PCA_CON_88kHz;
+ break;
+ case 59000:
+ pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ break;
+ case 44000:
+ pca_data->i2c_clock = I2C_PCA_CON_44kHz;
+ break;
+ case 36000:
+ pca_data->i2c_clock = I2C_PCA_CON_36kHz;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Invalid I2C clock speed selected."
+ " Using default 59kHz.\n", adap->name);
+ pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ }
+ } else {
+ printk(KERN_WARNING "%s: "
+ "Choosing the clock frequency based on "
+ "index is deprecated."
+ " Use the nominal frequency.\n", adap->name);
+ }
+
+ pca_reset(pca_data);
+
+ clock = pca_clock(pca_data);
+ printk(KERN_INFO "%s: Clock frequency is %dkHz\n",
+ adap->name, freqs[clock]);
+
+ pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+ } else {
+ int clock;
+ int mode;
+ int tlow, thi;
+ /* Values can be found on PCA9665 datasheet section 7.3.2.6 */
+ int min_tlow, min_thi;
+ /* These values are the maximum raise and fall values allowed
+ * by the I2C operation mode (Standard, Fast or Fast+)
+ * They are used (added) below to calculate the clock dividers
+ * of PCA9665. Note that they are slightly different of the
+ * real maximum, to allow the change on mode exactly on the
+ * maximum clock rate for each mode
+ */
+ int raise_fall_time;
+
+ /* Ignore the reset function from the module,
+ * we can use the parallel bus reset
+ */
+ pca_data->reset_chip = pca9665_reset;
+
+ if (pca_data->i2c_clock > 1265800) {
+ printk(KERN_WARNING "%s: I2C clock speed too high."
+ " Using 1265.8kHz.\n", adap->name);
+ pca_data->i2c_clock = 1265800;
+ }
+
+ if (pca_data->i2c_clock < 60300) {
+ printk(KERN_WARNING "%s: I2C clock speed too low."
+ " Using 60.3kHz.\n", adap->name);
+ pca_data->i2c_clock = 60300;
+ }
+
+ /* To avoid integer overflow, use clock/100 for calculations */
+ clock = pca_clock(pca_data) / 100;
+
+ if (pca_data->i2c_clock > 10000) {
+ mode = I2C_PCA_MODE_TURBO;
+ min_tlow = 14;
+ min_thi = 5;
+ raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
+ } else if (pca_data->i2c_clock > 4000) {
+ mode = I2C_PCA_MODE_FASTP;
+ min_tlow = 17;
+ min_thi = 9;
+ raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
+ } else if (pca_data->i2c_clock > 1000) {
+ mode = I2C_PCA_MODE_FAST;
+ min_tlow = 44;
+ min_thi = 20;
+ raise_fall_time = 58; /* Raise 29e-8s, Fall 29e-8s */
+ } else {
+ mode = I2C_PCA_MODE_STD;
+ min_tlow = 157;
+ min_thi = 134;
+ raise_fall_time = 127; /* Raise 29e-8s, Fall 98e-8s */
+ }
+
+ /* The minimum clock that respects the thi/tlow = 134/157 is
+ * 64800 Hz. Below that, we have to fix the tlow to 255 and
+ * calculate the thi factor.
+ */
+ if (clock < 648) {
+ tlow = 255;
+ thi = 1000000 - clock * raise_fall_time;
+ thi /= (I2C_PCA_OSC_PER * clock) - tlow;
+ } else {
+ tlow = (1000000 - clock * raise_fall_time) * min_tlow;
+ tlow /= I2C_PCA_OSC_PER * clock * (min_thi + min_tlow);
+ thi = tlow * min_thi / min_tlow;
+ }
+
+ pca_reset(pca_data);
+
+ printk(KERN_INFO
+ "%s: Clock frequency is %dHz\n", adap->name, clock * 100);
+
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE);
+ pca_outw(pca_data, I2C_PCA_IND, mode);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
+ pca_outw(pca_data, I2C_PCA_IND, tlow);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
+ pca_outw(pca_data, I2C_PCA_IND, thi);
+
+ pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
+ }
+ udelay(500); /* 500 us for oscilator to stabilise */
+
+ return 0;
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pca_add_bus(struct i2c_adapter *adap)
+{
+ int rval;
+
+ rval = pca_init(adap);
+ if (rval)
+ return rval;
+
+ return i2c_add_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_bus);
+
+int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
+{
+ int rval;
+
+ rval = pca_init(adap);
+ if (rval)
+ return rval;
+
+ return i2c_add_numbered_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
+ "Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, 0);
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
new file mode 100644
index 00000000..5eebf562
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -0,0 +1,441 @@
+/*
+ * i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters
+ *
+ * Copyright (C) 1995-1997 Simon G. Vogl
+ * 1998-2000 Hans Berglund
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+ * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
+ * <mbailey@littlefeet-inc.com>
+ *
+ * Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
+ * messages, proper stop/repstart signaling during receive, added detect code
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include "i2c-algo-pcf.h"
+
+
+#define DEB2(x) if (i2c_debug >= 2) x
+#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */
+#define DEBPROTO(x) if (i2c_debug >= 9) x;
+ /* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 16
+
+/*
+ * module parameters:
+ */
+static int i2c_debug;
+
+/* setting states on the bus with the right timing: */
+
+#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
+#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl)
+#define get_own(adap) adap->getown(adap->data)
+#define get_clock(adap) adap->getclock(adap->data)
+#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
+#define i2c_inb(adap) adap->getpcf(adap->data, 0)
+
+/* other auxiliary functions */
+
+static void i2c_start(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk(KERN_DEBUG "S "));
+ set_pcf(adap, 1, I2C_PCF_START);
+}
+
+static void i2c_repstart(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk(" Sr "));
+ set_pcf(adap, 1, I2C_PCF_REPSTART);
+}
+
+static void i2c_stop(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk("P\n"));
+ set_pcf(adap, 1, I2C_PCF_STOP);
+}
+
+static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
+{
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+ *status));
+ /*
+ * Cleanup from LAB -- reset and enable ESO.
+ * This resets the PCF8584; since we've lost the bus, no
+ * further attempts should be made by callers to clean up
+ * (no i2c_stop() etc.)
+ */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ /*
+ * We pause for a time period sufficient for any running
+ * I2C transaction to complete -- the arbitration logic won't
+ * work properly until the next START is seen.
+ * It is assumed the bus driver or client has set a proper value.
+ *
+ * REVISIT: should probably use msleep instead of mdelay if we
+ * know we can sleep.
+ */
+ if (adap->lab_mdelay)
+ mdelay(adap->lab_mdelay);
+
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
+ get_pcf(adap, 1)));
+}
+
+static int wait_for_bb(struct i2c_algo_pcf_data *adap)
+{
+
+ int timeout = DEF_TIMEOUT;
+ int status;
+
+ status = get_pcf(adap, 1);
+
+ while (!(status & I2C_PCF_BB) && --timeout) {
+ udelay(100); /* wait for 100 us */
+ status = get_pcf(adap, 1);
+ }
+
+ if (timeout == 0) {
+ printk(KERN_ERR "Timeout waiting for Bus Busy\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status)
+{
+
+ int timeout = DEF_TIMEOUT;
+
+ *status = get_pcf(adap, 1);
+
+ while ((*status & I2C_PCF_PIN) && --timeout) {
+ adap->waitforpin(adap->data);
+ *status = get_pcf(adap, 1);
+ }
+ if (*status & I2C_PCF_LAB) {
+ handle_lab(adap, status);
+ return -EINTR;
+ }
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/*
+ * This should perform the 'PCF8584 initialization sequence' as described
+ * in the Philips IC12 data book (1995, Aug 29).
+ * There should be a 30 clock cycle wait after reset, I assume this
+ * has been fulfilled.
+ * There should be a delay at the end equal to the longest I2C message
+ * to synchronize the BB-bit (in multimaster systems). How long is
+ * this? I assume 1 second is always long enough.
+ *
+ * vdovikin: added detect code for PCF8584
+ */
+static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+{
+ unsigned char temp;
+
+ DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n",
+ get_pcf(adap, 1)));
+
+ /* S1=0x80: S0 selected, serial interface off */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ /*
+ * check to see S1 now used as R/W ctrl -
+ * PCF8584 does that when ESO is zero
+ */
+ 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; /* definitely not PCF8584 */
+ }
+
+ /* load own address in S0, effective address is (own << 1) */
+ i2c_outb(adap, get_own(adap));
+ /* check it's really written */
+ if ((temp = i2c_inb(adap)) != get_own(adap)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* S1=0xA0, next byte in S2 */
+ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+ /* check to see S2 now selected */
+ if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* load clock register S2 */
+ i2c_outb(adap, get_clock(adap));
+ /* check it's really written, the only 5 lowest bits does matter */
+ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* Enable serial interface, idle, S0 selected */
+ set_pcf(adap, 1, I2C_PCF_IDLE);
+
+ /* check to see PCF is really idled and we can access status register */
+ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
+
+ return 0;
+}
+
+static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+ int count, int last)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wrcount, status, timeout;
+
+ for (wrcount=0; wrcount<count; ++wrcount) {
+ DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
+ buf[wrcount] & 0xff));
+ i2c_outb(adap, buf[wrcount]);
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ if (timeout == -EINTR)
+ return -EINTR; /* arbitration lost */
+
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n");
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ }
+ if (last)
+ i2c_stop(adap);
+ else
+ i2c_repstart(adap);
+
+ return wrcount;
+}
+
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+ int count, int last)
+{
+ int i, status;
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wfp;
+
+ /* increment number of bytes to read by one -- read dummy byte */
+ for (i = 0; i <= count; i++) {
+
+ if ((wfp = wait_for_pin(adap, &status))) {
+ if (wfp == -EINTR)
+ return -EINTR; /* arbitration lost */
+
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
+ return -1;
+ }
+
+ if ((status & I2C_PCF_LRB) && (i != count)) {
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n");
+ return -1;
+ }
+
+ if (i == count - 1) {
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ } else if (i == count) {
+ if (last)
+ i2c_stop(adap);
+ else
+ i2c_repstart(adap);
+ }
+
+ if (i)
+ buf[i - 1] = i2c_inb(adap);
+ else
+ i2c_inb(adap); /* dummy read */
+ }
+
+ return i - 1;
+}
+
+
+static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+ struct i2c_msg *msg)
+{
+ unsigned short flags = msg->flags;
+ unsigned char addr;
+
+ addr = msg->addr << 1;
+ if (flags & I2C_M_RD)
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+ i2c_outb(adap, addr);
+
+ return 0;
+}
+
+static int pcf_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i;
+ int ret=0, timeout, status;
+
+ if (adap->xfer_begin)
+ adap->xfer_begin(adap->data);
+
+ /* Check for bus busy */
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
+ "Timeout waiting for BB in pcf_xfer\n");)
+ i = -EIO;
+ goto out;
+ }
+
+ for (i = 0;ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);)
+
+ ret = pcf_doAddress(adap, pmsg);
+
+ /* Send START */
+ if (i == 0)
+ i2c_start(adap);
+
+ /* Wait for PIN (pending interrupt NOT) */
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ if (timeout == -EINTR) {
+ /* arbitration lost */
+ i = -EINTR;
+ goto out;
+ }
+ i2c_stop(adap);
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
+ "for PIN(1) in pcf_xfer\n");)
+ i = -EREMOTEIO;
+ goto out;
+ }
+
+ /* Check LRB (last rcvd bit - slave ack) */
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
+ i = -EREMOTEIO;
+ goto out;
+ }
+
+ DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+ i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+
+ if (pmsg->flags & I2C_M_RD) {
+ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
+
+ if (ret != pmsg->len) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+ "only read %d bytes.\n",ret));
+ } else {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
+ }
+ } else {
+ ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
+
+ if (ret != pmsg->len) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+ "only wrote %d bytes.\n",ret));
+ } else {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+ }
+ }
+ }
+
+out:
+ if (adap->xfer_end)
+ adap->xfer_end(adap->data);
+ return i;
+}
+
+static u32 pcf_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* exported algorithm data: */
+static const struct i2c_algorithm pcf_algo = {
+ .master_xfer = pcf_xfer,
+ .functionality = pcf_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pcf_add_bus(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
+ int rval;
+
+ DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
+
+ /* register new adapter to i2c module... */
+ adap->algo = &pcf_algo;
+
+ if ((rval = pcf_init_8584(pcf_adap)))
+ return rval;
+
+ rval = i2c_add_adapter(adap);
+
+ return rval;
+}
+EXPORT_SYMBOL(i2c_pcf_add_bus);
+
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff --git a/drivers/i2c/algos/i2c-algo-pcf.h b/drivers/i2c/algos/i2c-algo-pcf.h
new file mode 100644
index 00000000..5263a9ee
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-pcf.h
@@ -0,0 +1,76 @@
+/* -------------------------------------------------------------------- */
+/* i2c-pcf8584.h: PCF 8584 global defines */
+/* -------------------------------------------------------------------- */
+/* Copyright (C) 1996 Simon G. Vogl
+ 1999 Hans Berglund
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* -------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl> */
+
+#ifndef I2C_PCF8584_H
+#define I2C_PCF8584_H 1
+
+/* ----- Control register bits ---------------------------------------- */
+#define I2C_PCF_PIN 0x80
+#define I2C_PCF_ESO 0x40
+#define I2C_PCF_ES1 0x20
+#define I2C_PCF_ES2 0x10
+#define I2C_PCF_ENI 0x08
+#define I2C_PCF_STA 0x04
+#define I2C_PCF_STO 0x02
+#define I2C_PCF_ACK 0x01
+
+#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
+#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK)
+
+/* ----- Status register bits ----------------------------------------- */
+/*#define I2C_PCF_PIN 0x80 as above*/
+
+#define I2C_PCF_INI 0x40 /* 1 if not initialized */
+#define I2C_PCF_STS 0x20
+#define I2C_PCF_BER 0x10
+#define I2C_PCF_AD0 0x08
+#define I2C_PCF_LRB 0x08
+#define I2C_PCF_AAS 0x04
+#define I2C_PCF_LAB 0x02
+#define I2C_PCF_BB 0x01
+
+/* ----- Chip clock frequencies --------------------------------------- */
+#define I2C_PCF_CLK3 0x00
+#define I2C_PCF_CLK443 0x10
+#define I2C_PCF_CLK6 0x14
+#define I2C_PCF_CLK 0x18
+#define I2C_PCF_CLK12 0x1c
+
+/* ----- transmission frequencies ------------------------------------- */
+#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
+#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
+#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
+#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
+
+
+/* ----- Access to internal registers according to ES1,ES2 ------------ */
+/* they are mapped to the data port ( a0 = 0 ) */
+/* available when ESO == 0 : */
+
+#define I2C_PCF_OWNADR 0
+#define I2C_PCF_INTREG I2C_PCF_ES2
+#define I2C_PCF_CLKREG I2C_PCF_ES1
+
+#endif /* I2C_PCF8584_H */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
new file mode 100644
index 00000000..646068e5
--- /dev/null
+++ b/drivers/i2c/busses/Kconfig
@@ -0,0 +1,880 @@
+#
+# Sensor device configuration
+#
+
+menu "I2C Hardware Bus support"
+
+comment "PC SMBus host controller drivers"
+ depends on PCI
+
+config I2C_ALI1535
+ tristate "ALI 1535"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SMB
+ Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
+ controller is part of the 7101 device, which is an ACPI-compliant
+ Power Management Unit (PMU).
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ali1535.
+
+config I2C_ALI1563
+ tristate "ALI 1563"
+ depends on PCI && EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the SMB
+ Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
+ controller is part of the 7101 device, which is an ACPI-compliant
+ Power Management Unit (PMU).
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ali1563.
+
+config I2C_ALI15X3
+ tristate "ALI 15x3"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ali15x3.
+
+config I2C_AMD756
+ tristate "AMD 756/766/768/8111 and nVidia nForce"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the AMD
+ 756/766/768 mainboard I2C interfaces. The driver also includes
+ support for the first (SMBus 1.0) I2C interface of the AMD 8111 and
+ the nVidia nForce I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-amd756.
+
+config I2C_AMD756_S4882
+ tristate "SMBus multiplexing on the Tyan S4882"
+ depends on I2C_AMD756 && X86 && EXPERIMENTAL
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
+ over 8 different channels, where the various memory module EEPROMs
+ and temperature sensors live. Saying yes here will give you access
+ to these in addition to the trunk.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-amd756-s4882.
+
+config I2C_AMD8111
+ tristate "AMD 8111"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ second (SMBus 2.0) AMD 8111 mainboard I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-amd8111.
+
+config I2C_I801
+ tristate "Intel 82801 (ICH/PCH)"
+ depends on PCI
+ select CHECK_SIGNATURE if X86 && DMI
+ help
+ If you say yes to this option, support will be included for the Intel
+ 801 family of mainboard I2C interfaces. Specifically, the following
+ versions of the chipset are supported:
+ 82801AA
+ 82801AB
+ 82801BA
+ 82801CA/CAM
+ 82801DB
+ 82801EB/ER (ICH5/ICH5R)
+ 6300ESB
+ ICH6
+ ICH7
+ ESB2
+ ICH8
+ ICH9
+ EP80579 (Tolapai)
+ ICH10
+ 5/3400 Series (PCH)
+ 6 Series (PCH)
+ Patsburg (PCH)
+ DH89xxCC (PCH)
+ Panther Point (PCH)
+
+ This driver can also be built as a module. If so, the module
+ will be called 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.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-isch.
+
+config I2C_PIIX4
+ tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the Intel
+ PIIX4 family of mainboard I2C interfaces. Specifically, the following
+ versions of the chipset are supported (note that Serverworks is part
+ of Broadcom):
+ Intel PIIX4
+ Intel 440MX
+ ATI IXP200
+ ATI IXP300
+ ATI IXP400
+ ATI SB600
+ ATI SB700
+ ATI SB800
+ AMD Hudson-2
+ Serverworks OSB4
+ Serverworks CSB5
+ Serverworks CSB6
+ Serverworks HT-1000
+ Serverworks HT-1100
+ SMSC Victory66
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-piix4.
+
+config I2C_NFORCE2
+ tristate "Nvidia nForce2, nForce3 and nForce4"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the Nvidia
+ nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-nforce2.
+
+config I2C_NFORCE2_S4985
+ tristate "SMBus multiplexing on the Tyan S4985"
+ depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
+ over 4 different channels, where the various memory module EEPROMs
+ live. Saying yes here will give you access to these in addition
+ to the trunk.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-nforce2-s4985.
+
+config I2C_SIS5595
+ tristate "SiS 5595"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS5595 SMBus (a subset of I2C) interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis5595.
+
+config I2C_SIS630
+ tristate "SiS 630/730"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS630 and SiS730 SMBus (a subset of I2C) interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis630.
+
+config I2C_SIS96X
+ tristate "SiS 96x"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SiS
+ 96x SMBus (a subset of I2C) interfaces. Specifically, the following
+ chipsets are supported:
+ 645/961
+ 645DX/961
+ 645DX/962
+ 648/961
+ 650/961
+ 735
+ 745
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis96x.
+
+config I2C_VIA
+ tristate "VIA VT82C586B"
+ depends on PCI && EXPERIMENTAL
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be included for the VIA
+ 82C586B I2C interface
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-via.
+
+config I2C_VIAPRO
+ tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the VIA
+ VT82C596 and later SMBus interface. Specifically, the following
+ chipsets are supported:
+ VT82C596A/B
+ VT82C686A/B
+ VT8231
+ VT8233/A
+ VT8235
+ VT8237R/A/S
+ VT8251
+ CX700
+ VX800/VX820
+ VX855/VX875
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-viapro.
+
+if ACPI
+
+comment "ACPI drivers"
+
+config I2C_SCMI
+ tristate "SMBus Control Method Interface"
+ help
+ This driver supports the SMBus Control Method Interface. It needs the
+ BIOS to declare ACPI control methods as described in the SMBus Control
+ Method Interface specification.
+
+ To compile this driver as a module, choose M here:
+ the module will be called i2c-scmi.
+
+endif # ACPI
+
+comment "Mac SMBus host controller drivers"
+ depends on PPC_CHRP || PPC_PMAC
+
+config I2C_HYDRA
+ tristate "CHRP Apple Hydra Mac I/O I2C interface"
+ depends on PCI && PPC_CHRP && EXPERIMENTAL
+ select I2C_ALGOBIT
+ help
+ This supports the use of the I2C interface in the Apple Hydra Mac
+ I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you
+ have such a machine.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-hydra.
+
+config I2C_POWERMAC
+ tristate "Powermac I2C interface"
+ depends on PPC_PMAC
+ default y
+ help
+ This exposes the various PowerMac i2c interfaces to the linux i2c
+ layer and to userland. It is used by various drivers on the PowerMac
+ platform, and should generally be enabled.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-powermac.
+
+comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
+config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
+ This driver is BROKEN because the controller which it uses
+ will easily trigger RX overrun and TX underrun errors. Using
+ low I2C clock rates may partially work around those issues
+ on some systems. Another serious problem is that there is no
+ documented way to issue repeated START conditions, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+ unless your system can cope with those limitations.
+
+config I2C_AU1550
+ tristate "Au1550/Au1200 SMBus interface"
+ depends on SOC_AU1550 || SOC_AU1200
+ help
+ If you say yes to this option, support will be included for the
+ Au1550 and Au1200 SMBus interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-au1550.
+
+config I2C_BLACKFIN_TWI
+ tristate "Blackfin TWI I2C support"
+ depends on BLACKFIN
+ depends on !BF561 && !BF531 && !BF532 && !BF533
+ help
+ This is the I2C bus driver for Blackfin on-chip TWI interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-bfin-twi.
+
+config I2C_BLACKFIN_TWI_CLK_KHZ
+ int "Blackfin TWI I2C clock (kHz)"
+ depends on I2C_BLACKFIN_TWI
+ range 21 400
+ default 50
+ help
+ The unit of the TWI clock is kHz.
+
+config I2C_CPM
+ tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
+ depends on (CPM1 || CPM2) && OF_I2C
+ help
+ This supports the use of the I2C interface on Freescale
+ processors with CPM1 or CPM2.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-cpm.
+
+config I2C_DAVINCI
+ tristate "DaVinci I2C driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for TI DaVinci I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-davinci.
+
+ Please note that this driver might be needed to bring up other
+ devices such as DaVinci NIC.
+ For details please see http://www.ti.com/davinci
+
+config I2C_DESIGNWARE
+ tristate "Synopsys DesignWare"
+ depends on HAVE_CLK
+ help
+ If you say yes to this option, support will be included for the
+ Synopsys DesignWare I2C adapter. Only master mode is supported.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-designware.
+
+config I2C_GPIO
+ tristate "GPIO-based bitbanging I2C"
+ depends on GENERIC_GPIO
+ select I2C_ALGOBIT
+ help
+ This is a very simple bitbanging I2C driver utilizing the
+ arch-neutral GPIO API to control the SCL and SDA lines.
+
+config I2C_HIGHLANDER
+ tristate "Highlander FPGA SMBus interface"
+ depends on SH_HIGHLANDER
+ help
+ If you say yes to this option, support will be included for
+ the SMBus interface located in the FPGA on various Highlander
+ boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+ FPGAs. This is wholly unrelated to the SoC I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-highlander.
+
+config I2C_IBM_IIC
+ tristate "IBM PPC 4xx on-chip I2C interface"
+ depends on 4xx
+ help
+ Say Y here if you want to use IIC peripheral found on
+ embedded IBM PPC 4xx based systems.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ibm_iic.
+
+config I2C_IMX
+ tristate "IMX I2C interface"
+ depends on ARCH_MXC
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Freescale i.MX/MXC processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-imx.
+
+config I2C_INTEL_MID
+ tristate "Intel Moorestown/Medfield Platform I2C controller"
+ depends on PCI
+ help
+ Say Y here if you have an Intel Moorestown/Medfield platform I2C
+ controller.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-intel-mid.
+
+config I2C_IOP3XX
+ tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-iop3xx.
+
+config I2C_IXP2000
+ tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP2000
+ select I2C_ALGOBIT
+ help
+ Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
+ system and are using GPIO lines for an I2C bus.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-ixp2000.
+
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
+config I2C_MPC
+ tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
+ depends on PPC
+ help
+ If you say yes to this option, support will be included for the
+ 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.
+
+config I2C_MV64XXX
+ tristate "Marvell mv64xxx I2C Controller"
+ depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Marvell 64xxx line of host bridges.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mv64xxx.
+
+config I2C_MXS
+ tristate "Freescale i.MX28 I2C interface"
+ depends on SOC_IMX28
+ help
+ Say Y here if you want to use the I2C bus controller on
+ the Freescale i.MX28 processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mxs.
+
+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_NUC900
+ tristate "NUC900 I2C Driver"
+ depends on ARCH_W90X900
+ help
+ Say Y here to include support for I2C controller in the
+ Winbond/Nuvoton NUC900 based System-on-Chip devices.
+
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
+config I2C_OMAP
+ tristate "OMAP I2C adapter"
+ depends on ARCH_OMAP
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Texas Instruments OMAP1/2 family of processors.
+ Like OMAP1510/1610/1710/5912 and OMAP242x.
+ For details see http://www.ti.com/omap.
+
+config I2C_PASEMI
+ tristate "PA Semi SMBus interface"
+ depends on PPC_PASEMI && PCI
+ help
+ Supports the PA Semi PWRficient on-chip SMBus interfaces.
+
+config I2C_PCA_PLATFORM
+ tristate "PCA9564/PCA9665 as platform device"
+ select I2C_ALGOPCA
+ default n
+ help
+ This driver supports a memory mapped Philips PCA9564/PCA9665
+ parallel bus to I2C bus controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pca-platform.
+
+config I2C_PMCMSP
+ tristate "PMC MSP I2C TWI Controller"
+ depends on PMC_MSP
+ help
+ This driver supports the PMC TWI controller on MSP devices.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-pmcmsp.
+
+config I2C_PNX
+ tristate "I2C bus support for Philips PNX and NXP LPC targets"
+ depends on ARCH_PNX4008 || ARCH_LPC32XX
+ help
+ This driver supports the Philips IP3204 I2C IP block master and/or
+ slave controller
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pnx.
+
+config I2C_PUV3
+ tristate "PKUnity v3 I2C bus support"
+ depends on UNICORE32 && ARCH_PUV3
+ select I2C_ALGOBIT
+ help
+ This driver supports the I2C IP inside the PKUnity-v3 SoC.
+ This I2C bus controller is under AMBA/AXI bus.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-puv3.
+
+config I2C_PXA
+ tristate "Intel PXA2XX I2C adapter"
+ depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF)
+ help
+ If you have devices in the PXA I2C bus, say yes to this option.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pxa.
+
+config I2C_PXA_PCI
+ def_bool I2C_PXA && X86_32 && PCI && OF
+
+config I2C_PXA_SLAVE
+ bool "Intel PXA2XX I2C Slave comms support"
+ depends on I2C_PXA && !X86_32
+ help
+ Support I2C slave mode communications on the PXA I2C bus. This
+ is necessary for systems where the PXA may be a target on the
+ I2C bus.
+
+config HAVE_S3C2410_I2C
+ bool
+ help
+ This will include I2C support for Samsung SoCs. If you want to
+ include I2C support for any machine, kindly select this in the
+ respective Kconfig file.
+
+config I2C_S3C2410
+ tristate "S3C2410 I2C Driver"
+ depends on HAVE_S3C2410_I2C
+ help
+ Say Y here to include support for I2C controller in the
+ Samsung SoCs.
+
+config I2C_S6000
+ tristate "S6000 I2C support"
+ depends on XTENSA_VARIANT_S6000
+ help
+ This driver supports the on chip I2C device on the
+ S6000 xtensa processor family.
+
+ To compile this driver as a module, choose M here. The module
+ will be called i2c-s6000.
+
+config I2C_SH7760
+ tristate "Renesas SH7760 I2C Controller"
+ depends on CPU_SUBTYPE_SH7760
+ help
+ This driver supports the 2 I2C interfaces on the Renesas SH7760.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sh7760.
+
+config I2C_SH_MOBILE
+ tristate "SuperH Mobile I2C Controller"
+ depends on SUPERH || ARCH_SHMOBILE
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Renesas SH-Mobile processor.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sh_mobile.
+
+config I2C_SIMTEC
+ tristate "Simtec Generic I2C interface"
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be included for
+ the Simtec Generic I2C interface. This driver is for the
+ simple I2C bus used on newer Simtec products for general
+ I2C, such as DDC on the Simtec BBD2016A.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-simtec.
+
+config I2C_STU300
+ tristate "ST Microelectronics DDC I2C interface"
+ depends on MACH_U300
+ default y if MACH_U300
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface from ST Microelectronics simply called "DDC I2C"
+ supporting both I2C and DDC, used in e.g. the U300 series
+ mobile platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-stu300.
+
+config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+
+config I2C_VERSATILE
+ tristate "ARM Versatile/Realview I2C bus support"
+ depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C serial bus on ARMs Versatile
+ range of platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-versatile.
+
+config I2C_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.
+
+config I2C_EG20T
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
+ depends on PCI
+ help
+ This driver is for PCH(Platform controller Hub) I2C of EG20T which
+ is an IOH(Input/Output Hub) for x86 embedded processor.
+ This driver can access PCH I2C bus device.
+
+ This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+ Output Hub), ML7213 and ML7223.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+ for MP(Media Phone) use.
+ ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+
+comment "External I2C/SMBus adapter drivers"
+
+config I2C_DIOLAN_U2C
+ tristate "Diolan U2C-12 USB adapter"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for Diolan
+ U2C-12, a USB to I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-diolan-u2c.
+
+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.
+ Basically any adapter using the parallel port as an I2C bus with
+ no extra chipset is supported by this driver, or could be.
+
+ This driver is a replacement for (and was inspired by) an older
+ driver named i2c-philips-par. The new driver supports more devices,
+ and makes it easier to add support for new devices.
+
+ An adapter type parameter is now mandatory. Please read the file
+ Documentation/i2c/busses/i2c-parport for details.
+
+ Another driver exists, named i2c-parport-light, which doesn't depend
+ on the parport driver. This is meant for embedded systems. Don't say
+ Y here if you intend to say Y or M there.
+
+ This support is also available as a module. If so, the module
+ will be called 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.
+ Basically any adapter using the parallel port as an I2C bus with
+ no extra chipset is supported by this driver, or could be.
+
+ This driver is a light version of i2c-parport. It doesn't depend
+ on the parport driver, and uses direct I/O access instead. This
+ might be preferred on embedded systems where wasting memory for
+ the clean but heavy parport handling is not an option. The
+ drawback is a reduced portability and the impossibility to
+ daisy-chain other parallel port devices.
+
+ Don't say Y here if you said Y or M to i2c-parport. Saying M to
+ both is possible but both modules should not be loaded at the same
+ time.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-parport-light.
+
+config I2C_TAOS_EVM
+ tristate "TAOS evaluation module"
+ depends on EXPERIMENTAL
+ select SERIO
+ select SERIO_SERPORT
+ default n
+ help
+ This supports TAOS evaluation modules on serial port. In order to
+ use this driver, you will need the inputattach tool, which is part
+ of the input-utils package.
+
+ If unsure, say N.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-taos-evm.
+
+config I2C_TINY_USB
+ tristate "Tiny-USB adapter"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for the
+ i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
+ http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-tiny-usb.
+
+comment "Other I2C/SMBus bus drivers"
+
+config I2C_ACORN
+ tristate "Acorn IOC/IOMD I2C bus support"
+ depends on ARCH_ACORN
+ default y
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C bus on Acorn platforms.
+
+ If you don't know, say Y.
+
+config I2C_ELEKTOR
+ tristate "Elektor ISA card"
+ depends on ISA && BROKEN_ON_SMP
+ select I2C_ALGOPCF
+ help
+ This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
+ such an adapter.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-elektor.
+
+config I2C_PCA_ISA
+ tristate "PCA9564/PCA9665 on an ISA bus"
+ depends on ISA
+ select I2C_ALGOPCA
+ default n
+ help
+ This driver supports ISA boards using the Philips PCA9564/PCA9665
+ parallel bus to I2C bus controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pca-isa.
+
+ This device is almost undetectable and using this driver on a
+ system which doesn't have this device will result in long
+ delays when I2C/SMBus chip drivers are loaded (e.g. at boot
+ time). If unsure, say N.
+
+config I2C_SIBYTE
+ tristate "SiByte SMBus interface"
+ depends on SIBYTE_SB1xxx_SOC
+ help
+ Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+
+config I2C_STUB
+ tristate "I2C/SMBus Test Stub"
+ depends on EXPERIMENTAL && m
+ default 'n'
+ help
+ This module may be useful to developers of SMBus client drivers,
+ especially for certain kinds of sensor chips.
+
+ If you do build this module, be sure to read the notes and warnings
+ in <file:Documentation/i2c/i2c-stub>.
+
+ If you don't know what to do here, definitely say N.
+
+config SCx200_I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+ depends on SCx200_GPIO
+ select I2C_ALGOBIT
+ help
+ Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_i2c.
+
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ (or scx200_acb) instead.
+
+config SCx200_I2C_SCL
+ int "GPIO pin used for SCL"
+ depends on SCx200_I2C
+ default "12"
+ help
+ Enter the GPIO pin number used for the SCL signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_I2C_SDA
+ int "GPIO pin used for SDA"
+ depends on SCx200_I2C
+ default "13"
+ help
+ Enter the GPIO pin number used for the SSA signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_ACB
+ tristate "Geode ACCESS.bus support"
+ depends on X86_32 && PCI
+ help
+ Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
+ SC1100 processors and the CS5535 and CS5536 Geode companion devices.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_acb.
+
+endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
new file mode 100644
index 00000000..e6cf294d
--- /dev/null
+++ b/drivers/i2c/busses/Makefile
@@ -0,0 +1,86 @@
+#
+# Makefile for the i2c bus drivers.
+#
+
+# ACPI drivers
+obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
+
+# PC SMBus host controller drivers
+obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
+obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
+obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
+obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
+obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
+obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
+obj-$(CONFIG_I2C_I801) += i2c-i801.o
+obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
+obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
+obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
+obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
+obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
+obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
+obj-$(CONFIG_I2C_VIA) += i2c-via.o
+obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
+
+# Mac SMBus host controller drivers
+obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+# Embedded system I2C/SMBus host controller drivers
+obj-$(CONFIG_I2C_AT91) += i2c-at91.o
+obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
+obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o
+obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
+obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
+obj-$(CONFIG_I2C_IMX) += i2c-imx.o
+obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o
+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_MXS) += i2c-mxs.o
+obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
+obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
+obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
+obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
+obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
+obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
+obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
+obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
+obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
+obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
+obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
+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_TEGRA) += i2c-tegra.o
+obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
+obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
+obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
+
+# External I2C/SMBus adapter drivers
+obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
+obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+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
+
+# Other I2C/SMBus bus drivers
+obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
+obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
+obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
new file mode 100644
index 00000000..86796488
--- /dev/null
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -0,0 +1,97 @@
+/*
+ * linux/drivers/acorn/char/i2c.c
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ * ARM IOC/IOMD i2c driver.
+ *
+ * On Acorn machines, the following i2c devices are on the bus:
+ * - PCF8583 real time clock & static RAM
+ */
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/ioc.h>
+#include <asm/system.h>
+
+#define FORCE_ONES 0xdc
+#define SCL 0x02
+#define SDA 0x01
+
+/*
+ * We must preserve all non-i2c output bits in IOC_CONTROL.
+ * Note also that we need to preserve the value of SCL and
+ * SDA outputs as well (which may be different from the
+ * values read back from IOC_CONTROL).
+ */
+static u_int force_ones;
+
+static void ioc_setscl(void *data, int state)
+{
+ u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+ u_int ones = force_ones;
+
+ if (state)
+ ones |= SCL;
+ else
+ ones &= ~SCL;
+
+ force_ones = ones;
+
+ ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static void ioc_setsda(void *data, int state)
+{
+ u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+ u_int ones = force_ones;
+
+ if (state)
+ ones |= SDA;
+ else
+ ones &= ~SDA;
+
+ force_ones = ones;
+
+ ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static int ioc_getscl(void *data)
+{
+ return (ioc_readb(IOC_CONTROL) & SCL) != 0;
+}
+
+static int ioc_getsda(void *data)
+{
+ return (ioc_readb(IOC_CONTROL) & SDA) != 0;
+}
+
+static struct i2c_algo_bit_data ioc_data = {
+ .setsda = ioc_setsda,
+ .setscl = ioc_setscl,
+ .getsda = ioc_getsda,
+ .getscl = ioc_getscl,
+ .udelay = 80,
+ .timeout = HZ,
+};
+
+static struct i2c_adapter ioc_ops = {
+ .nr = 0,
+ .algo_data = &ioc_data,
+};
+
+static int __init i2c_ioc_init(void)
+{
+ force_ones = FORCE_ONES | SCL | SDA;
+
+ return i2c_bit_add_numbered_bus(&ioc_ops);
+}
+
+module_init(i2c_ioc_init);
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
new file mode 100644
index 00000000..cd7ac5c6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -0,0 +1,540 @@
+/*
+ Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ Dan Eaton <dan.eaton@rocketlogix.com> and
+ Stephen Rousset<stephen.rousset@rocketlogix.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ This is the driver for the SMB Host controller on
+ Acer Labs Inc. (ALI) M1535 South Bridge.
+
+ The M1535 is a South bridge for portable systems.
+ It is very similar to the M15x3 South bridges also produced
+ by Acer Labs Inc. Some of the registers within the part
+ have moved and some have been redefined slightly. Additionally,
+ the sequencing of the SMBus transactions has been modified
+ to be more consistent with the sequencing recommended by
+ the manufacturer and observed through testing. These
+ changes are reflected in this driver and can be identified
+ by comparing this driver to the i2c-ali15x3 driver.
+ For an overview of these chips see http://www.acerlabs.com
+
+ The SMB controller is part of the 7101 device, which is an
+ ACPI-compliant Power Management Unit (PMU).
+
+ The whole 7101 device has to be enabled for the SMB to work.
+ You can't just enable the SMB alone.
+ The SMB and the ACPI have separate I/O spaces.
+ We make sure that the SMB is enabled. We leave the ACPI alone.
+
+ This driver controls the SMB Host only.
+
+ This driver does not use interrupts.
+*/
+
+
+/* Note: we assume there can only be one ALI1535, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/* ALI1535 SMBus address offsets */
+#define SMBHSTSTS (0 + ali1535_smba)
+#define SMBHSTTYP (1 + ali1535_smba)
+#define SMBHSTPORT (2 + ali1535_smba)
+#define SMBHSTCMD (7 + ali1535_smba)
+#define SMBHSTADD (3 + ali1535_smba)
+#define SMBHSTDAT0 (4 + ali1535_smba)
+#define SMBHSTDAT1 (5 + ali1535_smba)
+#define SMBBLKDAT (6 + ali1535_smba)
+
+/* PCI Address Constants */
+#define SMBCOM 0x004
+#define SMBREV 0x008
+#define SMBCFG 0x0D1
+#define SMBBA 0x0E2
+#define SMBHSTCFG 0x0F0
+#define SMBCLK 0x0F2
+
+/* Other settings */
+#define MAX_TIMEOUT 500 /* times 1/100 sec */
+#define ALI1535_SMB_IOSIZE 32
+
+#define ALI1535_SMB_DEFAULTBASE 0x8040
+
+/* ALI1535 address lock bits */
+#define ALI1535_LOCK 0x06 /* dwe */
+
+/* ALI1535 command constants */
+#define ALI1535_QUICK 0x00
+#define ALI1535_BYTE 0x10
+#define ALI1535_BYTE_DATA 0x20
+#define ALI1535_WORD_DATA 0x30
+#define ALI1535_BLOCK_DATA 0x40
+#define ALI1535_I2C_READ 0x60
+
+#define ALI1535_DEV10B_EN 0x80 /* Enable 10-bit addressing in */
+ /* I2C read */
+#define ALI1535_T_OUT 0x08 /* Time-out Command (write) */
+#define ALI1535_A_HIGH_BIT9 0x08 /* Bit 9 of 10-bit address in */
+ /* Alert-Response-Address */
+ /* (read) */
+#define ALI1535_KILL 0x04 /* Kill Command (write) */
+#define ALI1535_A_HIGH_BIT8 0x04 /* Bit 8 of 10-bit address in */
+ /* Alert-Response-Address */
+ /* (read) */
+
+#define ALI1535_D_HI_MASK 0x03 /* Mask for isolating bits 9-8 */
+ /* of 10-bit address in I2C */
+ /* Read Command */
+
+/* ALI1535 status register bits */
+#define ALI1535_STS_IDLE 0x04
+#define ALI1535_STS_BUSY 0x08 /* host busy */
+#define ALI1535_STS_DONE 0x10 /* transaction complete */
+#define ALI1535_STS_DEV 0x20 /* device error */
+#define ALI1535_STS_BUSERR 0x40 /* bus error */
+#define ALI1535_STS_FAIL 0x80 /* failed bus transaction */
+#define ALI1535_STS_ERR 0xE0 /* all the bad error bits */
+
+#define ALI1535_BLOCK_CLR 0x04 /* reset block data index */
+
+/* ALI1535 device address register bits */
+#define ALI1535_RD_ADDR 0x01 /* Read/Write Bit in Device */
+ /* Address field */
+ /* -> Write = 0 */
+ /* -> Read = 1 */
+#define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */
+
+static struct pci_driver ali1535_driver;
+static unsigned short ali1535_smba;
+
+/* Detect whether a ALI1535 can be found, and initialize it, where necessary.
+ 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 __devinit ali1535_setup(struct pci_dev *dev)
+{
+ int retval;
+ unsigned char temp;
+
+ /* Check the following things:
+ - SMB I/O address is initialized
+ - Device is enabled
+ - We can use the addresses
+ */
+
+ /* Determine the address of the SMBus area */
+ pci_read_config_word(dev, SMBBA, &ali1535_smba);
+ ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
+ if (ali1535_smba == 0) {
+ dev_warn(&dev->dev,
+ "ALI1535_smb region uninitialized - upgrade BIOS?\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
+ ali1535_driver.name);
+ if (retval)
+ goto exit;
+
+ if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
+ ali1535_driver.name)) {
+ dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n",
+ ali1535_smba);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ /* check if whole device is enabled */
+ pci_read_config_byte(dev, SMBCFG, &temp);
+ if ((temp & ALI1535_SMBIO_EN) == 0) {
+ dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
+ retval = -ENODEV;
+ goto exit_free;
+ }
+
+ /* Is SMB Host controller enabled? */
+ pci_read_config_byte(dev, SMBHSTCFG, &temp);
+ if ((temp & 1) == 0) {
+ dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
+ retval = -ENODEV;
+ goto exit_free;
+ }
+
+ /* set SMB clock to 74KHz as recommended in data sheet */
+ pci_write_config_byte(dev, SMBCLK, 0x20);
+
+ /*
+ The interrupt routing for SMB is set up in register 0x77 in the
+ 1533 ISA Bridge device, NOT in the 7101 device.
+ Don't bother with finding the 1533 device and reading the register.
+ if ((....... & 0x0F) == 1)
+ dev_dbg(&dev->dev, "ALI1535 using Interrupt 9 for SMBus.\n");
+ */
+ pci_read_config_byte(dev, SMBREV, &temp);
+ dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba);
+
+ return 0;
+
+exit_free:
+ release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+exit:
+ return retval;
+}
+
+static int ali1535_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, TYP=%02x, "
+ "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
+ inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+ /* get status */
+ temp = inb_p(SMBHSTSTS);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ /* Check the busy bit first */
+ if (temp & ALI1535_STS_BUSY) {
+ /* If the host controller is still busy, it may have timed out
+ * in the previous transaction, resulting in a "SMBus Timeout"
+ * printk. I've tried the following to reset a stuck busy bit.
+ * 1. Reset the controller with an KILL command. (this
+ * doesn't seem to clear the controller if an external
+ * device is hung)
+ * 2. Reset the controller and the other SMBus devices with a
+ * T_OUT command. (this clears the host busy bit if an
+ * external device is hung, but it comes back upon a new
+ * access to a device)
+ * 3. Disable and reenable the controller in SMBHSTCFG. Worst
+ * case, nothing seems to work except power reset.
+ */
+
+ /* Try resetting entire SMB bus, including other devices - This
+ * may not work either - it clears the BUSY bit but then the
+ * BUSY bit may come back on when you try and use the chip
+ * again. If that's the case you are stuck.
+ */
+ dev_info(&adap->dev,
+ "Resetting entire SMB Bus to clear busy condition (%02x)\n",
+ temp);
+ outb_p(ALI1535_T_OUT, SMBHSTTYP);
+ temp = inb_p(SMBHSTSTS);
+ }
+
+ /* now check the error bits and the busy bit */
+ if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+ /* do a clear-on-write */
+ outb_p(0xFF, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) &
+ (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+ /* This is probably going to be correctable only by a
+ * power reset as one of the bits now appears to be
+ * stuck */
+ /* This may be a bus or device with electrical problems. */
+ dev_err(&adap->dev,
+ "SMBus reset failed! (0x%02x) - controller or "
+ "device on bus is probably hung\n", temp);
+ return -EBUSY;
+ }
+ } else {
+ /* check and clear done bit */
+ if (temp & ALI1535_STS_DONE) {
+ outb_p(temp, SMBHSTSTS);
+ }
+ }
+
+ /* start the transaction by writing anything to the start register */
+ outb_p(0xFF, SMBHSTPORT);
+
+ /* We will always wait for a fraction of a second! */
+ timeout = 0;
+ do {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ } while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
+ && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ result = -ETIMEDOUT;
+ dev_err(&adap->dev, "SMBus Timeout!\n");
+ }
+
+ if (temp & ALI1535_STS_FAIL) {
+ result = -EIO;
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ }
+
+ /* Unfortunately the ALI SMB controller maps "no response" and "bus
+ * collision" into a single bit. No response is the usual case so don't
+ * do a printk. This means that bus collisions go unreported.
+ */
+ if (temp & ALI1535_STS_BUSERR) {
+ result = -ENXIO;
+ dev_dbg(&adap->dev,
+ "Error: no response or bus collision ADD=%02x\n",
+ inb_p(SMBHSTADD));
+ }
+
+ /* haven't ever seen this */
+ if (temp & ALI1535_STS_DEV) {
+ result = -EIO;
+ dev_err(&adap->dev, "Error: device error\n");
+ }
+
+ /* check to see if the "command complete" indication is set */
+ if (!(temp & ALI1535_STS_DONE)) {
+ result = -ETIMEDOUT;
+ dev_err(&adap->dev, "Error: command never completed\n");
+ }
+
+ dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, "
+ "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
+ inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+ /* take consequent actions for error conditions */
+ if (!(temp & ALI1535_STS_DONE)) {
+ /* issue "kill" to reset host controller */
+ outb_p(ALI1535_KILL,SMBHSTTYP);
+ outb_p(0xFF,SMBHSTSTS);
+ } else if (temp & ALI1535_STS_ERR) {
+ /* issue "timeout" to reset all devices on bus */
+ outb_p(ALI1535_T_OUT,SMBHSTTYP);
+ outb_p(0xFF,SMBHSTSTS);
+ }
+
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int i, len;
+ int temp;
+ int timeout;
+ s32 result = 0;
+
+ /* make sure SMBus is idle */
+ temp = inb_p(SMBHSTSTS);
+ for (timeout = 0;
+ (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
+ timeout++) {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ }
+ if (timeout >= MAX_TIMEOUT)
+ dev_warn(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+
+ /* clear status register (clear-on-write) */
+ outb_p(0xFF, SMBHSTSTS);
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_QUICK;
+ outb_p(size, SMBHSTTYP); /* output command */
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_BYTE;
+ outb_p(size, SMBHSTTYP); /* output command */
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_BYTE_DATA;
+ outb_p(size, SMBHSTTYP); /* output command */
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_WORD_DATA;
+ outb_p(size, SMBHSTTYP); /* output command */
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_BLOCK_DATA;
+ outb_p(size, SMBHSTTYP); /* output command */
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0) {
+ len = 0;
+ data->block[0] = len;
+ }
+ if (len > 32) {
+ len = 32;
+ data->block[0] = len;
+ }
+ outb_p(len, SMBHSTDAT0);
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ result = -EOPNOTSUPP;
+ goto EXIT;
+ }
+
+ result = ali1535_transaction(adap);
+ if (result)
+ goto EXIT;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK)) {
+ result = 0;
+ goto EXIT;
+ }
+
+ switch (size) {
+ case ALI1535_BYTE: /* Result put in SMBHSTDAT0 */
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI1535_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI1535_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case ALI1535_BLOCK_DATA:
+ len = inb_p(SMBHSTDAT0);
+ if (len > 32)
+ len = 32;
+ data->block[0] = len;
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
+ for (i = 1; i <= data->block[0]; i++) {
+ data->block[i] = inb_p(SMBBLKDAT);
+ dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+ len, i, data->block[i]);
+ }
+ break;
+ }
+EXIT:
+ return result;
+}
+
+
+static u32 ali1535_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ali1535_access,
+ .functionality = ali1535_func,
+};
+
+static struct i2c_adapter ali1535_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id ali1535_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+ { },
+};
+
+MODULE_DEVICE_TABLE (pci, ali1535_ids);
+
+static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if (ali1535_setup(dev)) {
+ dev_warn(&dev->dev,
+ "ALI1535 not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ ali1535_adapter.dev.parent = &dev->dev;
+
+ snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
+ "SMBus ALI1535 adapter at %04x", ali1535_smba);
+ return i2c_add_adapter(&ali1535_adapter);
+}
+
+static void __devexit ali1535_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&ali1535_adapter);
+ release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+}
+
+static struct pci_driver ali1535_driver = {
+ .name = "ali1535_smbus",
+ .id_table = ali1535_ids,
+ .probe = ali1535_probe,
+ .remove = __devexit_p(ali1535_remove),
+};
+
+static int __init i2c_ali1535_init(void)
+{
+ return pci_register_driver(&ali1535_driver);
+}
+
+static void __exit i2c_ali1535_exit(void)
+{
+ pci_unregister_driver(&ali1535_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "Mark D. Studebaker <mdsxyz123@yahoo.com> "
+ "and Dan Eaton <dan.eaton@rocketlogix.com>");
+MODULE_DESCRIPTION("ALI1535 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali1535_init);
+module_exit(i2c_ali1535_exit);
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
new file mode 100644
index 00000000..a409cfcf
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -0,0 +1,448 @@
+/**
+ * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
+ *
+ * Copyright (C) 2004 Patrick Mochel
+ * 2005 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * The 1563 southbridge is deceptively similar to the 1533, with a
+ * few notable exceptions. One of those happens to be the fact they
+ * upgraded the i2c core to be 2.0 compliant, and happens to be almost
+ * identical to the i2c controller found in the Intel 801 south
+ * bridges.
+ *
+ * This driver is based on a mix of the 15x3, 1535, and i801 drivers,
+ * with a little help from the ALi 1563 spec.
+ *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+#define ALI1563_MAX_TIMEOUT 500
+#define ALI1563_SMBBA 0x80
+#define ALI1563_SMB_IOEN 1
+#define ALI1563_SMB_HOSTEN 2
+#define ALI1563_SMB_IOSIZE 16
+
+#define SMB_HST_STS (ali1563_smba + 0)
+#define SMB_HST_CNTL1 (ali1563_smba + 1)
+#define SMB_HST_CNTL2 (ali1563_smba + 2)
+#define SMB_HST_CMD (ali1563_smba + 3)
+#define SMB_HST_ADD (ali1563_smba + 4)
+#define SMB_HST_DAT0 (ali1563_smba + 5)
+#define SMB_HST_DAT1 (ali1563_smba + 6)
+#define SMB_BLK_DAT (ali1563_smba + 7)
+
+#define HST_STS_BUSY 0x01
+#define HST_STS_INTR 0x02
+#define HST_STS_DEVERR 0x04
+#define HST_STS_BUSERR 0x08
+#define HST_STS_FAIL 0x10
+#define HST_STS_DONE 0x80
+#define HST_STS_BAD 0x1c
+
+
+#define HST_CNTL1_TIMEOUT 0x80
+#define HST_CNTL1_LAST 0x40
+
+#define HST_CNTL2_KILL 0x04
+#define HST_CNTL2_START 0x40
+#define HST_CNTL2_QUICK 0x00
+#define HST_CNTL2_BYTE 0x01
+#define HST_CNTL2_BYTE_DATA 0x02
+#define HST_CNTL2_WORD_DATA 0x03
+#define HST_CNTL2_BLOCK 0x05
+
+
+#define HST_CNTL2_SIZEMASK 0x38
+
+static struct pci_driver ali1563_pci_driver;
+static unsigned short ali1563_smba;
+
+static int ali1563_transaction(struct i2c_adapter * a, int size)
+{
+ u32 data;
+ int timeout;
+ int status = -EIO;
+
+ dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, "
+ "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD) {
+ dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
+ outb_p(data | HST_STS_BAD,SMB_HST_STS);
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD)
+ return -EBUSY;
+ }
+ outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
+
+ timeout = ALI1563_MAX_TIMEOUT;
+ do {
+ msleep(1);
+ } 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",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ if (timeout && !(data & HST_STS_BAD))
+ return 0;
+
+ if (!timeout) {
+ dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
+ /* Issue 'kill' to host controller */
+ outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
+ data = inb_p(SMB_HST_STS);
+ status = -ETIMEDOUT;
+ }
+
+ /* device error - no response, ignore the autodetection case */
+ if (data & HST_STS_DEVERR) {
+ if (size != HST_CNTL2_QUICK)
+ dev_err(&a->dev, "Device error!\n");
+ status = -ENXIO;
+ }
+ /* bus collision */
+ if (data & HST_STS_BUSERR) {
+ dev_err(&a->dev, "Bus collision!\n");
+ /* Issue timeout, hoping it helps */
+ outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1);
+ }
+
+ if (data & HST_STS_FAIL) {
+ dev_err(&a->dev, "Cleaning fail after KILL!\n");
+ outb_p(0x0,SMB_HST_CNTL2);
+ }
+
+ return status;
+}
+
+static int ali1563_block_start(struct i2c_adapter * a)
+{
+ u32 data;
+ int timeout;
+ int status = -EIO;
+
+ dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, "
+ "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD) {
+ dev_warn(&a->dev,"ali1563: Trying to reset busy device\n");
+ outb_p(data | HST_STS_BAD,SMB_HST_STS);
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD)
+ return -EBUSY;
+ }
+
+ /* Clear byte-ready bit */
+ outb_p(data | HST_STS_DONE, SMB_HST_STS);
+
+ /* Start transaction and wait for byte-ready bit to be set */
+ outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
+
+ timeout = ALI1563_MAX_TIMEOUT;
+ do {
+ msleep(1);
+ } 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",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ if (timeout && !(data & HST_STS_BAD))
+ return 0;
+
+ if (timeout == 0)
+ status = -ETIMEDOUT;
+
+ if (data & HST_STS_DEVERR)
+ status = -ENXIO;
+
+ dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
+ timeout ? "" : "Timeout ",
+ data & HST_STS_FAIL ? "Transaction Failed " : "",
+ data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
+ data & HST_STS_DEVERR ? "Device Error " : "",
+ !(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
+ return status;
+}
+
+static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw)
+{
+ int i, len;
+ int error = 0;
+
+ /* Do we need this? */
+ outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1);
+
+ if (rw == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 1)
+ len = 1;
+ else if (len > 32)
+ len = 32;
+ outb_p(len,SMB_HST_DAT0);
+ outb_p(data->block[1],SMB_BLK_DAT);
+ } else
+ len = 32;
+
+ outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2);
+
+ for (i = 0; i < len; i++) {
+ if (rw == I2C_SMBUS_WRITE) {
+ outb_p(data->block[i + 1], SMB_BLK_DAT);
+ if ((error = ali1563_block_start(a)))
+ break;
+ } else {
+ if ((error = ali1563_block_start(a)))
+ break;
+ if (i == 0) {
+ len = inb_p(SMB_HST_DAT0);
+ if (len < 1)
+ len = 1;
+ else if (len > 32)
+ len = 32;
+ }
+ data->block[i+1] = inb_p(SMB_BLK_DAT);
+ }
+ }
+ /* Do we need this? */
+ outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1);
+ return error;
+}
+
+static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data * data)
+{
+ int error = 0;
+ int timeout;
+ u32 reg;
+
+ for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) {
+ if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY))
+ break;
+ }
+ if (!timeout)
+ dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg);
+ outb_p(0xff,SMB_HST_STS);
+
+ /* Map the size to what the chip understands */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ size = HST_CNTL2_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ size = HST_CNTL2_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ size = HST_CNTL2_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ size = HST_CNTL2_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ size = HST_CNTL2_BLOCK;
+ break;
+ default:
+ dev_warn(&a->dev, "Unsupported transaction %d\n", size);
+ error = -EOPNOTSUPP;
+ goto Done;
+ }
+
+ outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
+ outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2);
+
+ /* Write the command register */
+
+ switch(size) {
+ case HST_CNTL2_BYTE:
+ if (rw== I2C_SMBUS_WRITE)
+ /* Beware it uses DAT0 register and not CMD! */
+ outb_p(cmd, SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_BYTE_DATA:
+ outb_p(cmd, SMB_HST_CMD);
+ if (rw == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_WORD_DATA:
+ outb_p(cmd, SMB_HST_CMD);
+ if (rw == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMB_HST_DAT0);
+ outb_p((data->word & 0xff00) >> 8, SMB_HST_DAT1);
+ }
+ break;
+ case HST_CNTL2_BLOCK:
+ outb_p(cmd, SMB_HST_CMD);
+ error = ali1563_block(a,data,rw);
+ goto Done;
+ }
+
+ if ((error = ali1563_transaction(a, size)))
+ goto Done;
+
+ if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
+ goto Done;
+
+ switch (size) {
+ case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */
+ data->byte = inb_p(SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_BYTE_DATA:
+ data->byte = inb_p(SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_WORD_DATA:
+ data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8);
+ break;
+ }
+Done:
+ return error;
+}
+
+static u32 ali1563_func(struct i2c_adapter * a)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+
+static int __devinit ali1563_setup(struct pci_dev * dev)
+{
+ u16 ctrl;
+
+ pci_read_config_word(dev,ALI1563_SMBBA,&ctrl);
+
+ /* SMB I/O Base in high 12 bits and must be aligned with the
+ * size of the I/O space. */
+ ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1);
+ if (!ali1563_smba) {
+ dev_warn(&dev->dev,"ali1563_smba Uninitialized\n");
+ goto Err;
+ }
+
+ /* Check if device is enabled */
+ if (!(ctrl & ALI1563_SMB_HOSTEN)) {
+ dev_warn(&dev->dev, "Host Controller not enabled\n");
+ goto Err;
+ }
+ if (!(ctrl & ALI1563_SMB_IOEN)) {
+ dev_warn(&dev->dev, "I/O space not enabled, trying manually\n");
+ pci_write_config_word(dev, ALI1563_SMBBA,
+ ctrl | ALI1563_SMB_IOEN);
+ pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
+ if (!(ctrl & ALI1563_SMB_IOEN)) {
+ dev_err(&dev->dev, "I/O space still not enabled, "
+ "giving up\n");
+ goto Err;
+ }
+ }
+
+ if (acpi_check_region(ali1563_smba, ALI1563_SMB_IOSIZE,
+ ali1563_pci_driver.name))
+ goto Err;
+
+ if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE,
+ ali1563_pci_driver.name)) {
+ dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n",
+ ali1563_smba);
+ goto Err;
+ }
+ dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n", ali1563_smba);
+
+ return 0;
+Err:
+ return -ENODEV;
+}
+
+static void ali1563_shutdown(struct pci_dev *dev)
+{
+ release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
+}
+
+static const struct i2c_algorithm ali1563_algorithm = {
+ .smbus_xfer = ali1563_access,
+ .functionality = ali1563_func,
+};
+
+static struct i2c_adapter ali1563_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &ali1563_algorithm,
+};
+
+static int __devinit ali1563_probe(struct pci_dev * dev,
+ const struct pci_device_id * id_table)
+{
+ int error;
+
+ if ((error = ali1563_setup(dev)))
+ goto exit;
+ ali1563_adapter.dev.parent = &dev->dev;
+ snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
+ "SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
+ if ((error = i2c_add_adapter(&ali1563_adapter)))
+ goto exit_shutdown;
+ return 0;
+
+exit_shutdown:
+ ali1563_shutdown(dev);
+exit:
+ dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n", error);
+ return error;
+}
+
+static void __devexit ali1563_remove(struct pci_dev * dev)
+{
+ i2c_del_adapter(&ali1563_adapter);
+ ali1563_shutdown(dev);
+}
+
+static const struct pci_device_id ali1563_id_table[] __devinitconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
+ {},
+};
+
+MODULE_DEVICE_TABLE (pci, ali1563_id_table);
+
+static struct pci_driver ali1563_pci_driver = {
+ .name = "ali1563_smbus",
+ .id_table = ali1563_id_table,
+ .probe = ali1563_probe,
+ .remove = __devexit_p(ali1563_remove),
+};
+
+static int __init ali1563_init(void)
+{
+ return pci_register_driver(&ali1563_pci_driver);
+}
+
+module_init(ali1563_init);
+
+static void __exit ali1563_exit(void)
+{
+ pci_unregister_driver(&ali1563_pci_driver);
+}
+
+module_exit(ali1563_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
new file mode 100644
index 00000000..83e8a60c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -0,0 +1,533 @@
+/*
+ Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com> and
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ This is the driver for the SMB Host controller on
+ Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
+
+ The M1543C is a South bridge for desktop systems.
+ The M1533 is a South bridge for portable systems.
+ They are part of the following ALI chipsets:
+ "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
+ with AGP and 100MHz CPU Front Side bus
+ "Aladdin V": Includes the M1541 Socket 7 North bridge
+ with AGP and 100MHz CPU Front Side bus
+ "Aladdin IV": Includes the M1541 Socket 7 North bridge
+ with host bus up to 83.3 MHz.
+ For an overview of these chips see http://www.acerlabs.com
+
+ The M1533/M1543C devices appear as FOUR separate devices
+ on the PCI bus. An output of lspci will show something similar
+ to the following:
+
+ 00:02.0 USB Controller: Acer Laboratories Inc. M5237
+ 00:03.0 Bridge: Acer Laboratories Inc. M7101
+ 00:07.0 ISA bridge: Acer Laboratories Inc. M1533
+ 00:0f.0 IDE interface: Acer Laboratories Inc. M5229
+
+ The SMB controller is part of the 7101 device, which is an
+ ACPI-compliant Power Management Unit (PMU).
+
+ The whole 7101 device has to be enabled for the SMB to work.
+ You can't just enable the SMB alone.
+ The SMB and the ACPI have separate I/O spaces.
+ We make sure that the SMB is enabled. We leave the ACPI alone.
+
+ This driver controls the SMB Host only.
+ The SMB Slave controller on the M15X3 is not enabled.
+
+ This driver does not use interrupts.
+*/
+
+/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* ALI15X3 SMBus address offsets */
+#define SMBHSTSTS (0 + ali15x3_smba)
+#define SMBHSTCNT (1 + ali15x3_smba)
+#define SMBHSTSTART (2 + ali15x3_smba)
+#define SMBHSTCMD (7 + ali15x3_smba)
+#define SMBHSTADD (3 + ali15x3_smba)
+#define SMBHSTDAT0 (4 + ali15x3_smba)
+#define SMBHSTDAT1 (5 + ali15x3_smba)
+#define SMBBLKDAT (6 + ali15x3_smba)
+
+/* PCI Address Constants */
+#define SMBCOM 0x004
+#define SMBBA 0x014
+#define SMBATPC 0x05B /* used to unlock xxxBA registers */
+#define SMBHSTCFG 0x0E0
+#define SMBSLVC 0x0E1
+#define SMBCLK 0x0E2
+#define SMBREV 0x008
+
+/* Other settings */
+#define MAX_TIMEOUT 200 /* times 1/100 sec */
+#define ALI15X3_SMB_IOSIZE 32
+
+/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
+ We don't use these here. If the bases aren't set to some value we
+ tell user to upgrade BIOS and we fail.
+*/
+#define ALI15X3_SMB_DEFAULTBASE 0xE800
+
+/* ALI15X3 address lock bits */
+#define ALI15X3_LOCK 0x06
+
+/* ALI15X3 command constants */
+#define ALI15X3_ABORT 0x02
+#define ALI15X3_T_OUT 0x04
+#define ALI15X3_QUICK 0x00
+#define ALI15X3_BYTE 0x10
+#define ALI15X3_BYTE_DATA 0x20
+#define ALI15X3_WORD_DATA 0x30
+#define ALI15X3_BLOCK_DATA 0x40
+#define ALI15X3_BLOCK_CLR 0x80
+
+/* ALI15X3 status register bits */
+#define ALI15X3_STS_IDLE 0x04
+#define ALI15X3_STS_BUSY 0x08
+#define ALI15X3_STS_DONE 0x10
+#define ALI15X3_STS_DEV 0x20 /* device error */
+#define ALI15X3_STS_COLL 0x40 /* collision or no response */
+#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
+#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
+
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the device at the given address. */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+ "Initialize the base address of the i2c controller");
+
+static struct pci_driver ali15x3_driver;
+static unsigned short ali15x3_smba;
+
+static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
+{
+ u16 a;
+ unsigned char temp;
+
+ /* Check the following things:
+ - SMB I/O address is initialized
+ - Device is enabled
+ - We can use the addresses
+ */
+
+ /* Unlock the register.
+ The data sheet says that the address registers are read-only
+ if the lock bits are 1, but in fact the address registers
+ are zero unless you clear the lock bits.
+ */
+ pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
+ if (temp & ALI15X3_LOCK) {
+ temp &= ~ALI15X3_LOCK;
+ pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
+ }
+
+ /* Determine the address of the SMBus area */
+ pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
+ ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
+ if (ali15x3_smba == 0 && force_addr == 0) {
+ dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
+ "- upgrade BIOS or use force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+
+ if(force_addr)
+ ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
+
+ if (acpi_check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
+ ali15x3_driver.name))
+ return -EBUSY;
+
+ if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
+ ali15x3_driver.name)) {
+ dev_err(&ALI15X3_dev->dev,
+ "ALI15X3_smb region 0x%x already in use!\n",
+ ali15x3_smba);
+ return -ENODEV;
+ }
+
+ if(force_addr) {
+ dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
+ ali15x3_smba);
+ if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev,
+ SMBBA,
+ ali15x3_smba))
+ goto error;
+ if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev,
+ SMBBA, &a))
+ goto error;
+ if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
+ /* make sure it works */
+ dev_err(&ALI15X3_dev->dev,
+ "force address failed - not supported?\n");
+ goto error;
+ }
+ }
+ /* check if whole device is enabled */
+ pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
+ if ((temp & 1) == 0) {
+ dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
+ pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
+ }
+
+ /* Is SMB Host controller enabled? */
+ pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
+ if ((temp & 1) == 0) {
+ dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
+ pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
+ }
+
+ /* set SMB clock to 74KHz as recommended in data sheet */
+ pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
+
+ /*
+ The interrupt routing for SMB is set up in register 0x77 in the
+ 1533 ISA Bridge device, NOT in the 7101 device.
+ Don't bother with finding the 1533 device and reading the register.
+ if ((....... & 0x0F) == 1)
+ dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
+ */
+ pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
+ dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
+
+ return 0;
+error:
+ release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+ return -ENODEV;
+}
+
+/* Another internally used function */
+static int ali15x3_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+ /* get status */
+ temp = inb_p(SMBHSTSTS);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ /* Check the busy bit first */
+ if (temp & ALI15X3_STS_BUSY) {
+ /*
+ If the host controller is still busy, it may have timed out in the
+ previous transaction, resulting in a "SMBus Timeout" Dev.
+ I've tried the following to reset a stuck busy bit.
+ 1. Reset the controller with an ABORT command.
+ (this doesn't seem to clear the controller if an external
+ device is hung)
+ 2. Reset the controller and the other SMBus devices with a
+ T_OUT command. (this clears the host busy bit if an
+ external device is hung, but it comes back upon a new access
+ to a device)
+ 3. Disable and reenable the controller in SMBHSTCFG
+ Worst case, nothing seems to work except power reset.
+ */
+ /* Abort - reset the host controller */
+ /*
+ Try resetting entire SMB bus, including other devices -
+ This may not work either - it clears the BUSY bit but
+ then the BUSY bit may come back on when you try and use the chip again.
+ If that's the case you are stuck.
+ */
+ dev_info(&adap->dev, "Resetting entire SMB Bus to "
+ "clear busy condition (%02x)\n", temp);
+ outb_p(ALI15X3_T_OUT, SMBHSTCNT);
+ temp = inb_p(SMBHSTSTS);
+ }
+
+ /* now check the error bits and the busy bit */
+ if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+ /* do a clear-on-write */
+ outb_p(0xFF, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) &
+ (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+ /* this is probably going to be correctable only by a power reset
+ as one of the bits now appears to be stuck */
+ /* This may be a bus or device with electrical problems. */
+ dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
+ "controller or device on bus is probably hung\n",
+ temp);
+ return -EBUSY;
+ }
+ } else {
+ /* check and clear done bit */
+ if (temp & ALI15X3_STS_DONE) {
+ outb_p(temp, SMBHSTSTS);
+ }
+ }
+
+ /* start the transaction by writing anything to the start register */
+ outb_p(0xFF, SMBHSTSTART);
+
+ /* We will always wait for a fraction of a second! */
+ timeout = 0;
+ do {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ } while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
+ && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ result = -ETIMEDOUT;
+ dev_err(&adap->dev, "SMBus Timeout!\n");
+ }
+
+ if (temp & ALI15X3_STS_TERM) {
+ result = -EIO;
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ }
+
+ /*
+ Unfortunately the ALI SMB controller maps "no response" and "bus
+ collision" into a single bit. No response is the usual case so don't
+ do a printk.
+ This means that bus collisions go unreported.
+ */
+ if (temp & ALI15X3_STS_COLL) {
+ result = -ENXIO;
+ dev_dbg(&adap->dev,
+ "Error: no response or bus collision ADD=%02x\n",
+ inb_p(SMBHSTADD));
+ }
+
+ /* haven't ever seen this */
+ if (temp & ALI15X3_STS_DEV) {
+ result = -EIO;
+ dev_err(&adap->dev, "Error: device error\n");
+ }
+ dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data * data)
+{
+ int i, len;
+ int temp;
+ int timeout;
+
+ /* clear all the bits (clear-on-write) */
+ outb_p(0xFF, SMBHSTSTS);
+ /* make sure SMBus is idle */
+ temp = inb_p(SMBHSTSTS);
+ for (timeout = 0;
+ (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
+ timeout++) {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ }
+ if (timeout >= MAX_TIMEOUT) {
+ dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+ }
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI15X3_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ size = ALI15X3_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ size = ALI15X3_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = ALI15X3_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0) {
+ len = 0;
+ data->block[0] = len;
+ }
+ if (len > 32) {
+ len = 32;
+ data->block[0] = len;
+ }
+ outb_p(len, SMBHSTDAT0);
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ size = ALI15X3_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ outb_p(size, SMBHSTCNT); /* output command */
+
+ temp = ali15x3_transaction(adap);
+ if (temp)
+ return temp;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
+ return 0;
+
+
+ switch (size) {
+ case ALI15X3_BYTE: /* Result put in SMBHSTDAT0 */
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI15X3_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI15X3_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case ALI15X3_BLOCK_DATA:
+ len = inb_p(SMBHSTDAT0);
+ if (len > 32)
+ len = 32;
+ data->block[0] = len;
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+ for (i = 1; i <= data->block[0]; i++) {
+ data->block[i] = inb_p(SMBBLKDAT);
+ dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+ len, i, data->block[i]);
+ }
+ break;
+ }
+ return 0;
+}
+
+static u32 ali15x3_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ali15x3_access,
+ .functionality = ali15x3_func,
+};
+
+static struct i2c_adapter ali15x3_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id ali15x3_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, ali15x3_ids);
+
+static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if (ali15x3_setup(dev)) {
+ dev_err(&dev->dev,
+ "ALI15X3 not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ ali15x3_adapter.dev.parent = &dev->dev;
+
+ snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
+ "SMBus ALI15X3 adapter at %04x", ali15x3_smba);
+ return i2c_add_adapter(&ali15x3_adapter);
+}
+
+static void __devexit ali15x3_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&ali15x3_adapter);
+ release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+}
+
+static struct pci_driver ali15x3_driver = {
+ .name = "ali15x3_smbus",
+ .id_table = ali15x3_ids,
+ .probe = ali15x3_probe,
+ .remove = __devexit_p(ali15x3_remove),
+};
+
+static int __init i2c_ali15x3_init(void)
+{
+ return pci_register_driver(&ali15x3_driver);
+}
+
+static void __exit i2c_ali15x3_exit(void)
+{
+ pci_unregister_driver(&ali15x3_driver);
+}
+
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("ALI15X3 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali15x3_init);
+module_exit(i2c_ali15x3_exit);
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
new file mode 100644
index 00000000..378fcb5d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -0,0 +1,262 @@
+/*
+ * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
+ *
+ * Copyright (C) 2004, 2008 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.
+ */
+
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4, and 0x4c (LM63)
+ * located on multiplexed channels 0 and 5-7. We define one
+ * virtual adapter per CPU, which corresponds to two multiplexed
+ * channels:
+ * CPU0: virtual adapter 1, channels 1 and 0
+ * CPU1: virtual adapter 2, channels 2 and 5
+ * CPU2: virtual adapter 3, channels 3 and 6
+ * CPU3: virtual adapter 4, channels 4 and 7
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+extern struct i2c_adapter amd756_smbus;
+
+static struct i2c_adapter *s4882_adapter;
+static struct i2c_algorithm *s4882_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static DEFINE_MUTEX(amd756_lock);
+
+static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ int error;
+
+ /* We exclude the multiplexed addresses */
+ if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+ || addr == 0x18)
+ return -ENXIO;
+
+ mutex_lock(&amd756_lock);
+
+ error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+
+ mutex_unlock(&amd756_lock);
+
+ return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+ channels when it is really needed. This greatly reduces the SMBus
+ overhead, but also assumes that nobody will be writing to the PCA9556
+ in our back. */
+static u8 last_channels;
+
+static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data,
+ u8 channels)
+{
+ int error;
+
+ /* We exclude the non-multiplexed addresses */
+ if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+ return -ENXIO;
+
+ mutex_lock(&amd756_lock);
+
+ if (last_channels != channels) {
+ union i2c_smbus_data mplxdata;
+ mplxdata.byte = channels;
+
+ error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
+ I2C_SMBUS_WRITE, 0x01,
+ I2C_SMBUS_BYTE_DATA,
+ &mplxdata);
+ if (error)
+ goto UNLOCK;
+ last_channels = channels;
+ }
+ error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+
+UNLOCK:
+ mutex_unlock(&amd756_lock);
+ return error;
+}
+
+static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU0: channels 1 and 0 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x03);
+}
+
+static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU1: channels 2 and 5 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x24);
+}
+
+static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU2: channels 3 and 6 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x48);
+}
+
+static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU3: channels 4 and 7 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x90);
+}
+
+static int __init amd756_s4882_init(void)
+{
+ int i, error;
+ union i2c_smbus_data ioconfig;
+
+ if (!amd756_smbus.dev.parent)
+ return -ENODEV;
+
+ /* Configure the PCA9556 multiplexer */
+ ioconfig.byte = 0x00; /* All I/O to output mode */
+ error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+ I2C_SMBUS_BYTE_DATA, &ioconfig);
+ if (error) {
+ dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
+ error = -EIO;
+ goto ERROR0;
+ }
+
+ /* Unregister physical bus */
+ error = i2c_del_adapter(&amd756_smbus);
+ if (error) {
+ dev_err(&amd756_smbus.dev, "Physical bus removal failed\n");
+ goto ERROR0;
+ }
+
+ printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
+ /* Define the 5 virtual adapters and algorithms structures */
+ if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter),
+ GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto ERROR1;
+ }
+ if (!(s4882_algo = kzalloc(5 * sizeof(struct i2c_algorithm),
+ GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto ERROR2;
+ }
+
+ /* Fill in the new structures */
+ s4882_algo[0] = *(amd756_smbus.algo);
+ s4882_algo[0].smbus_xfer = amd756_access_virt0;
+ s4882_adapter[0] = amd756_smbus;
+ s4882_adapter[0].algo = s4882_algo;
+ s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
+ for (i = 1; i < 5; i++) {
+ s4882_algo[i] = *(amd756_smbus.algo);
+ s4882_adapter[i] = amd756_smbus;
+ snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
+ "SMBus 8111 adapter (CPU%d)", i-1);
+ s4882_adapter[i].algo = s4882_algo+i;
+ s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
+ }
+ s4882_algo[1].smbus_xfer = amd756_access_virt1;
+ s4882_algo[2].smbus_xfer = amd756_access_virt2;
+ s4882_algo[3].smbus_xfer = amd756_access_virt3;
+ s4882_algo[4].smbus_xfer = amd756_access_virt4;
+
+ /* Register virtual adapters */
+ for (i = 0; i < 5; i++) {
+ error = i2c_add_adapter(s4882_adapter+i);
+ if (error) {
+ printk(KERN_ERR "i2c-amd756-s4882: "
+ "Virtual adapter %d registration "
+ "failed, module not inserted\n", i);
+ for (i--; i >= 0; i--)
+ i2c_del_adapter(s4882_adapter+i);
+ goto ERROR3;
+ }
+ }
+
+ return 0;
+
+ERROR3:
+ kfree(s4882_algo);
+ s4882_algo = NULL;
+ERROR2:
+ kfree(s4882_adapter);
+ s4882_adapter = NULL;
+ERROR1:
+ /* Restore physical bus */
+ i2c_add_adapter(&amd756_smbus);
+ERROR0:
+ return error;
+}
+
+static void __exit amd756_s4882_exit(void)
+{
+ if (s4882_adapter) {
+ int i;
+
+ for (i = 0; i < 5; i++)
+ i2c_del_adapter(s4882_adapter+i);
+ kfree(s4882_adapter);
+ s4882_adapter = NULL;
+ }
+ kfree(s4882_algo);
+ s4882_algo = NULL;
+
+ /* Restore physical bus */
+ if (i2c_add_adapter(&amd756_smbus))
+ printk(KERN_ERR "i2c-amd756-s4882: "
+ "Physical bus restoration failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("S4882 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(amd756_s4882_init);
+module_exit(amd756_s4882_exit);
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
new file mode 100644
index 00000000..03bcd07c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -0,0 +1,430 @@
+/*
+ Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
+
+ Shamelessly ripped from i2c-piix4.c:
+
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+*/
+
+/*
+ 2002-04-08: Added nForce support. (Csaba Halasz)
+ 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
+ 2002-12-28: Rewritten into something that resembles a Linux driver (hch)
+ 2003-11-29: Added back AMD8111 removed by the previous rewrite.
+ (Philip Pokorny)
+*/
+
+/*
+ Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* AMD756 SMBus address offsets */
+#define SMB_ADDR_OFFSET 0xE0
+#define SMB_IOSIZE 16
+#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport)
+#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport)
+#define SMB_HOST_ADDRESS (0x4 + amd756_ioport)
+#define SMB_HOST_DATA (0x6 + amd756_ioport)
+#define SMB_HOST_COMMAND (0x8 + amd756_ioport)
+#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport)
+#define SMB_HAS_DATA (0xA + amd756_ioport)
+#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
+#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport)
+#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport)
+
+/* PCI Address Constants */
+
+/* address of I/O space */
+#define SMBBA 0x058 /* mh */
+#define SMBBANFORCE 0x014
+
+/* general configuration */
+#define SMBGCFG 0x041 /* mh */
+
+/* silicon revision code */
+#define SMBREV 0x008
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* AMD756 constants */
+#define AMD756_QUICK 0x00
+#define AMD756_BYTE 0x01
+#define AMD756_BYTE_DATA 0x02
+#define AMD756_WORD_DATA 0x03
+#define AMD756_PROCESS_CALL 0x04
+#define AMD756_BLOCK_DATA 0x05
+
+static struct pci_driver amd756_driver;
+static unsigned short amd756_ioport;
+
+/*
+ SMBUS event = I/O 28-29 bit 11
+ see E0 for the status bits and enabled in E2
+
+*/
+#define GS_ABRT_STS (1 << 0)
+#define GS_COL_STS (1 << 1)
+#define GS_PRERR_STS (1 << 2)
+#define GS_HST_STS (1 << 3)
+#define GS_HCYC_STS (1 << 4)
+#define GS_TO_STS (1 << 5)
+#define GS_SMB_STS (1 << 11)
+
+#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
+ GS_HCYC_STS | GS_TO_STS )
+
+#define GE_CYC_TYPE_MASK (7)
+#define GE_HOST_STC (1 << 3)
+#define GE_ABORT (1 << 5)
+
+
+static int amd756_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
+ "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
+ inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
+ inb_p(SMB_HOST_DATA));
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
+ dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
+ do {
+ msleep(1);
+ temp = inw_p(SMB_GLOBAL_STATUS);
+ } while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
+ (timeout++ < MAX_TIMEOUT));
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
+ goto abort;
+ }
+ timeout = 0;
+ }
+
+ /* start the transaction by setting the start bit */
+ outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = inw_p(SMB_GLOBAL_STATUS);
+ } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "Completion timeout!\n");
+ goto abort;
+ }
+
+ if (temp & GS_PRERR_STS) {
+ result = -ENXIO;
+ dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
+ }
+
+ if (temp & GS_COL_STS) {
+ result = -EIO;
+ dev_warn(&adap->dev, "SMBus collision!\n");
+ }
+
+ if (temp & GS_TO_STS) {
+ result = -ETIMEDOUT;
+ dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
+ }
+
+ if (temp & GS_HCYC_STS)
+ dev_dbg(&adap->dev, "SMBus protocol success!\n");
+
+ outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+
+#ifdef DEBUG
+ if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
+ dev_dbg(&adap->dev,
+ "Failed reset at end of transaction (%04x)\n", temp);
+ }
+#endif
+
+ dev_dbg(&adap->dev,
+ "Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+ inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+ inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+
+ return result;
+
+ abort:
+ dev_warn(&adap->dev, "Sending abort\n");
+ outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
+ msleep(100);
+ outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+ return -EIO;
+}
+
+/* Return negative errno on error. */
+static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ int i, len;
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ size = AMD756_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMB_HOST_DATA);
+ size = AMD756_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ outb_p(command, SMB_HOST_COMMAND);
+ if (read_write == I2C_SMBUS_WRITE)
+ outw_p(data->byte, SMB_HOST_DATA);
+ size = AMD756_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ outb_p(command, SMB_HOST_COMMAND);
+ if (read_write == I2C_SMBUS_WRITE)
+ outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */
+ size = AMD756_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ outb_p(command, SMB_HOST_COMMAND);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0)
+ len = 0;
+ if (len > 32)
+ len = 32;
+ outw_p(len, SMB_HOST_DATA);
+ /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i],
+ SMB_HOST_BLOCK_DATA);
+ }
+ size = AMD756_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ /* How about enabling interrupts... */
+ outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
+
+ status = amd756_transaction(adap);
+ if (status)
+ return status;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
+ return 0;
+
+
+ switch (size) {
+ case AMD756_BYTE:
+ data->byte = inw_p(SMB_HOST_DATA);
+ break;
+ case AMD756_BYTE_DATA:
+ data->byte = inw_p(SMB_HOST_DATA);
+ break;
+ case AMD756_WORD_DATA:
+ data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */
+ break;
+ case AMD756_BLOCK_DATA:
+ data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
+ if(data->block[0] > 32)
+ data->block[0] = 32;
+ /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
+ break;
+ }
+
+ return 0;
+}
+
+static u32 amd756_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = amd756_access,
+ .functionality = amd756_func,
+};
+
+struct i2c_adapter amd756_smbus = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
+static const char* chipname[] = {
+ "AMD756", "AMD766", "AMD768",
+ "nVidia nForce", "AMD8111",
+};
+
+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),
+ .driver_data = AMD766 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443),
+ .driver_data = AMD768 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS),
+ .driver_data = AMD8111 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS),
+ .driver_data = NFORCE },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd756_ids);
+
+static int __devinit amd756_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int nforce = (id->driver_data == NFORCE);
+ int error;
+ u8 temp;
+
+ if (amd756_ioport) {
+ dev_err(&pdev->dev, "Only one device supported "
+ "(you have a strange motherboard, btw)\n");
+ return -ENODEV;
+ }
+
+ if (nforce) {
+ if (PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
+
+ pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
+ amd756_ioport &= 0xfffc;
+ } else { /* amd */
+ if (PCI_FUNC(pdev->devfn) != 3)
+ return -ENODEV;
+
+ pci_read_config_byte(pdev, SMBGCFG, &temp);
+ if ((temp & 128) == 0) {
+ dev_err(&pdev->dev,
+ "Error: SMBus controller I/O not enabled!\n");
+ return -ENODEV;
+ }
+
+ /* Determine the address of the SMBus areas */
+ /* Technically it is a dword but... */
+ pci_read_config_word(pdev, SMBBA, &amd756_ioport);
+ amd756_ioport &= 0xff00;
+ amd756_ioport += SMB_ADDR_OFFSET;
+ }
+
+ error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
+ amd756_driver.name);
+ if (error)
+ return -ENODEV;
+
+ if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
+ dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
+ amd756_ioport);
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(pdev, SMBREV, &temp);
+ dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
+
+ /* set up the sysfs linkage to our parent device */
+ amd756_smbus.dev.parent = &pdev->dev;
+
+ snprintf(amd756_smbus.name, sizeof(amd756_smbus.name),
+ "SMBus %s adapter at %04x", chipname[id->driver_data],
+ amd756_ioport);
+
+ error = i2c_add_adapter(&amd756_smbus);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Adapter registration failed, module not inserted\n");
+ goto out_err;
+ }
+
+ return 0;
+
+ out_err:
+ release_region(amd756_ioport, SMB_IOSIZE);
+ return error;
+}
+
+static void __devexit amd756_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&amd756_smbus);
+ release_region(amd756_ioport, SMB_IOSIZE);
+}
+
+static struct pci_driver amd756_driver = {
+ .name = "amd756_smbus",
+ .id_table = amd756_ids,
+ .probe = amd756_probe,
+ .remove = __devexit_p(amd756_remove),
+};
+
+static int __init amd756_init(void)
+{
+ return pci_register_driver(&amd756_driver);
+}
+
+static void __exit amd756_exit(void)
+{
+ pci_unregister_driver(&amd756_driver);
+}
+
+MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
+MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(amd756_smbus);
+
+module_init(amd756_init)
+module_exit(amd756_exit)
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
new file mode 100644
index 00000000..6b6a6b1d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -0,0 +1,505 @@
+/*
+ * SMBus 2.0 driver for AMD-8111 IO-Hub.
+ *
+ * Copyright (c) 2002 Vojtech Pavlik
+ *
+ * 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 version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver");
+
+struct amd_smbus {
+ struct pci_dev *dev;
+ struct i2c_adapter adapter;
+ int base;
+ int size;
+};
+
+static struct pci_driver amd8111_driver;
+
+/*
+ * AMD PCI control registers definitions.
+ */
+
+#define AMD_PCI_MISC 0x48
+
+#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */
+#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */
+#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */
+
+/*
+ * ACPI 2.0 chapter 13 PCI interface definitions.
+ */
+
+#define AMD_EC_DATA 0x00 /* data register */
+#define AMD_EC_SC 0x04 /* status of controller */
+#define AMD_EC_CMD 0x04 /* command register */
+#define AMD_EC_ICR 0x08 /* interrupt control register */
+
+#define AMD_EC_SC_SMI 0x04 /* smi event pending */
+#define AMD_EC_SC_SCI 0x02 /* sci event pending */
+#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */
+#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */
+#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */
+#define AMD_EC_SC_OBF 0x01 /* data ready for host */
+
+#define AMD_EC_CMD_RD 0x80 /* read EC */
+#define AMD_EC_CMD_WR 0x81 /* write EC */
+#define AMD_EC_CMD_BE 0x82 /* enable burst mode */
+#define AMD_EC_CMD_BD 0x83 /* disable burst mode */
+#define AMD_EC_CMD_QR 0x84 /* query EC */
+
+/*
+ * ACPI 2.0 chapter 13 access of registers of the EC
+ */
+
+static int amd_ec_wait_write(struct amd_smbus *smbus)
+{
+ int timeout = 500;
+
+ while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout)
+ udelay(1);
+
+ if (!timeout) {
+ dev_warn(&smbus->dev->dev,
+ "Timeout while waiting for IBF to clear\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int amd_ec_wait_read(struct amd_smbus *smbus)
+{
+ int timeout = 500;
+
+ while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout)
+ udelay(1);
+
+ if (!timeout) {
+ dev_warn(&smbus->dev->dev,
+ "Timeout while waiting for OBF to set\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
+ unsigned char *data)
+{
+ int status;
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(address, smbus->base + AMD_EC_DATA);
+
+ status = amd_ec_wait_read(smbus);
+ if (status)
+ return status;
+ *data = inb(smbus->base + AMD_EC_DATA);
+
+ return 0;
+}
+
+static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
+ unsigned char data)
+{
+ int status;
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(address, smbus->base + AMD_EC_DATA);
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(data, smbus->base + AMD_EC_DATA);
+
+ return 0;
+}
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+
+#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */
+#define AMD_SMB_STS 0x01 /* status */
+#define AMD_SMB_ADDR 0x02 /* address */
+#define AMD_SMB_CMD 0x03 /* command */
+#define AMD_SMB_DATA 0x04 /* 32 data registers */
+#define AMD_SMB_BCNT 0x24 /* number of data bytes */
+#define AMD_SMB_ALRM_A 0x25 /* alarm address */
+#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
+
+#define AMD_SMB_STS_DONE 0x80
+#define AMD_SMB_STS_ALRM 0x40
+#define AMD_SMB_STS_RES 0x20
+#define AMD_SMB_STS_STATUS 0x1f
+
+#define AMD_SMB_STATUS_OK 0x00
+#define AMD_SMB_STATUS_FAIL 0x07
+#define AMD_SMB_STATUS_DNAK 0x10
+#define AMD_SMB_STATUS_DERR 0x11
+#define AMD_SMB_STATUS_CMD_DENY 0x12
+#define AMD_SMB_STATUS_UNKNOWN 0x13
+#define AMD_SMB_STATUS_ACC_DENY 0x17
+#define AMD_SMB_STATUS_TIMEOUT 0x18
+#define AMD_SMB_STATUS_NOTSUP 0x19
+#define AMD_SMB_STATUS_BUSY 0x1A
+#define AMD_SMB_STATUS_PEC 0x1F
+
+#define AMD_SMB_PRTCL_WRITE 0x00
+#define AMD_SMB_PRTCL_READ 0x01
+#define AMD_SMB_PRTCL_QUICK 0x02
+#define AMD_SMB_PRTCL_BYTE 0x04
+#define AMD_SMB_PRTCL_BYTE_DATA 0x06
+#define AMD_SMB_PRTCL_WORD_DATA 0x08
+#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a
+#define AMD_SMB_PRTCL_PROC_CALL 0x0c
+#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
+#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
+#define AMD_SMB_PRTCL_PEC 0x80
+
+
+static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ struct amd_smbus *smbus = adap->algo_data;
+ unsigned char protocol, len, pec, temp[2];
+ int i, status;
+
+ protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ
+ : AMD_SMB_PRTCL_WRITE;
+ pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ protocol |= AMD_SMB_PRTCL_QUICK;
+ read_write = I2C_SMBUS_WRITE;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_CMD,
+ command);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->byte);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX);
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ for (i = 0; i < len; i++) {
+ status =
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
+ }
+ protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
+ break;
+
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE)
+ for (i = 0; i < len; i++) {
+ status =
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
+ break;
+
+ case I2C_SMBUS_PROC_CALL:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
+ if (status)
+ return status;
+ protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
+ read_write = I2C_SMBUS_READ;
+ break;
+
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX - 1);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ for (i = 0; i < len; i++) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
+ protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+ read_write = I2C_SMBUS_READ;
+ break;
+
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+ if (status)
+ return status;
+
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
+
+ if (~temp[0] & AMD_SMB_STS_DONE) {
+ udelay(500);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
+ }
+
+ if (~temp[0] & AMD_SMB_STS_DONE) {
+ msleep(1);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
+ }
+
+ if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
+ return -EIO;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+ if (status)
+ return status;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
+ if (status)
+ return status;
+ status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+ if (status)
+ return status;
+ data->word = (temp[1] << 8) | temp[0];
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+ if (status)
+ return status;
+ len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ for (i = 0; i < len; i++) {
+ status = amd_ec_read(smbus, AMD_SMB_DATA + i,
+ data->block + i + 1);
+ if (status)
+ return status;
+ }
+ data->block[0] = len;
+ break;
+ }
+
+ return 0;
+}
+
+
+static u32 amd8111_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = amd8111_access,
+ .functionality = amd8111_func,
+};
+
+
+static const struct pci_device_id amd8111_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd8111_ids);
+
+static int __devinit amd8111_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct amd_smbus *smbus;
+ int error;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+ return -ENODEV;
+
+ smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL);
+ if (!smbus)
+ return -ENOMEM;
+
+ smbus->dev = dev;
+ smbus->base = pci_resource_start(dev, 0);
+ smbus->size = pci_resource_len(dev, 0);
+
+ error = acpi_check_resource_conflict(&dev->resource[0]);
+ if (error) {
+ error = -ENODEV;
+ goto out_kfree;
+ }
+
+ if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
+ error = -EBUSY;
+ goto out_kfree;
+ }
+
+ smbus->adapter.owner = THIS_MODULE;
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+ "SMBus2 AMD8111 adapter at %04x", smbus->base);
+ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+
+ /* set up the sysfs linkage to our parent device */
+ smbus->adapter.dev.parent = &dev->dev;
+
+ pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
+ error = i2c_add_adapter(&smbus->adapter);
+ if (error)
+ goto out_release_region;
+
+ pci_set_drvdata(dev, smbus);
+ return 0;
+
+ out_release_region:
+ release_region(smbus->base, smbus->size);
+ out_kfree:
+ kfree(smbus);
+ return error;
+}
+
+static void __devexit amd8111_remove(struct pci_dev *dev)
+{
+ struct amd_smbus *smbus = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&smbus->adapter);
+ release_region(smbus->base, smbus->size);
+ kfree(smbus);
+}
+
+static struct pci_driver amd8111_driver = {
+ .name = "amd8111_smbus2",
+ .id_table = amd8111_ids,
+ .probe = amd8111_probe,
+ .remove = __devexit_p(amd8111_remove),
+};
+
+static int __init i2c_amd8111_init(void)
+{
+ return pci_register_driver(&amd8111_driver);
+}
+
+static void __exit i2c_amd8111_exit(void)
+{
+ pci_unregister_driver(&amd8111_driver);
+}
+
+module_init(i2c_amd8111_init);
+module_exit(i2c_amd8111_exit);
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 00000000..305c0750
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,327 @@
+/*
+ i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+
+ Copyright (C) 2004 Rick Bronson
+ Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+
+ Borrowed heavily from original work by:
+ Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/at91_twi.h>
+#include <mach/board.h>
+#include <mach/cpu.h>
+
+#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+
+
+static struct clk *twi_clk;
+static void __iomem *twi_base;
+
+#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
+#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+
+
+/*
+ * Initialize the TWI hardware registers.
+ */
+static void __devinit at91_twi_hwinit(void)
+{
+ unsigned long cdiv, ckdiv;
+
+ at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
+
+ /* Calcuate clock dividers */
+ cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+ cdiv = cdiv + 1; /* round up */
+ ckdiv = 0;
+ while (cdiv > 255) {
+ ckdiv++;
+ cdiv = cdiv >> 1;
+ }
+
+ if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
+ if (ckdiv > 5) {
+ printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+ ckdiv = 5;
+ }
+ }
+
+ at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+}
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short at91_poll_status(unsigned long bit)
+{
+ int loop_cntr = 10000;
+
+ do {
+ udelay(10);
+ } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+
+ return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ /* Read data */
+ while (length--) {
+ if (!length) /* need to send Stop before reading last byte */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+ if (!at91_poll_status(AT91_TWI_RXRDY)) {
+ dev_dbg(&adap->dev, "RXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+ *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+ }
+
+ return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Load first byte into transmitter */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ do {
+ if (!at91_poll_status(AT91_TWI_TXRDY)) {
+ dev_dbg(&adap->dev, "TXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ length--; /* byte was transmitted */
+
+ if (length > 0) /* more data to send? */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+ } while (length);
+
+ /* Send Stop */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ * Note: We do not use Atmel's feature of storing the "internal device address".
+ * Instead the "internal device address" has to be written using a separate
+ * i2c message.
+ * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+ */
+static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+ int i, ret;
+
+ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+
+ for (i = 0; i < num; i++) {
+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+ pmsg->flags & I2C_M_RD ? "read" : "writ",
+ pmsg->len, pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+ at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+ | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+ if (pmsg->len && pmsg->buf) { /* sanity check */
+ if (pmsg->flags & I2C_M_RD)
+ ret = xfer_read(adap, pmsg->buf, pmsg->len);
+ else
+ ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+ if (ret)
+ return ret;
+
+ /* Wait until transfer is finished */
+ if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+ dev_dbg(&adap->dev, "TXCOMP timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+ return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 at91_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm at91_algorithm = {
+ .master_xfer = at91_xfer,
+ .functionality = at91_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit at91_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct resource *res;
+ int rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
+ return -EBUSY;
+
+ twi_base = ioremap(res->start, resource_size(res));
+ if (!twi_base) {
+ rc = -ENOMEM;
+ goto fail0;
+ }
+
+ twi_clk = clk_get(NULL, "twi_clk");
+ if (IS_ERR(twi_clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ rc = -ENODEV;
+ goto fail1;
+ }
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "can't allocate inteface!\n");
+ rc = -ENOMEM;
+ goto fail2;
+ }
+ snprintf(adapter->name, sizeof(adapter->name), "AT91");
+ adapter->algo = &at91_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+ /* adapter->id == 0 ... only one TWI controller for now */
+
+ platform_set_drvdata(pdev, adapter);
+
+ clk_enable(twi_clk); /* enable peripheral clock */
+ at91_twi_hwinit(); /* initialize TWI controller */
+
+ rc = i2c_add_numbered_adapter(adapter);
+ if (rc) {
+ dev_err(&pdev->dev, "Adapter %s registration failed\n",
+ adapter->name);
+ goto fail3;
+ }
+
+ dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+ return 0;
+
+fail3:
+ platform_set_drvdata(pdev, NULL);
+ kfree(adapter);
+ clk_disable(twi_clk);
+fail2:
+ clk_put(twi_clk);
+fail1:
+ iounmap(twi_base);
+fail0:
+ release_mem_region(res->start, resource_size(res));
+
+ return rc;
+}
+
+static int __devexit at91_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct resource *res;
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(twi_base);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_disable(twi_clk); /* disable peripheral clock */
+ clk_put(twi_clk);
+
+ return rc;
+}
+
+#ifdef CONFIG_PM
+
+/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+
+static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ clk_disable(twi_clk);
+ return 0;
+}
+
+static int at91_i2c_resume(struct platform_device *pdev)
+{
+ return clk_enable(twi_clk);
+}
+
+#else
+#define at91_i2c_suspend NULL
+#define at91_i2c_resume NULL
+#endif
+
+/* work with "modprobe at91_i2c" from hotplugging or coldplugging */
+MODULE_ALIAS("platform:at91_i2c");
+
+static struct platform_driver at91_i2c_driver = {
+ .probe = at91_i2c_probe,
+ .remove = __devexit_p(at91_i2c_remove),
+ .suspend = at91_i2c_suspend,
+ .resume = at91_i2c_resume,
+ .driver = {
+ .name = "at91_i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_i2c_init(void)
+{
+ return platform_driver_register(&at91_i2c_driver);
+}
+
+static void __exit at91_i2c_exit(void)
+{
+ platform_driver_unregister(&at91_i2c_driver);
+}
+
+module_init(at91_i2c_init);
+module_exit(at91_i2c_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
new file mode 100644
index 00000000..532828bc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -0,0 +1,497 @@
+/*
+ * i2c-au1550.c: SMBus (i2c) adapter for Alchemy PSC interface
+ * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
+ *
+ * 2.6 port by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * The documentation describes this as an SMBus controller, but it doesn't
+ * understand any of the SMBus protocol in hardware. It's really an I2C
+ * controller that could emulate most of the SMBus in software.
+ *
+ * This is just a skeleton adapter to use with the Au1550 PSC
+ * algorithm. It was developed for the Pb1550, but will work with
+ * any Au1550 board that has a similar PSC configuration.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+struct i2c_au1550_data {
+ u32 psc_base;
+ int xfer_timeout;
+ int ack_timeout;
+ struct i2c_adapter adap;
+ struct resource *ioarea;
+};
+
+static int
+wait_xfer_done(struct i2c_au1550_data *adap)
+{
+ u32 stat;
+ int i;
+ volatile psc_smb_t *sp;
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ /* Wait for Tx Buffer Empty
+ */
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ stat = sp->psc_smbstat;
+ au_sync();
+ if ((stat & PSC_SMBSTAT_TE) != 0)
+ return 0;
+
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int
+wait_ack(struct i2c_au1550_data *adap)
+{
+ u32 stat;
+ volatile psc_smb_t *sp;
+
+ if (wait_xfer_done(adap))
+ return -ETIMEDOUT;
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ stat = sp->psc_smbevnt;
+ au_sync();
+
+ if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int
+wait_master_done(struct i2c_au1550_data *adap)
+{
+ u32 stat;
+ int i;
+ volatile psc_smb_t *sp;
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ /* Wait for Master Done.
+ */
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ stat = sp->psc_smbevnt;
+ au_sync();
+ if ((stat & PSC_SMBEVNT_MD) != 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int
+do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
+{
+ volatile psc_smb_t *sp;
+ u32 stat;
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ /* Reset the FIFOs, clear events.
+ */
+ stat = sp->psc_smbstat;
+ sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
+ au_sync();
+
+ if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
+ sp->psc_smbpcr = PSC_SMBPCR_DC;
+ au_sync();
+ do {
+ stat = sp->psc_smbpcr;
+ au_sync();
+ } while ((stat & PSC_SMBPCR_DC) != 0);
+ udelay(50);
+ }
+
+ /* Write out the i2c chip address and specify operation
+ */
+ addr <<= 1;
+ if (rd)
+ addr |= 1;
+
+ /* zero-byte xfers stop immediately */
+ if (q)
+ addr |= PSC_SMBTXRX_STP;
+
+ /* Put byte into fifo, start up master.
+ */
+ sp->psc_smbtxrx = addr;
+ au_sync();
+ sp->psc_smbpcr = PSC_SMBPCR_MS;
+ au_sync();
+ if (wait_ack(adap))
+ return -EIO;
+ return (q) ? wait_master_done(adap) : 0;
+}
+
+static u32
+wait_for_rx_byte(struct i2c_au1550_data *adap, u32 *ret_data)
+{
+ int j;
+ u32 data, stat;
+ volatile psc_smb_t *sp;
+
+ if (wait_xfer_done(adap))
+ return -EIO;
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ j = adap->xfer_timeout * 100;
+ do {
+ j--;
+ if (j <= 0)
+ return -EIO;
+
+ stat = sp->psc_smbstat;
+ au_sync();
+ if ((stat & PSC_SMBSTAT_RE) == 0)
+ j = 0;
+ else
+ udelay(1);
+ } while (j > 0);
+ data = sp->psc_smbtxrx;
+ au_sync();
+ *ret_data = data;
+
+ return 0;
+}
+
+static int
+i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+ u32 data;
+ volatile psc_smb_t *sp;
+
+ if (len == 0)
+ return 0;
+
+ /* A read is performed by stuffing the transmit fifo with
+ * zero bytes for timing, waiting for bytes to appear in the
+ * receive fifo, then reading the bytes.
+ */
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ i = 0;
+ while (i < (len-1)) {
+ sp->psc_smbtxrx = 0;
+ au_sync();
+ if (wait_for_rx_byte(adap, &data))
+ return -EIO;
+
+ buf[i] = data;
+ i++;
+ }
+
+ /* The last byte has to indicate transfer done.
+ */
+ sp->psc_smbtxrx = PSC_SMBTXRX_STP;
+ au_sync();
+ if (wait_master_done(adap))
+ return -EIO;
+
+ data = sp->psc_smbtxrx;
+ au_sync();
+ buf[i] = data;
+ return 0;
+}
+
+static int
+i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+ u32 data;
+ volatile psc_smb_t *sp;
+
+ if (len == 0)
+ return 0;
+
+ sp = (volatile psc_smb_t *)(adap->psc_base);
+
+ i = 0;
+ while (i < (len-1)) {
+ data = buf[i];
+ sp->psc_smbtxrx = data;
+ au_sync();
+ if (wait_ack(adap))
+ return -EIO;
+ i++;
+ }
+
+ /* The last byte has to indicate transfer done.
+ */
+ data = buf[i];
+ data |= PSC_SMBTXRX_STP;
+ sp->psc_smbtxrx = data;
+ au_sync();
+ if (wait_master_done(adap))
+ return -EIO;
+ return 0;
+}
+
+static int
+au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_au1550_data *adap = i2c_adap->algo_data;
+ volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base;
+ struct i2c_msg *p;
+ int i, err = 0;
+
+ sp->psc_ctrl = PSC_CTRL_ENABLE;
+ au_sync();
+
+ for (i = 0; !err && i < num; i++) {
+ p = &msgs[i];
+ err = do_address(adap, p->addr, p->flags & I2C_M_RD,
+ (p->len == 0));
+ if (err || !p->len)
+ continue;
+ if (p->flags & I2C_M_RD)
+ err = i2c_read(adap, p->buf, p->len);
+ else
+ err = i2c_write(adap, p->buf, p->len);
+ }
+
+ /* Return the number of messages processed, or the error code.
+ */
+ if (err == 0)
+ err = num;
+
+ sp->psc_ctrl = PSC_CTRL_SUSPEND;
+ au_sync();
+
+ return err;
+}
+
+static u32
+au1550_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm au1550_algo = {
+ .master_xfer = au1550_xfer,
+ .functionality = au1550_func,
+};
+
+static void i2c_au1550_setup(struct i2c_au1550_data *priv)
+{
+ volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
+ u32 stat;
+
+ sp->psc_ctrl = PSC_CTRL_DISABLE;
+ au_sync();
+ sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
+ sp->psc_smbcfg = 0;
+ au_sync();
+ sp->psc_ctrl = PSC_CTRL_ENABLE;
+ au_sync();
+ do {
+ stat = sp->psc_smbstat;
+ au_sync();
+ } while ((stat & PSC_SMBSTAT_SR) == 0);
+
+ sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 |
+ PSC_SMBCFG_DD_DISABLE);
+
+ /* Divide by 8 to get a 6.25 MHz clock. The later protocol
+ * timings are based on this clock.
+ */
+ sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
+ sp->psc_smbmsk = PSC_SMBMSK_ALLMASK;
+ au_sync();
+
+ /* Set the protocol timer values. See Table 71 in the
+ * Au1550 Data Book for standard timing values.
+ */
+ sp->psc_smbtmr = PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
+ PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
+ PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
+ PSC_SMBTMR_SET_CH(15);
+ au_sync();
+
+ sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE;
+ do {
+ stat = sp->psc_smbstat;
+ au_sync();
+ } while ((stat & PSC_SMBSTAT_SR) == 0);
+
+ sp->psc_ctrl = PSC_CTRL_SUSPEND;
+ au_sync();
+}
+
+static void i2c_au1550_disable(struct i2c_au1550_data *priv)
+{
+ volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
+
+ sp->psc_smbcfg = 0;
+ sp->psc_ctrl = PSC_CTRL_DISABLE;
+ au_sync();
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ * Prior to calling us, the 50MHz clock frequency and routing
+ * must have been set up for the PSC indicated by the adapter.
+ */
+static int __devinit
+i2c_au1550_probe(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv;
+ struct resource *r;
+ int ret;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ priv->ioarea = request_mem_region(r->start, resource_size(r),
+ pdev->name);
+ if (!priv->ioarea) {
+ ret = -EBUSY;
+ goto out_mem;
+ }
+
+ priv->psc_base = CKSEG1ADDR(r->start);
+ priv->xfer_timeout = 200;
+ priv->ack_timeout = 200;
+
+ priv->adap.nr = pdev->id;
+ priv->adap.algo = &au1550_algo;
+ priv->adap.algo_data = priv;
+ priv->adap.dev.parent = &pdev->dev;
+ strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
+
+ /* Now, set up the PSC for SMBus PIO mode.
+ */
+ i2c_au1550_setup(priv);
+
+ ret = i2c_add_numbered_adapter(&priv->adap);
+ if (ret == 0) {
+ platform_set_drvdata(pdev, priv);
+ return 0;
+ }
+
+ i2c_au1550_disable(priv);
+
+ release_resource(priv->ioarea);
+ kfree(priv->ioarea);
+out_mem:
+ kfree(priv);
+out:
+ return ret;
+}
+
+static int __devexit
+i2c_au1550_remove(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&priv->adap);
+ i2c_au1550_disable(priv);
+ release_resource(priv->ioarea);
+ kfree(priv->ioarea);
+ kfree(priv);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+
+ i2c_au1550_disable(priv);
+
+ return 0;
+}
+
+static int
+i2c_au1550_resume(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+
+ i2c_au1550_setup(priv);
+
+ return 0;
+}
+#else
+#define i2c_au1550_suspend NULL
+#define i2c_au1550_resume NULL
+#endif
+
+static struct platform_driver au1xpsc_smbus_driver = {
+ .driver = {
+ .name = "au1xpsc_smbus",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2c_au1550_probe,
+ .remove = __devexit_p(i2c_au1550_remove),
+ .suspend = i2c_au1550_suspend,
+ .resume = i2c_au1550_resume,
+};
+
+static int __init
+i2c_au1550_init(void)
+{
+ return platform_driver_register(&au1xpsc_smbus_driver);
+}
+
+static void __exit
+i2c_au1550_exit(void)
+{
+ platform_driver_unregister(&au1xpsc_smbus_driver);
+}
+
+MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
+MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:au1xpsc_smbus");
+
+module_init (i2c_au1550_init);
+module_exit (i2c_au1550_exit);
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
new file mode 100644
index 00000000..cbc98aea
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -0,0 +1,797 @@
+/*
+ * Blackfin On-Chip Two Wire Interface Driver
+ *
+ * Copyright 2005-2007 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#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>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/blackfin.h>
+#include <asm/portmux.h>
+#include <asm/irq.h>
+
+/* SMBus mode*/
+#define TWI_I2C_MODE_STANDARD 1
+#define TWI_I2C_MODE_STANDARDSUB 2
+#define TWI_I2C_MODE_COMBINED 3
+#define TWI_I2C_MODE_REPEAT 4
+
+struct bfin_twi_iface {
+ int irq;
+ spinlock_t lock;
+ char read_write;
+ u8 command;
+ u8 *transPtr;
+ int readNum;
+ int writeNum;
+ int cur_mode;
+ int manual_stop;
+ int result;
+ struct i2c_adapter adap;
+ struct completion complete;
+ struct i2c_msg *pmsg;
+ int msg_num;
+ int cur_msg;
+ u16 saved_clkdiv;
+ u16 saved_control;
+ void __iomem *regs_base;
+};
+
+
+#define DEFINE_TWI_REG(reg, off) \
+static inline u16 read_##reg(struct bfin_twi_iface *iface) \
+ { return bfin_read16(iface->regs_base + (off)); } \
+static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
+ { bfin_write16(iface->regs_base + (off), v); }
+
+DEFINE_TWI_REG(CLKDIV, 0x00)
+DEFINE_TWI_REG(CONTROL, 0x04)
+DEFINE_TWI_REG(SLAVE_CTL, 0x08)
+DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
+DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
+DEFINE_TWI_REG(MASTER_CTL, 0x14)
+DEFINE_TWI_REG(MASTER_STAT, 0x18)
+DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
+DEFINE_TWI_REG(INT_STAT, 0x20)
+DEFINE_TWI_REG(INT_MASK, 0x24)
+DEFINE_TWI_REG(FIFO_CTL, 0x28)
+DEFINE_TWI_REG(FIFO_STAT, 0x2C)
+DEFINE_TWI_REG(XMT_DATA8, 0x80)
+DEFINE_TWI_REG(XMT_DATA16, 0x84)
+DEFINE_TWI_REG(RCV_DATA8, 0x88)
+DEFINE_TWI_REG(RCV_DATA16, 0x8C)
+
+static const u16 pin_req[2][3] = {
+ {P_TWI0_SCL, P_TWI0_SDA, 0},
+ {P_TWI1_SCL, P_TWI1_SDA, 0},
+};
+
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
+ unsigned short twi_int_status)
+{
+ unsigned short mast_stat = read_MASTER_STAT(iface);
+
+ if (twi_int_status & XMTSERV) {
+ /* Transmit next data */
+ if (iface->writeNum > 0) {
+ SSYNC();
+ write_XMT_DATA8(iface, *(iface->transPtr++));
+ iface->writeNum--;
+ }
+ /* start receive immediately after complete sending in
+ * combine mode.
+ */
+ else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | MDIR | RSTART);
+ else if (iface->manual_stop)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg + 1 < iface->msg_num) {
+ if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | RSTART | MDIR);
+ else
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+ }
+ }
+ if (twi_int_status & RCVSERV) {
+ if (iface->readNum > 0) {
+ /* Receive next data */
+ *(iface->transPtr) = read_RCV_DATA8(iface);
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ /* Change combine mode into sub mode after
+ * read first data.
+ */
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ /* Get read number from first byte in block
+ * combine mode.
+ */
+ if (iface->readNum == 1 && iface->manual_stop)
+ iface->readNum = *iface->transPtr + 1;
+ }
+ iface->transPtr++;
+ iface->readNum--;
+ } else if (iface->manual_stop) {
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg + 1 < iface->msg_num) {
+ if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | RSTART | MDIR);
+ else
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+ }
+ }
+ if (twi_int_status & MERR) {
+ write_INT_MASK(iface, 0);
+ write_MASTER_STAT(iface, 0x3e);
+ write_MASTER_CTL(iface, 0);
+ iface->result = -EIO;
+
+ if (mast_stat & LOSTARB)
+ dev_dbg(&iface->adap.dev, "Lost Arbitration\n");
+ if (mast_stat & ANAK)
+ dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n");
+ if (mast_stat & DNAK)
+ dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n");
+ if (mast_stat & BUFRDERR)
+ dev_dbg(&iface->adap.dev, "Buffer Read Error\n");
+ if (mast_stat & BUFWRERR)
+ dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
+
+ /* Faulty slave devices, may drive SDA low after a transfer
+ * finishes. To release the bus this code generates up to 9
+ * extra clocks until SDA is released.
+ */
+
+ if (read_MASTER_STAT(iface) & SDASEN) {
+ int cnt = 9;
+ do {
+ write_MASTER_CTL(iface, SCLOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, 0);
+ udelay(6);
+ } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--);
+
+ write_MASTER_CTL(iface, SDAOVR | SCLOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, SDAOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, 0);
+ }
+
+ /* If it is a quick transfer, only address without data,
+ * not an err, return 1.
+ */
+ if (iface->cur_mode == TWI_I2C_MODE_STANDARD &&
+ iface->transPtr == NULL &&
+ (twi_int_status & MCOMP) && (mast_stat & DNAK))
+ iface->result = 1;
+
+ complete(&iface->complete);
+ return;
+ }
+ if (twi_int_status & MCOMP) {
+ if ((read_MASTER_CTL(iface) & MEN) == 0 &&
+ (iface->cur_mode == TWI_I2C_MODE_REPEAT ||
+ iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
+ iface->result = -1;
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
+ } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ if (iface->readNum == 0) {
+ /* set the read number to 1 and ask for manual
+ * stop in block combine mode
+ */
+ iface->readNum = 1;
+ iface->manual_stop = 1;
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | (0xff << 6));
+ } else {
+ /* set the readd number in other
+ * combine mode.
+ */
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) &
+ (~(0xff << 6))) |
+ (iface->readNum << 6));
+ }
+ /* remove restart bit and enable master receive */
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) & ~RSTART);
+ } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg+1 < iface->msg_num) {
+ iface->cur_msg++;
+ iface->transPtr = iface->pmsg[iface->cur_msg].buf;
+ iface->writeNum = iface->readNum =
+ iface->pmsg[iface->cur_msg].len;
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface,
+ iface->pmsg[iface->cur_msg].addr);
+ if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface,
+ *(iface->transPtr++));
+ iface->writeNum--;
+ }
+ }
+
+ if (iface->pmsg[iface->cur_msg].len <= 255)
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) &
+ (~(0xff << 6))) |
+ (iface->pmsg[iface->cur_msg].len << 6));
+ else {
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) |
+ (0xff << 6)));
+ iface->manual_stop = 1;
+ }
+ /* remove restart bit and enable master receive */
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) & ~RSTART);
+ } else {
+ iface->result = 1;
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
+ }
+ }
+ complete(&iface->complete);
+}
+
+/* Interrupt handler */
+static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
+{
+ struct bfin_twi_iface *iface = dev_id;
+ unsigned long flags;
+ unsigned short twi_int_status;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ while (1) {
+ twi_int_status = read_INT_STAT(iface);
+ if (!twi_int_status)
+ break;
+ /* Clear interrupt status */
+ write_INT_STAT(iface, twi_int_status);
+ bfin_twi_handle_interrupt(iface, twi_int_status);
+ SSYNC();
+ }
+ spin_unlock_irqrestore(&iface->lock, flags);
+ return IRQ_HANDLED;
+}
+
+/*
+ * One i2c master transfer
+ */
+static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ struct i2c_msg *pmsg;
+ int rc = 0;
+
+ if (!(read_CONTROL(iface) & TWI_ENA))
+ return -ENXIO;
+
+ while (read_MASTER_STAT(iface) & BUSBUSY)
+ yield();
+
+ iface->pmsg = msgs;
+ iface->msg_num = num;
+ iface->cur_msg = 0;
+
+ pmsg = &msgs[0];
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&adap->dev, "10 bits addr not supported!\n");
+ return -EINVAL;
+ }
+
+ iface->cur_mode = TWI_I2C_MODE_REPEAT;
+ iface->manual_stop = 0;
+ iface->transPtr = pmsg->buf;
+ iface->writeNum = iface->readNum = pmsg->len;
+ iface->result = 0;
+ init_completion(&(iface->complete));
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface, pmsg->addr);
+
+ /* FIFO Initiation. Data in FIFO should be
+ * discarded before start a new operation.
+ */
+ write_FIFO_CTL(iface, 0x3);
+ SSYNC();
+ write_FIFO_CTL(iface, 0);
+ SSYNC();
+
+ if (pmsg->flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface, *(iface->transPtr++));
+ iface->writeNum--;
+ SSYNC();
+ }
+ }
+
+ /* clear int stat */
+ write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
+
+ /* Interrupt mask . Enable XMT, RCV interrupt */
+ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();
+
+ if (pmsg->len <= 255)
+ write_MASTER_CTL(iface, pmsg->len << 6);
+ else {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ }
+
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ SSYNC();
+
+ while (!iface->result) {
+ if (!wait_for_completion_timeout(&iface->complete,
+ adap->timeout)) {
+ iface->result = -1;
+ dev_err(&adap->dev, "master transfer timeout\n");
+ }
+ }
+
+ if (iface->result == 1)
+ rc = iface->cur_msg + 1;
+ else
+ rc = iface->result;
+
+ return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ return bfin_twi_do_master_xfer(adap, msgs, num);
+}
+
+/*
+ * One I2C SMBus transfer
+ */
+int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ int rc = 0;
+
+ if (!(read_CONTROL(iface) & TWI_ENA))
+ return -ENXIO;
+
+ while (read_MASTER_STAT(iface) & BUSBUSY)
+ yield();
+
+ iface->writeNum = 0;
+ iface->readNum = 0;
+
+ /* Prepare datas & select mode */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ iface->transPtr = NULL;
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (data == NULL)
+ iface->transPtr = NULL;
+ else {
+ if (read_write == I2C_SMBUS_READ)
+ iface->readNum = 1;
+ else
+ iface->writeNum = 1;
+ iface->transPtr = &data->byte;
+ }
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = &data->byte;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ iface->writeNum = 2;
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 0;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = data->block[0] + 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = data->block;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = data->block[0];
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = data->block[0];
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = (u8 *)&data->block[1];
+ break;
+ default:
+ return -1;
+ }
+
+ iface->result = 0;
+ iface->manual_stop = 0;
+ iface->read_write = read_write;
+ iface->command = command;
+ init_completion(&(iface->complete));
+
+ /* FIFO Initiation. Data in FIFO should be discarded before
+ * start a new operation.
+ */
+ write_FIFO_CTL(iface, 0x3);
+ SSYNC();
+ write_FIFO_CTL(iface, 0);
+
+ /* clear int stat */
+ write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
+
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface, addr);
+ SSYNC();
+
+ switch (iface->cur_mode) {
+ case TWI_I2C_MODE_STANDARDSUB:
+ write_XMT_DATA8(iface, iface->command);
+ write_INT_MASK(iface, MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ if (iface->writeNum + 1 <= 255)
+ write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
+ else {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ }
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ case TWI_I2C_MODE_COMBINED:
+ write_XMT_DATA8(iface, iface->command);
+ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();
+
+ if (iface->writeNum > 0)
+ write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
+ else
+ write_MASTER_CTL(iface, 0x1 << 6);
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ default:
+ write_MASTER_CTL(iface, 0);
+ if (size != I2C_SMBUS_QUICK) {
+ /* Don't access xmit data register when this is a
+ * read operation.
+ */
+ if (iface->read_write != I2C_SMBUS_READ) {
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface,
+ *(iface->transPtr++));
+ if (iface->writeNum <= 255)
+ write_MASTER_CTL(iface,
+ iface->writeNum << 6);
+ else {
+ write_MASTER_CTL(iface,
+ 0xff << 6);
+ iface->manual_stop = 1;
+ }
+ iface->writeNum--;
+ } else {
+ write_XMT_DATA8(iface, iface->command);
+ write_MASTER_CTL(iface, 1 << 6);
+ }
+ } else {
+ if (iface->readNum > 0 && iface->readNum <= 255)
+ write_MASTER_CTL(iface,
+ iface->readNum << 6);
+ else if (iface->readNum > 255) {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ } else
+ break;
+ }
+ }
+ write_INT_MASK(iface, MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ break;
+ }
+ SSYNC();
+
+ while (!iface->result) {
+ if (!wait_for_completion_timeout(&iface->complete,
+ adap->timeout)) {
+ iface->result = -1;
+ dev_err(&adap->dev, "smbus transfer timeout\n");
+ }
+ }
+
+ rc = (iface->result >= 0) ? 0 : -1;
+
+ return rc;
+}
+
+/*
+ * Generic I2C SMBus transfer entrypoint
+ */
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ return bfin_twi_do_smbus_xfer(adap, addr, flags,
+ read_write, command, size, data);
+}
+
+/*
+ * Return what the adapter supports
+ */
+static u32 bfin_twi_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static struct i2c_algorithm bfin_twi_algorithm = {
+ .master_xfer = bfin_twi_master_xfer,
+ .smbus_xfer = bfin_twi_smbus_xfer,
+ .functionality = bfin_twi_functionality,
+};
+
+static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ iface->saved_clkdiv = read_CLKDIV(iface);
+ iface->saved_control = read_CONTROL(iface);
+
+ free_irq(iface->irq, iface);
+
+ /* Disable TWI */
+ write_CONTROL(iface, iface->saved_control & ~TWI_ENA);
+
+ return 0;
+}
+
+static int i2c_bfin_twi_resume(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ IRQF_DISABLED, pdev->name, iface);
+ if (rc) {
+ dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+ return -ENODEV;
+ }
+
+ /* Resume TWI interface clock as specified */
+ write_CLKDIV(iface, iface->saved_clkdiv);
+
+ /* Resume TWI */
+ write_CONTROL(iface, iface->saved_control);
+
+ return 0;
+}
+
+static int i2c_bfin_twi_probe(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface;
+ struct i2c_adapter *p_adap;
+ struct resource *res;
+ int rc;
+ unsigned int clkhilow;
+
+ iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
+ if (!iface) {
+ dev_err(&pdev->dev, "Cannot allocate memory\n");
+ rc = -ENOMEM;
+ goto out_error_nomem;
+ }
+
+ spin_lock_init(&(iface->lock));
+
+ /* Find and map our resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+ rc = -ENOENT;
+ goto out_error_get_res;
+ }
+
+ iface->regs_base = ioremap(res->start, resource_size(res));
+ if (iface->regs_base == NULL) {
+ dev_err(&pdev->dev, "Cannot map IO\n");
+ rc = -ENXIO;
+ goto out_error_ioremap;
+ }
+
+ iface->irq = platform_get_irq(pdev, 0);
+ if (iface->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ specified\n");
+ rc = -ENOENT;
+ goto out_error_no_irq;
+ }
+
+ p_adap = &iface->adap;
+ p_adap->nr = pdev->id;
+ strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
+ p_adap->algo = &bfin_twi_algorithm;
+ p_adap->algo_data = iface;
+ p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ p_adap->dev.parent = &pdev->dev;
+ p_adap->timeout = 5 * HZ;
+ p_adap->retries = 3;
+
+ rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
+ if (rc) {
+ dev_err(&pdev->dev, "Can't setup pin mux!\n");
+ goto out_error_pin_mux;
+ }
+
+ rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ IRQF_DISABLED, pdev->name, iface);
+ if (rc) {
+ dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+ rc = -ENODEV;
+ goto out_error_req_irq;
+ }
+
+ /* Set TWI internal clock as 10MHz */
+ 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 * 1000 / 20 = 250)
+ */
+ clkhilow = ((10 * 1000 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) + 1) / 2;
+
+ /* Set Twi interface clock as specified */
+ write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
+
+ /* Enable TWI */
+ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
+ SSYNC();
+
+ rc = i2c_add_numbered_adapter(p_adap);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Can't add i2c adapter!\n");
+ goto out_error_add_adapter;
+ }
+
+ platform_set_drvdata(pdev, iface);
+
+ dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+ "regs_base@%p\n", iface->regs_base);
+
+ return 0;
+
+out_error_add_adapter:
+ free_irq(iface->irq, iface);
+out_error_req_irq:
+out_error_no_irq:
+ peripheral_free_list(pin_req[pdev->id]);
+out_error_pin_mux:
+ iounmap(iface->regs_base);
+out_error_ioremap:
+out_error_get_res:
+ kfree(iface);
+out_error_nomem:
+ return rc;
+}
+
+static int i2c_bfin_twi_remove(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&(iface->adap));
+ free_irq(iface->irq, iface);
+ peripheral_free_list(pin_req[pdev->id]);
+ iounmap(iface->regs_base);
+ kfree(iface);
+
+ return 0;
+}
+
+static struct platform_driver i2c_bfin_twi_driver = {
+ .probe = i2c_bfin_twi_probe,
+ .remove = i2c_bfin_twi_remove,
+ .suspend = i2c_bfin_twi_suspend,
+ .resume = i2c_bfin_twi_resume,
+ .driver = {
+ .name = "i2c-bfin-twi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_bfin_twi_init(void)
+{
+ return platform_driver_register(&i2c_bfin_twi_driver);
+}
+
+static void __exit i2c_bfin_twi_exit(void)
+{
+ platform_driver_unregister(&i2c_bfin_twi_driver);
+}
+
+subsys_initcall(i2c_bfin_twi_init);
+module_exit(i2c_bfin_twi_exit);
+
+MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-bfin-twi");
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
new file mode 100644
index 00000000..3a20961b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -0,0 +1,745 @@
+/*
+ * Freescale CPM1/CPM2 I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * Parts from dbox2_i2c.c (cvs.tuxbox.org)
+ * (C) 2000-2001 Felix Domke (tmbinc@gmx.net), Gillem (htoa@gmx.net)
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ *
+ * Converted to of_platform_device. Renamed to i2c-cpm.c.
+ * (C) 2007,2008 Jochen Friedrich <jochen@scram.de>
+ *
+ * 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/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+
+/* Try to define this if you have an older CPU (earlier than rev D4) */
+/* However, better use a GPIO based bitbang driver in this case :/ */
+#undef I2C_CHIP_ERRATA
+
+#define CPM_MAX_READ 513
+#define CPM_MAXBD 4
+
+#define I2C_EB (0x10) /* Big endian mode */
+#define I2C_EB_CPM2 (0x30) /* Big endian mode, memory snoop */
+
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0))
+
+/* I2C parameter RAM. */
+struct i2c_ram {
+ ushort rbase; /* Rx Buffer descriptor base address */
+ ushort tbase; /* Tx Buffer descriptor base address */
+ u_char rfcr; /* Rx function code */
+ u_char tfcr; /* Tx function code */
+ ushort mrblr; /* Max receive buffer length */
+ uint rstate; /* Internal */
+ uint rdp; /* Internal */
+ ushort rbptr; /* Rx Buffer descriptor pointer */
+ ushort rbc; /* Internal */
+ uint rxtmp; /* Internal */
+ uint tstate; /* Internal */
+ uint tdp; /* Internal */
+ ushort tbptr; /* Tx Buffer descriptor pointer */
+ ushort tbc; /* Internal */
+ uint txtmp; /* Internal */
+ char res1[4]; /* Reserved */
+ ushort rpbase; /* Relocation pointer */
+ char res2[2]; /* Reserved */
+};
+
+#define I2COM_START 0x80
+#define I2COM_MASTER 0x01
+#define I2CER_TXE 0x10
+#define I2CER_BUSY 0x04
+#define I2CER_TXB 0x02
+#define I2CER_RXB 0x01
+#define I2MOD_EN 0x01
+
+/* I2C Registers */
+struct i2c_reg {
+ u8 i2mod;
+ u8 res1[3];
+ u8 i2add;
+ u8 res2[3];
+ u8 i2brg;
+ u8 res3[3];
+ u8 i2com;
+ u8 res4[3];
+ u8 i2cer;
+ u8 res5[3];
+ u8 i2cmr;
+};
+
+struct cpm_i2c {
+ char *base;
+ struct platform_device *ofdev;
+ struct i2c_adapter adap;
+ uint dp_addr;
+ int version; /* CPM1=1, CPM2=2 */
+ int irq;
+ int cp_command;
+ int freq;
+ struct i2c_reg __iomem *i2c_reg;
+ struct i2c_ram __iomem *i2c_ram;
+ u16 i2c_addr;
+ wait_queue_head_t i2c_wait;
+ cbd_t __iomem *tbase;
+ cbd_t __iomem *rbase;
+ u_char *txbuf[CPM_MAXBD];
+ u_char *rxbuf[CPM_MAXBD];
+ u32 txdma[CPM_MAXBD];
+ u32 rxdma[CPM_MAXBD];
+};
+
+static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
+{
+ struct cpm_i2c *cpm;
+ struct i2c_reg __iomem *i2c_reg;
+ struct i2c_adapter *adap = dev_id;
+ int i;
+
+ cpm = i2c_get_adapdata(dev_id);
+ i2c_reg = cpm->i2c_reg;
+
+ /* Clear interrupt. */
+ i = in_8(&i2c_reg->i2cer);
+ out_8(&i2c_reg->i2cer, i);
+
+ dev_dbg(&adap->dev, "Interrupt: %x\n", i);
+
+ wake_up(&cpm->i2c_wait);
+
+ return i ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void cpm_reset_i2c_params(struct cpm_i2c *cpm)
+{
+ struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+
+ /* Set up the I2C parameters in the parameter ram. */
+ out_be16(&i2c_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE);
+ out_be16(&i2c_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+ if (cpm->version == 1) {
+ out_8(&i2c_ram->tfcr, I2C_EB);
+ out_8(&i2c_ram->rfcr, I2C_EB);
+ } else {
+ out_8(&i2c_ram->tfcr, I2C_EB_CPM2);
+ out_8(&i2c_ram->rfcr, I2C_EB_CPM2);
+ }
+
+ out_be16(&i2c_ram->mrblr, CPM_MAX_READ);
+
+ out_be32(&i2c_ram->rstate, 0);
+ out_be32(&i2c_ram->rdp, 0);
+ out_be16(&i2c_ram->rbptr, 0);
+ out_be16(&i2c_ram->rbc, 0);
+ out_be32(&i2c_ram->rxtmp, 0);
+ out_be32(&i2c_ram->tstate, 0);
+ out_be32(&i2c_ram->tdp, 0);
+ out_be16(&i2c_ram->tbptr, 0);
+ out_be16(&i2c_ram->tbc, 0);
+ out_be32(&i2c_ram->txtmp, 0);
+}
+
+static void cpm_i2c_force_close(struct i2c_adapter *adap)
+{
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+ struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+
+ dev_dbg(&adap->dev, "cpm_i2c_force_close()\n");
+
+ cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD);
+
+ out_8(&i2c_reg->i2cmr, 0x00); /* Disable all interrupts */
+ out_8(&i2c_reg->i2cer, 0xff);
+}
+
+static void cpm_i2c_parse_message(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg, int num, int tx, int rx)
+{
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ u_char addr;
+ u_char *tb;
+ u_char *rb;
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+ tbdf = cpm->tbase + tx;
+ rbdf = cpm->rbase + rx;
+
+ addr = pmsg->addr << 1;
+ if (pmsg->flags & I2C_M_RD)
+ addr |= 1;
+
+ tb = cpm->txbuf[tx];
+ rb = cpm->rxbuf[rx];
+
+ /* Align read buffer */
+ rb = (u_char *) (((ulong) rb + 1) & ~1);
+
+ tb[0] = addr; /* Device address byte w/rw flag */
+
+ out_be16(&tbdf->cbd_datlen, pmsg->len + 1);
+ out_be16(&tbdf->cbd_sc, 0);
+
+ if (!(pmsg->flags & I2C_M_NOSTART))
+ setbits16(&tbdf->cbd_sc, BD_I2C_START);
+
+ if (tx + 1 == num)
+ setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP);
+
+ if (pmsg->flags & I2C_M_RD) {
+ /*
+ * To read, we need an empty buffer of the proper length.
+ * All that is used is the first byte for address, the remainder
+ * is just used for timing (and doesn't really have to exist).
+ */
+
+ dev_dbg(&adap->dev, "cpm_i2c_read(abyte=0x%x)\n", addr);
+
+ out_be16(&rbdf->cbd_datlen, 0);
+ out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
+
+ if (rx + 1 == CPM_MAXBD)
+ setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
+
+ eieio();
+ setbits16(&tbdf->cbd_sc, BD_SC_READY);
+ } else {
+ dev_dbg(&adap->dev, "cpm_i2c_write(abyte=0x%x)\n", addr);
+
+ memcpy(tb+1, pmsg->buf, pmsg->len);
+
+ eieio();
+ setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT);
+ }
+}
+
+static int cpm_i2c_check_message(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg, int tx, int rx)
+{
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ u_char *tb;
+ u_char *rb;
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+ tbdf = cpm->tbase + tx;
+ rbdf = cpm->rbase + rx;
+
+ tb = cpm->txbuf[tx];
+ rb = cpm->rxbuf[rx];
+
+ /* Align read buffer */
+ rb = (u_char *) (((uint) rb + 1) & ~1);
+
+ eieio();
+ if (pmsg->flags & I2C_M_RD) {
+ dev_dbg(&adap->dev, "tx sc 0x%04x, rx sc 0x%04x\n",
+ in_be16(&tbdf->cbd_sc), in_be16(&rbdf->cbd_sc));
+
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+ dev_dbg(&adap->dev, "I2C read; No ack\n");
+ return -ENXIO;
+ }
+ if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) {
+ dev_err(&adap->dev,
+ "I2C read; complete but rbuf empty\n");
+ return -EREMOTEIO;
+ }
+ if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) {
+ dev_err(&adap->dev, "I2C read; Overrun\n");
+ return -EREMOTEIO;
+ }
+ memcpy(pmsg->buf, rb, pmsg->len);
+ } else {
+ dev_dbg(&adap->dev, "tx sc %d 0x%04x\n", tx,
+ in_be16(&tbdf->cbd_sc));
+
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+ dev_dbg(&adap->dev, "I2C write; No ack\n");
+ return -ENXIO;
+ }
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
+ dev_err(&adap->dev, "I2C write; Underrun\n");
+ return -EIO;
+ }
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
+ dev_err(&adap->dev, "I2C write; Collision\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+ struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+ struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+ struct i2c_msg *pmsg;
+ int ret, i;
+ int tptr;
+ int rptr;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+
+ if (num > CPM_MAXBD)
+ return -EINVAL;
+
+ /* Check if we have any oversized READ requests */
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ if (pmsg->len >= CPM_MAX_READ)
+ return -EINVAL;
+ }
+
+ /* Reset to use first buffer */
+ out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
+ out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ tptr = 0;
+ rptr = 0;
+
+ while (tptr < num) {
+ pmsg = &msgs[tptr];
+ dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);
+
+ cpm_i2c_parse_message(adap, pmsg, num, tptr, rptr);
+ if (pmsg->flags & I2C_M_RD)
+ rptr++;
+ tptr++;
+ }
+ /* Start transfer now */
+ /* Enable RX/TX/Error interupts */
+ out_8(&i2c_reg->i2cmr, I2CER_TXE | I2CER_TXB | I2CER_RXB);
+ out_8(&i2c_reg->i2cer, 0xff); /* Clear interrupt status */
+ /* Chip bug, set enable here */
+ setbits8(&i2c_reg->i2mod, I2MOD_EN); /* Enable */
+ /* Begin transmission */
+ setbits8(&i2c_reg->i2com, I2COM_START);
+
+ tptr = 0;
+ rptr = 0;
+
+ while (tptr < num) {
+ /* Check for outstanding messages */
+ dev_dbg(&adap->dev, "test ready.\n");
+ pmsg = &msgs[tptr];
+ if (pmsg->flags & I2C_M_RD)
+ ret = wait_event_timeout(cpm->i2c_wait,
+ (in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) ||
+ !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY),
+ 1 * HZ);
+ else
+ ret = wait_event_timeout(cpm->i2c_wait,
+ !(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY),
+ 1 * HZ);
+ if (ret == 0) {
+ ret = -EREMOTEIO;
+ dev_err(&adap->dev, "I2C transfer: timeout\n");
+ goto out_err;
+ }
+ if (ret > 0) {
+ dev_dbg(&adap->dev, "ready.\n");
+ ret = cpm_i2c_check_message(adap, pmsg, tptr, rptr);
+ tptr++;
+ if (pmsg->flags & I2C_M_RD)
+ rptr++;
+ if (ret)
+ goto out_err;
+ }
+ }
+#ifdef I2C_CHIP_ERRATA
+ /*
+ * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+ * Disabling I2C too early may cause too short stop condition
+ */
+ udelay(4);
+ clrbits8(&i2c_reg->i2mod, I2MOD_EN);
+#endif
+ return (num);
+
+out_err:
+ cpm_i2c_force_close(adap);
+#ifdef I2C_CHIP_ERRATA
+ /*
+ * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+ */
+ clrbits8(&i2c_reg->i2mod, I2MOD_EN);
+#endif
+ return ret;
+}
+
+static u32 cpm_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm cpm_i2c_algo = {
+ .master_xfer = cpm_i2c_xfer,
+ .functionality = cpm_i2c_func,
+};
+
+static const struct i2c_adapter cpm_ops = {
+ .owner = THIS_MODULE,
+ .name = "i2c-cpm",
+ .algo = &cpm_i2c_algo,
+};
+
+static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
+{
+ struct platform_device *ofdev = cpm->ofdev;
+ const u32 *data;
+ int len, ret, i;
+ void __iomem *i2c_base;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ unsigned char brg;
+
+ dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n");
+
+ init_waitqueue_head(&cpm->i2c_wait);
+
+ cpm->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+ if (!cpm->irq)
+ return -EINVAL;
+
+ /* Install interrupt handler. */
+ ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c",
+ &cpm->adap);
+ if (ret)
+ return ret;
+
+ /* I2C parameter RAM */
+ i2c_base = of_iomap(ofdev->dev.of_node, 1);
+ if (i2c_base == NULL) {
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm1-i2c")) {
+
+ /* Check for and use a microcode relocation patch. */
+ cpm->i2c_ram = i2c_base;
+ cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase);
+
+ /*
+ * Maybe should use cpm_muram_alloc instead of hardcoding
+ * this in micropatch.c
+ */
+ if (cpm->i2c_addr) {
+ cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+ iounmap(i2c_base);
+ }
+
+ cpm->version = 1;
+
+ } else if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm2-i2c")) {
+ cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
+ cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+ out_be16(i2c_base, cpm->i2c_addr);
+ iounmap(i2c_base);
+
+ cpm->version = 2;
+
+ } else {
+ iounmap(i2c_base);
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ /* I2C control/status registers */
+ cpm->i2c_reg = of_iomap(ofdev->dev.of_node, 0);
+ if (cpm->i2c_reg == NULL) {
+ ret = -EINVAL;
+ goto out_ram;
+ }
+
+ data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
+ if (!data || len != 4) {
+ ret = -EINVAL;
+ goto out_reg;
+ }
+ cpm->cp_command = *data;
+
+ data = of_get_property(ofdev->dev.of_node, "linux,i2c-class", &len);
+ if (data && len == 4)
+ cpm->adap.class = *data;
+
+ data = of_get_property(ofdev->dev.of_node, "clock-frequency", &len);
+ if (data && len == 4)
+ cpm->freq = *data;
+ else
+ cpm->freq = 60000; /* use 60kHz i2c clock by default */
+
+ /*
+ * Allocate space for CPM_MAXBD transmit and receive buffer
+ * descriptors in the DP ram.
+ */
+ cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
+ if (!cpm->dp_addr) {
+ ret = -ENOMEM;
+ goto out_reg;
+ }
+
+ cpm->tbase = cpm_muram_addr(cpm->dp_addr);
+ cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
+
+ /* Allocate TX and RX buffers */
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ for (i = 0; i < CPM_MAXBD; i++) {
+ cpm->rxbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
+ CPM_MAX_READ + 1,
+ &cpm->rxdma[i], GFP_KERNEL);
+ if (!cpm->rxbuf[i]) {
+ ret = -ENOMEM;
+ goto out_muram;
+ }
+ out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
+
+ cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+ if (!cpm->txbuf[i]) {
+ ret = -ENOMEM;
+ goto out_muram;
+ }
+ out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
+ }
+
+ /* Initialize Tx/Rx parameters. */
+
+ cpm_reset_i2c_params(cpm);
+
+ dev_dbg(&cpm->ofdev->dev, "i2c_ram 0x%p, i2c_addr 0x%04x, freq %d\n",
+ cpm->i2c_ram, cpm->i2c_addr, cpm->freq);
+ dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
+ (u8 __iomem *)cpm->tbase - DPRAM_BASE,
+ (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+ cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);
+
+ /*
+ * Select an invalid address. Just make sure we don't use loopback mode
+ */
+ out_8(&cpm->i2c_reg->i2add, 0x7f << 1);
+
+ /*
+ * PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the
+ * i2c baud rate generator. This is divided by 2 x (DIV + 3) to get
+ * the actual i2c bus frequency.
+ */
+ brg = get_brgfreq() / (32 * 2 * cpm->freq) - 3;
+ out_8(&cpm->i2c_reg->i2brg, brg);
+
+ out_8(&cpm->i2c_reg->i2mod, 0x00);
+ out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); /* Master mode */
+
+ /* Disable interrupts. */
+ out_8(&cpm->i2c_reg->i2cmr, 0);
+ out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+ return 0;
+
+out_muram:
+ for (i = 0; i < CPM_MAXBD; i++) {
+ if (cpm->rxbuf[i])
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->rxbuf[i], cpm->rxdma[i]);
+ if (cpm->txbuf[i])
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->txbuf[i], cpm->txdma[i]);
+ }
+ cpm_muram_free(cpm->dp_addr);
+out_reg:
+ iounmap(cpm->i2c_reg);
+out_ram:
+ if ((cpm->version == 1) && (!cpm->i2c_addr))
+ iounmap(cpm->i2c_ram);
+ if (cpm->version == 2)
+ cpm_muram_free(cpm->i2c_addr);
+out_irq:
+ free_irq(cpm->irq, &cpm->adap);
+ return ret;
+}
+
+static void cpm_i2c_shutdown(struct cpm_i2c *cpm)
+{
+ int i;
+
+ /* Shut down I2C. */
+ clrbits8(&cpm->i2c_reg->i2mod, I2MOD_EN);
+
+ /* Disable interrupts */
+ out_8(&cpm->i2c_reg->i2cmr, 0);
+ out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+ free_irq(cpm->irq, &cpm->adap);
+
+ /* Free all memory */
+ for (i = 0; i < CPM_MAXBD; i++) {
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->rxbuf[i], cpm->rxdma[i]);
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->txbuf[i], cpm->txdma[i]);
+ }
+
+ cpm_muram_free(cpm->dp_addr);
+ iounmap(cpm->i2c_reg);
+
+ if ((cpm->version == 1) && (!cpm->i2c_addr))
+ iounmap(cpm->i2c_ram);
+ if (cpm->version == 2)
+ cpm_muram_free(cpm->i2c_addr);
+}
+
+static int __devinit cpm_i2c_probe(struct platform_device *ofdev)
+{
+ int result, len;
+ struct cpm_i2c *cpm;
+ const u32 *data;
+
+ cpm = kzalloc(sizeof(struct cpm_i2c), GFP_KERNEL);
+ if (!cpm)
+ return -ENOMEM;
+
+ cpm->ofdev = ofdev;
+
+ dev_set_drvdata(&ofdev->dev, cpm);
+
+ cpm->adap = cpm_ops;
+ i2c_set_adapdata(&cpm->adap, cpm);
+ cpm->adap.dev.parent = &ofdev->dev;
+ cpm->adap.dev.of_node = of_node_get(ofdev->dev.of_node);
+
+ result = cpm_i2c_setup(cpm);
+ if (result) {
+ dev_err(&ofdev->dev, "Unable to init hardware\n");
+ goto out_free;
+ }
+
+ /* register new adapter to i2c module... */
+
+ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len);
+ if (data && len == 4) {
+ cpm->adap.nr = *data;
+ result = i2c_add_numbered_adapter(&cpm->adap);
+ } else
+ result = i2c_add_adapter(&cpm->adap);
+
+ if (result < 0) {
+ dev_err(&ofdev->dev, "Unable to register with I2C\n");
+ goto out_shut;
+ }
+
+ dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
+ cpm->adap.name);
+
+ /*
+ * register OF I2C devices
+ */
+ of_i2c_register_devices(&cpm->adap);
+
+ return 0;
+out_shut:
+ cpm_i2c_shutdown(cpm);
+out_free:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(cpm);
+
+ return result;
+}
+
+static int __devexit cpm_i2c_remove(struct platform_device *ofdev)
+{
+ struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
+
+ i2c_del_adapter(&cpm->adap);
+
+ cpm_i2c_shutdown(cpm);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(cpm);
+
+ return 0;
+}
+
+static const struct of_device_id cpm_i2c_match[] = {
+ {
+ .compatible = "fsl,cpm1-i2c",
+ },
+ {
+ .compatible = "fsl,cpm2-i2c",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, cpm_i2c_match);
+
+static struct platform_driver cpm_i2c_driver = {
+ .probe = cpm_i2c_probe,
+ .remove = __devexit_p(cpm_i2c_remove),
+ .driver = {
+ .name = "fsl-i2c-cpm",
+ .owner = THIS_MODULE,
+ .of_match_table = cpm_i2c_match,
+ },
+};
+
+static int __init cpm_i2c_init(void)
+{
+ return platform_driver_register(&cpm_i2c_driver);
+}
+
+static void __exit cpm_i2c_exit(void)
+{
+ platform_driver_unregister(&cpm_i2c_driver);
+}
+
+module_init(cpm_i2c_init);
+module_exit(cpm_i2c_exit);
+
+MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 00000000..79b4bcb3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,830 @@
+/*
+ * TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ *
+ * Updated by Vinod & Sudhakar Feb 2005
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define DAVINCI_I2C_MAX_TRIES 2
+#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \
+ DAVINCI_I2C_IMR_SCD | \
+ DAVINCI_I2C_IMR_ARDY | \
+ DAVINCI_I2C_IMR_NACK | \
+ DAVINCI_I2C_IMR_AL)
+
+#define DAVINCI_I2C_OAR_REG 0x00
+#define DAVINCI_I2C_IMR_REG 0x04
+#define DAVINCI_I2C_STR_REG 0x08
+#define DAVINCI_I2C_CLKL_REG 0x0c
+#define DAVINCI_I2C_CLKH_REG 0x10
+#define DAVINCI_I2C_CNT_REG 0x14
+#define DAVINCI_I2C_DRR_REG 0x18
+#define DAVINCI_I2C_SAR_REG 0x1c
+#define DAVINCI_I2C_DXR_REG 0x20
+#define DAVINCI_I2C_MDR_REG 0x24
+#define DAVINCI_I2C_IVR_REG 0x28
+#define DAVINCI_I2C_EMDR_REG 0x2c
+#define DAVINCI_I2C_PSC_REG 0x30
+
+#define DAVINCI_I2C_IVR_AAS 0x07
+#define DAVINCI_I2C_IVR_SCD 0x06
+#define DAVINCI_I2C_IVR_XRDY 0x05
+#define DAVINCI_I2C_IVR_RDR 0x04
+#define DAVINCI_I2C_IVR_ARDY 0x03
+#define DAVINCI_I2C_IVR_NACK 0x02
+#define DAVINCI_I2C_IVR_AL 0x01
+
+#define DAVINCI_I2C_STR_BB BIT(12)
+#define DAVINCI_I2C_STR_RSFULL BIT(11)
+#define DAVINCI_I2C_STR_SCD BIT(5)
+#define DAVINCI_I2C_STR_ARDY BIT(2)
+#define DAVINCI_I2C_STR_NACK BIT(1)
+#define DAVINCI_I2C_STR_AL BIT(0)
+
+#define DAVINCI_I2C_MDR_NACK BIT(15)
+#define DAVINCI_I2C_MDR_STT BIT(13)
+#define DAVINCI_I2C_MDR_STP BIT(11)
+#define DAVINCI_I2C_MDR_MST BIT(10)
+#define DAVINCI_I2C_MDR_TRX BIT(9)
+#define DAVINCI_I2C_MDR_XA BIT(8)
+#define DAVINCI_I2C_MDR_RM BIT(7)
+#define DAVINCI_I2C_MDR_IRS BIT(5)
+
+#define DAVINCI_I2C_IMR_AAS BIT(6)
+#define DAVINCI_I2C_IMR_SCD BIT(5)
+#define DAVINCI_I2C_IMR_XRDY BIT(4)
+#define DAVINCI_I2C_IMR_RRDY BIT(3)
+#define DAVINCI_I2C_IMR_ARDY BIT(2)
+#define DAVINCI_I2C_IMR_NACK BIT(1)
+#define DAVINCI_I2C_IMR_AL BIT(0)
+
+struct davinci_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ int cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ int irq;
+ int stop;
+ u8 terminate;
+ struct i2c_adapter adapter;
+#ifdef CONFIG_CPU_FREQ
+ struct completion xfr_complete;
+ struct notifier_block freq_transition;
+#endif
+};
+
+/* default platform data to use if not supplied in the platform_device */
+static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = {
+ .bus_freq = 100,
+ .bus_delay = 0,
+};
+
+static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+/* Generate a pulse on the i2c clock pin. */
+static void generic_i2c_clock_pulse(unsigned int scl_pin)
+{
+ u16 i;
+
+ if (scl_pin) {
+ /* Send high and low on the SCL line */
+ for (i = 0; i < 9; i++) {
+ gpio_set_value(scl_pin, 0);
+ udelay(20);
+ gpio_set_value(scl_pin, 1);
+ udelay(20);
+ }
+ }
+}
+
+/* This routine does i2c bus recovery as specified in the
+ * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
+ */
+static void i2c_recover_bus(struct davinci_i2c_dev *dev)
+{
+ u32 flag = 0;
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+
+ dev_err(dev->dev, "initiating i2c bus recovery\n");
+ /* Send NACK to the slave */
+ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ flag |= DAVINCI_I2C_MDR_NACK;
+ /* write the data into mode register */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+ if (pdata)
+ generic_i2c_clock_pulse(pdata->scl_pin);
+ /* Send STOP */
+ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ flag |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+}
+
+static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
+ int val)
+{
+ u16 w;
+
+ w = davinci_i2c_read_reg(i2c_dev, DAVINCI_I2C_MDR_REG);
+ if (!val) /* put I2C into reset */
+ w &= ~DAVINCI_I2C_MDR_IRS;
+ else /* take I2C out of reset */
+ w |= DAVINCI_I2C_MDR_IRS;
+
+ davinci_i2c_write_reg(i2c_dev, DAVINCI_I2C_MDR_REG, w);
+}
+
+static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
+{
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ u16 psc;
+ u32 clk;
+ u32 d;
+ u32 clkh;
+ u32 clkl;
+ u32 input_clock = clk_get_rate(dev->clk);
+
+ /* NOTE: I2C Clock divider programming info
+ * As per I2C specs the following formulas provide prescaler
+ * and low/high divider values
+ * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+ * module clk
+ *
+ * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+ *
+ * Thus,
+ * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+ *
+ * where if PSC == 0, d = 7,
+ * if PSC == 1, d = 6
+ * if PSC > 1 , d = 5
+ */
+
+ /* get minimum of 7 MHz clock, but max of 12 MHz */
+ psc = (input_clock / 7000000) - 1;
+ if ((input_clock / (psc + 1)) > 12000000)
+ psc++; /* better to run under spec than over */
+ d = (psc >= 2) ? 5 : 7 - psc;
+
+ clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - (d << 1);
+ clkh = clk >> 1;
+ clkl = clk - clkh;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
+
+ dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
+}
+
+/*
+ * This function configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounters any errors.
+ */
+static int i2c_davinci_init(struct davinci_i2c_dev *dev)
+{
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(dev, 0);
+
+ /* compute clock dividers */
+ i2c_davinci_calc_clk_dividers(dev);
+
+ /* Respond at reserved "SMBus Host" slave address" (and zero);
+ * we seem to have no option to not respond...
+ */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);
+
+ dev_dbg(dev->dev, "PSC = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
+ dev_dbg(dev->dev, "CLKL = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
+ dev_dbg(dev->dev, "CLKH = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
+ dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",
+ pdata->bus_freq, pdata->bus_delay);
+
+ /* Take the I2C module out of reset: */
+ davinci_i2c_reset_ctrl(dev, 1);
+
+ /* Enable interrupts */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
+
+ return 0;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
+ char allow_sleep)
+{
+ unsigned long timeout;
+ static u16 to_cnt;
+
+ timeout = jiffies + dev->adapter.timeout;
+ while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
+ & DAVINCI_I2C_STR_BB) {
+ if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev,
+ "timeout waiting for bus ready\n");
+ to_cnt++;
+ return -ETIMEDOUT;
+ } else {
+ to_cnt = 0;
+ i2c_recover_bus(dev);
+ i2c_davinci_init(dev);
+ }
+ }
+ if (allow_sleep)
+ schedule_timeout(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ u32 flag;
+ u16 w;
+ int r;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+ /* Introduce a delay, required for some boards (e.g Davinci EVM) */
+ if (pdata->bus_delay)
+ udelay(pdata->bus_delay);
+
+ /* set the slave address */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);
+
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+ dev->stop = stop;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
+
+ INIT_COMPLETION(dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ /* Take I2C out of reset and configure it as master */
+ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST;
+
+ /* if the slave address is ten bit address, enable XA bit */
+ if (msg->flags & I2C_M_TEN)
+ flag |= DAVINCI_I2C_MDR_XA;
+ if (!(msg->flags & I2C_M_RD))
+ flag |= DAVINCI_I2C_MDR_TRX;
+ if (msg->len == 0)
+ flag |= DAVINCI_I2C_MDR_RM;
+
+ /* Enable receive or transmit interrupts */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
+ if (msg->flags & I2C_M_RD)
+ w |= DAVINCI_I2C_IMR_RRDY;
+ else
+ w |= DAVINCI_I2C_IMR_XRDY;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
+
+ dev->terminate = 0;
+
+ /*
+ * Write mode register first as needed for correct behaviour
+ * on OMAP-L138, but don't set STT yet to avoid a race with XRDY
+ * occurring before we have loaded DXR
+ */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+ /*
+ * First byte should be set here, not after interrupt,
+ * because transmit-data-ready interrupt can come before
+ * NACK-interrupt during sending of previous message and
+ * ICDXR may have wrong data
+ * It also saves us one interrupt, slightly faster
+ */
+ if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) {
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++);
+ dev->buf_len--;
+ }
+
+ /* Set STT to begin transmit now DXR is loaded */
+ flag |= DAVINCI_I2C_MDR_STT;
+ if (stop && msg->len != 0)
+ flag |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_recover_bus(dev);
+ i2c_davinci_init(dev);
+ dev->buf_len = 0;
+ return -ETIMEDOUT;
+ }
+ if (dev->buf_len) {
+ /* This should be 0 if all bytes were transferred
+ * or dev->cmd_err denotes an error.
+ * A signal may have aborted the transfer.
+ */
+ if (r >= 0) {
+ dev_err(dev->dev, "abnormal termination buf_len=%i\n",
+ dev->buf_len);
+ r = -EREMOTEIO;
+ }
+ dev->terminate = 1;
+ wmb();
+ dev->buf_len = 0;
+ }
+ if (r < 0)
+ return r;
+
+ /* no error */
+ if (likely(!dev->cmd_err))
+ return msg->len;
+
+ /* We have an error */
+ if (dev->cmd_err & DAVINCI_I2C_STR_AL) {
+ i2c_davinci_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return msg->len;
+ if (stop) {
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int ret;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+ ret = i2c_davinci_wait_bus_not_busy(dev, 1);
+ if (ret < 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num,
+ ret);
+ if (ret < 0)
+ return ret;
+ }
+
+#ifdef CONFIG_CPU_FREQ
+ complete(&dev->xfr_complete);
+#endif
+
+ return num;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static void terminate_read(struct davinci_i2c_dev *dev)
+{
+ u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_NACK;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ /* Throw away data */
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG);
+ if (!dev->terminate)
+ dev_err(dev->dev, "RDR IRQ while no data requested\n");
+}
+static void terminate_write(struct davinci_i2c_dev *dev)
+{
+ u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ if (!dev->terminate)
+ dev_dbg(dev->dev, "TDR IRQ while no data to send\n");
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
+{
+ struct davinci_i2c_dev *dev = dev_id;
+ u32 stat;
+ int count = 0;
+ u16 w;
+
+ while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
+ dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ switch (stat) {
+ case DAVINCI_I2C_IVR_AL:
+ /* Arbitration lost, must retry */
+ dev->cmd_err |= DAVINCI_I2C_STR_AL;
+ dev->buf_len = 0;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_NACK:
+ dev->cmd_err |= DAVINCI_I2C_STR_NACK;
+ dev->buf_len = 0;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_ARDY:
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);
+ if (((dev->buf_len == 0) && (dev->stop != 0)) ||
+ (dev->cmd_err & DAVINCI_I2C_STR_NACK)) {
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_MDR_REG, w);
+ }
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_RDR:
+ if (dev->buf_len) {
+ *dev->buf++ =
+ davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_DRR_REG);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG,
+ DAVINCI_I2C_IMR_RRDY);
+ } else {
+ /* signal can terminate transfer */
+ terminate_read(dev);
+ }
+ break;
+
+ case DAVINCI_I2C_IVR_XRDY:
+ if (dev->buf_len) {
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
+ *dev->buf++);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_IMR_REG);
+ w &= ~DAVINCI_I2C_IMR_XRDY;
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_IMR_REG,
+ w);
+ } else {
+ /* signal can terminate transfer */
+ terminate_write(dev);
+ }
+ break;
+
+ case DAVINCI_I2C_IVR_SCD:
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_SCD);
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_AAS:
+ dev_dbg(dev->dev, "Address as slave interrupt\n");
+ break;
+
+ default:
+ dev_warn(dev->dev, "Unrecognized irq stat %d\n", stat);
+ break;
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct davinci_i2c_dev *dev;
+
+ dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
+ if (val == CPUFREQ_PRECHANGE) {
+ wait_for_completion(&dev->xfr_complete);
+ davinci_i2c_reset_ctrl(dev, 0);
+ } else if (val == CPUFREQ_POSTCHANGE) {
+ i2c_davinci_calc_clk_dividers(dev);
+ davinci_i2c_reset_ctrl(dev, 1);
+ }
+
+ return 0;
+}
+
+static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
+{
+ dev->freq_transition.notifier_call = i2c_davinci_cpufreq_transition;
+
+ return cpufreq_register_notifier(&dev->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
+{
+ cpufreq_unregister_notifier(&dev->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+#else
+static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
+{
+ return 0;
+}
+
+static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
+{
+}
+#endif
+
+static struct i2c_algorithm i2c_davinci_algo = {
+ .master_xfer = i2c_davinci_xfer,
+ .functionality = i2c_davinci_func,
+};
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, resource_size(mem),
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ init_completion(&dev->cmd_complete);
+#ifdef CONFIG_CPU_FREQ
+ init_completion(&dev->xfr_complete);
+#endif
+ dev->dev = get_device(&pdev->dev);
+ dev->irq = irq->start;
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ r = -ENODEV;
+ goto err_free_mem;
+ }
+ clk_enable(dev->clk);
+
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (!dev->base) {
+ r = -EBUSY;
+ goto err_mem_ioremap;
+ }
+
+ i2c_davinci_init(dev);
+
+ r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+
+ r = i2c_davinci_cpufreq_register(dev);
+ if (r) {
+ dev_err(&pdev->dev, "failed to register cpufreq\n");
+ goto err_free_irq;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+ adap->algo = &i2c_davinci_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->timeout = DAVINCI_I2C_TIMEOUT;
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ iounmap(dev->base);
+err_mem_ioremap:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ i2c_davinci_cpufreq_deregister(dev);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+ free_irq(dev->irq, dev);
+ iounmap(dev->base);
+ kfree(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int davinci_i2c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(i2c_dev, 0);
+ clk_disable(i2c_dev->clk);
+
+ return 0;
+}
+
+static int davinci_i2c_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ clk_enable(i2c_dev->clk);
+ /* take I2C out of reset */
+ davinci_i2c_reset_ctrl(i2c_dev, 1);
+
+ return 0;
+}
+
+static const struct dev_pm_ops davinci_i2c_pm = {
+ .suspend = davinci_i2c_suspend,
+ .resume = davinci_i2c_resume,
+};
+
+#define davinci_i2c_pm_ops (&davinci_i2c_pm)
+#else
+#define davinci_i2c_pm_ops NULL
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_davinci");
+
+static struct platform_driver davinci_i2c_driver = {
+ .probe = davinci_i2c_probe,
+ .remove = davinci_i2c_remove,
+ .driver = {
+ .name = "i2c_davinci",
+ .owner = THIS_MODULE,
+ .pm = davinci_i2c_pm_ops,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init davinci_i2c_init_driver(void)
+{
+ return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
new file mode 100644
index 00000000..b7a51c43
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -0,0 +1,847 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * Registers offset
+ */
+#define DW_IC_CON 0x0
+#define DW_IC_TAR 0x4
+#define DW_IC_DATA_CMD 0x10
+#define DW_IC_SS_SCL_HCNT 0x14
+#define DW_IC_SS_SCL_LCNT 0x18
+#define DW_IC_FS_SCL_HCNT 0x1c
+#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
+#define DW_IC_RXFLR 0x78
+#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_TX_ABRT_SOURCE 0x80
+
+#define DW_IC_CON_MASTER 0x1
+#define DW_IC_CON_SPEED_STD 0x2
+#define DW_IC_CON_SPEED_FAST 0x4
+#define DW_IC_CON_10BITADDR_MASTER 0x10
+#define DW_IC_CON_RESTART_EN 0x20
+#define DW_IC_CON_SLAVE_DISABLE 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
+
+#define DW_IC_ERR_TX_ABRT 0x1
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE 0x0
+#define STATUS_WRITE_IN_PROGRESS 0x1
+#define STATUS_READ_IN_PROGRESS 0x2
+
+#define TIMEOUT 20 /* ms */
+
+/*
+ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK 0
+#define ABRT_10ADDR1_NOACK 1
+#define ABRT_10ADDR2_NOACK 2
+#define ABRT_TXDATA_NOACK 3
+#define ABRT_GCALL_NOACK 4
+#define ABRT_GCALL_READ 5
+#define ABRT_SBYTE_ACKDET 7
+#define ABRT_SBYTE_NORSTRT 9
+#define ABRT_10B_RD_NORSTRT 10
+#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] =
+ "slave address not acknowledged (7bit mode)",
+ [ABRT_10ADDR1_NOACK] =
+ "first address byte not acknowledged (10bit mode)",
+ [ABRT_10ADDR2_NOACK] =
+ "second address byte not acknowledged (10bit mode)",
+ [ABRT_TXDATA_NOACK] =
+ "data not acknowledged",
+ [ABRT_GCALL_NOACK] =
+ "no acknowledgement for a general call",
+ [ABRT_GCALL_READ] =
+ "read after general call",
+ [ABRT_SBYTE_ACKDET] =
+ "start byte acknowledged",
+ [ABRT_SBYTE_NORSTRT] =
+ "trying to send start byte when restart is disabled",
+ [ABRT_10B_RD_NORSTRT] =
+ "trying to read when restart is disabled (10bit mode)",
+ [ABRT_MASTER_DIS] =
+ "trying to use disabled adapter",
+ [ARB_LOST] =
+ "lost arbitration",
+};
+
+/**
+ * struct dw_i2c_dev - private i2c-designware data
+ * @dev: driver model device node
+ * @base: IO registers pointer
+ * @cmd_complete: tx completion indicator
+ * @lock: protect this struct and IO registers
+ * @clk: input reference clock
+ * @cmd_err: run time hadware error code
+ * @msgs: points to an array of messages currently being transferred
+ * @msgs_num: the number of elements in msgs
+ * @msg_write_idx: the element index of the current tx message in the msgs
+ * array
+ * @tx_buf_len: the length of the current tx buffer
+ * @tx_buf: the current tx buffer
+ * @msg_read_idx: the element index of the current rx message in the msgs
+ * array
+ * @rx_buf_len: the length of the current rx buffer
+ * @rx_buf: the current rx buffer
+ * @msg_err: error status of the current transfer
+ * @status: i2c master status, one of STATUS_*
+ * @abort_source: copy of the TX_ABRT_SOURCE register
+ * @irq: interrupt number for the i2c master
+ * @adapter: i2c subsystem adapter node
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
+ */
+struct dw_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct mutex lock;
+ struct clk *clk;
+ int cmd_err;
+ struct i2c_msg *msgs;
+ int msgs_num;
+ int msg_write_idx;
+ u32 tx_buf_len;
+ u8 *tx_buf;
+ int msg_read_idx;
+ u32 rx_buf_len;
+ u8 *rx_buf;
+ int msg_err;
+ unsigned int status;
+ 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
+ *
+ * This functions configures and enables the I2C master.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+static void i2c_dw_init(struct dw_i2c_dev *dev)
+{
+ u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
+ u32 ic_con, hcnt, lcnt;
+
+ /* Disable the adapter */
+ writel(0, dev->base + DW_IC_ENABLE);
+
+ /* set standard and fast speed deviders for high/low periods */
+
+ /* 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;
+ writel(ic_con, dev->base + DW_IC_CON);
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+{
+ int timeout = TIMEOUT;
+
+ 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;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ return 0;
+}
+
+static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 ic_con;
+
+ /* Disable the adapter */
+ writel(0, dev->base + DW_IC_ENABLE);
+
+ /* 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 = 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 */
+ writel(1, dev->base + DW_IC_ENABLE);
+
+ /* 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) {
+ 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;
+ break;
+ }
+
+ if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+ /* new i2c_msg */
+ 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) {
+ writel(0x100, dev->base + DW_IC_DATA_CMD);
+ rx_limit--;
+ } else
+ 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;
+ }
+
+ /*
+ * 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;
+
+ if (dev->msg_err)
+ intr_mask = 0;
+
+ writel(intr_mask, dev->base + DW_IC_INTR_MASK);
+}
+
+static void
+i2c_dw_read(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ int rx_valid;
+
+ 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;
+
+ if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
+ len = msgs[dev->msg_read_idx].len;
+ buf = msgs[dev->msg_read_idx].buf;
+ } else {
+ len = dev->rx_buf_len;
+ buf = dev->rx_buf;
+ }
+
+ rx_valid = readl(dev->base + DW_IC_RXFLR);
+
+ for (; len > 0 && rx_valid > 0; len--, rx_valid--)
+ *buf++ = readl(dev->base + DW_IC_DATA_CMD);
+
+ if (len > 0) {
+ dev->status |= STATUS_READ_IN_PROGRESS;
+ dev->rx_buf_len = len;
+ dev->rx_buf = buf;
+ return;
+ } else
+ dev->status &= ~STATUS_READ_IN_PROGRESS;
+ }
+}
+
+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
+ */
+static int
+i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ int ret;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+ mutex_lock(&dev->lock);
+
+ INIT_COMPLETION(dev->cmd_complete);
+ dev->msgs = msgs;
+ dev->msgs_num = num;
+ dev->cmd_err = 0;
+ dev->msg_write_idx = 0;
+ 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_init(dev);
+
+ /* wait for tx to complete */
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+ if (ret == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_dw_init(dev);
+ ret = -ETIMEDOUT;
+ goto done;
+ } else if (ret < 0)
+ goto done;
+
+ if (dev->msg_err) {
+ ret = dev->msg_err;
+ goto done;
+ }
+
+ /* no error */
+ if (likely(!dev->cmd_err)) {
+ /* 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) {
+ ret = i2c_dw_handle_tx_abort(dev);
+ goto done;
+ }
+ ret = -EIO;
+
+done:
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+
+static u32 i2c_dw_func(struct i2c_adapter *adap)
+{
+ 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 u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+{
+ u32 stat;
+
+ /*
+ * 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);
+
+ return stat;
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+ struct dw_i2c_dev *dev = dev_id;
+ u32 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->cmd_err |= DW_IC_ERR_TX_ABRT;
+ dev->status = STATUS_IDLE;
+
+ /*
+ * 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;
+}
+
+static struct i2c_algorithm i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+};
+
+static int __devinit dw_i2c_probe(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *ioarea;
+ int irq, r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return irq; /* -ENXIO */
+ }
+
+ ioarea = request_mem_region(mem->start, resource_size(mem),
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ init_completion(&dev->cmd_complete);
+ mutex_init(&dev->lock);
+ dev->dev = get_device(&pdev->dev);
+ dev->irq = irq;
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ r = -ENODEV;
+ goto err_free_mem;
+ }
+ clk_enable(dev->clk);
+
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (dev->base == NULL) {
+ dev_err(&pdev->dev, "failure mapping io resources\n");
+ r = -EBUSY;
+ goto err_unuse_clocks;
+ }
+ {
+ u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1);
+
+ dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
+ dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
+ }
+ i2c_dw_init(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;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
+ sizeof(adap->name));
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = &pdev->dev;
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_iounmap:
+ iounmap(dev->base);
+err_unuse_clocks:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return r;
+}
+
+static int __devexit dw_i2c_remove(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ writel(0, dev->base + DW_IC_ENABLE);
+ free_irq(dev->irq, dev);
+ kfree(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_designware");
+
+static struct platform_driver dw_i2c_driver = {
+ .remove = __devexit_p(dw_i2c_remove),
+ .driver = {
+ .name = "i2c_designware",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+ return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+}
+module_init(dw_i2c_init_driver);
+
+static void __exit dw_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&dw_i2c_driver);
+}
+module_exit(dw_i2c_exit_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c
new file mode 100644
index 00000000..76366716
--- /dev/null
+++ b/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -0,0 +1,535 @@
+/*
+ * Driver for the Diolan u2c-12 USB-I2C adapter
+ *
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * Derived from:
+ * i2c-tiny-usb.c
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.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, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#define DRIVER_NAME "i2c-diolan-u2c"
+
+#define USB_VENDOR_ID_DIOLAN 0x0abf
+#define USB_DEVICE_ID_DIOLAN_U2C 0x3370
+
+#define DIOLAN_OUT_EP 0x02
+#define DIOLAN_IN_EP 0x84
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_I2C_READ 0x01
+#define CMD_I2C_WRITE 0x02
+#define CMD_I2C_SCAN 0x03 /* Returns list of detected devices */
+#define CMD_I2C_RELEASE_SDA 0x04
+#define CMD_I2C_RELEASE_SCL 0x05
+#define CMD_I2C_DROP_SDA 0x06
+#define CMD_I2C_DROP_SCL 0x07
+#define CMD_I2C_READ_SDA 0x08
+#define CMD_I2C_READ_SCL 0x09
+#define CMD_GET_FW_VERSION 0x0a
+#define CMD_GET_SERIAL 0x0b
+#define CMD_I2C_START 0x0c
+#define CMD_I2C_STOP 0x0d
+#define CMD_I2C_REPEATED_START 0x0e
+#define CMD_I2C_PUT_BYTE 0x0f
+#define CMD_I2C_GET_BYTE 0x10
+#define CMD_I2C_PUT_ACK 0x11
+#define CMD_I2C_GET_ACK 0x12
+#define CMD_I2C_PUT_BYTE_ACK 0x13
+#define CMD_I2C_GET_BYTE_ACK 0x14
+#define CMD_I2C_SET_SPEED 0x1b
+#define CMD_I2C_GET_SPEED 0x1c
+#define CMD_I2C_SET_CLK_SYNC 0x24
+#define CMD_I2C_GET_CLK_SYNC 0x25
+#define CMD_I2C_SET_CLK_SYNC_TO 0x26
+#define CMD_I2C_GET_CLK_SYNC_TO 0x27
+
+#define RESP_OK 0x00
+#define RESP_FAILED 0x01
+#define RESP_BAD_MEMADDR 0x04
+#define RESP_DATA_ERR 0x05
+#define RESP_NOT_IMPLEMENTED 0x06
+#define RESP_NACK 0x07
+#define RESP_TIMEOUT 0x09
+
+#define U2C_I2C_SPEED_FAST 0 /* 400 kHz */
+#define U2C_I2C_SPEED_STD 1 /* 100 kHz */
+#define U2C_I2C_SPEED_2KHZ 242 /* 2 kHz, minimum speed */
+#define U2C_I2C_SPEED(f) ((DIV_ROUND_UP(1000000, (f)) - 10) / 2 + 1)
+
+#define U2C_I2C_FREQ_FAST 400000
+#define U2C_I2C_FREQ_STD 100000
+#define U2C_I2C_FREQ(s) (1000000 / (2 * (s - 1) + 10))
+
+#define DIOLAN_USB_TIMEOUT 100 /* in ms */
+#define DIOLAN_SYNC_TIMEOUT 20 /* in ms */
+
+#define DIOLAN_OUTBUF_LEN 128
+#define DIOLAN_FLUSH_LEN (DIOLAN_OUTBUF_LEN - 4)
+#define DIOLAN_INBUF_LEN 256 /* Maximum supported receive length */
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_diolan_u2c {
+ u8 obuffer[DIOLAN_OUTBUF_LEN]; /* output buffer */
+ u8 ibuffer[DIOLAN_INBUF_LEN]; /* input buffer */
+ struct usb_device *usb_dev; /* the usb device for this device */
+ struct usb_interface *interface;/* the interface for this device */
+ struct i2c_adapter adapter; /* i2c related things */
+ int olen; /* Output buffer length */
+ int ocount; /* Number of enqueued messages */
+};
+
+static uint frequency = U2C_I2C_FREQ_STD; /* I2C clock frequency in Hz */
+
+module_param(frequency, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");
+
+/* usb layer */
+
+/* Send command to device, and get response. */
+static int diolan_usb_transfer(struct i2c_diolan_u2c *dev)
+{
+ int ret = 0;
+ int actual;
+ int i;
+
+ if (!dev->olen || !dev->ocount)
+ return -EINVAL;
+
+ ret = usb_bulk_msg(dev->usb_dev,
+ usb_sndbulkpipe(dev->usb_dev, DIOLAN_OUT_EP),
+ dev->obuffer, dev->olen, &actual,
+ DIOLAN_USB_TIMEOUT);
+ if (!ret) {
+ for (i = 0; i < dev->ocount; i++) {
+ int tmpret;
+
+ tmpret = usb_bulk_msg(dev->usb_dev,
+ usb_rcvbulkpipe(dev->usb_dev,
+ DIOLAN_IN_EP),
+ dev->ibuffer,
+ sizeof(dev->ibuffer), &actual,
+ DIOLAN_USB_TIMEOUT);
+ /*
+ * Stop command processing if a previous command
+ * returned an error.
+ * Note that we still need to retrieve all messages.
+ */
+ if (ret < 0)
+ continue;
+ ret = tmpret;
+ if (ret == 0 && actual > 0) {
+ switch (dev->ibuffer[actual - 1]) {
+ case RESP_NACK:
+ /*
+ * Return ENXIO if NACK was received as
+ * response to the address phase,
+ * EIO otherwise
+ */
+ ret = i == 1 ? -ENXIO : -EIO;
+ break;
+ case RESP_TIMEOUT:
+ ret = -ETIMEDOUT;
+ break;
+ case RESP_OK:
+ /* strip off return code */
+ ret = actual - 1;
+ break;
+ default:
+ ret = -EIO;
+ break;
+ }
+ }
+ }
+ }
+ dev->olen = 0;
+ dev->ocount = 0;
+ return ret;
+}
+
+static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush)
+{
+ if (flush || dev->olen >= DIOLAN_FLUSH_LEN)
+ return diolan_usb_transfer(dev);
+ return 0;
+}
+
+/* Send command (no data) */
+static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush)
+{
+ dev->obuffer[dev->olen++] = command;
+ dev->ocount++;
+ return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with one byte of data */
+static int diolan_usb_cmd_data(struct i2c_diolan_u2c *dev, u8 command, u8 data,
+ bool flush)
+{
+ dev->obuffer[dev->olen++] = command;
+ dev->obuffer[dev->olen++] = data;
+ dev->ocount++;
+ return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with two bytes of data */
+static int diolan_usb_cmd_data2(struct i2c_diolan_u2c *dev, u8 command, u8 d1,
+ u8 d2, bool flush)
+{
+ dev->obuffer[dev->olen++] = command;
+ dev->obuffer[dev->olen++] = d1;
+ dev->obuffer[dev->olen++] = d2;
+ dev->ocount++;
+ return diolan_write_cmd(dev, flush);
+}
+
+/*
+ * Flush input queue.
+ * If we don't do this at startup and the controller has queued up
+ * messages which were not retrieved, it will stop responding
+ * at some point.
+ */
+static void diolan_flush_input(struct i2c_diolan_u2c *dev)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ int actual = 0;
+ int ret;
+
+ ret = usb_bulk_msg(dev->usb_dev,
+ usb_rcvbulkpipe(dev->usb_dev, DIOLAN_IN_EP),
+ dev->ibuffer, sizeof(dev->ibuffer), &actual,
+ DIOLAN_USB_TIMEOUT);
+ if (ret < 0 || actual == 0)
+ break;
+ }
+ if (i == 10)
+ dev_err(&dev->interface->dev, "Failed to flush input buffer\n");
+}
+
+static int diolan_i2c_start(struct i2c_diolan_u2c *dev)
+{
+ return diolan_usb_cmd(dev, CMD_I2C_START, false);
+}
+
+static int diolan_i2c_repeated_start(struct i2c_diolan_u2c *dev)
+{
+ return diolan_usb_cmd(dev, CMD_I2C_REPEATED_START, false);
+}
+
+static int diolan_i2c_stop(struct i2c_diolan_u2c *dev)
+{
+ return diolan_usb_cmd(dev, CMD_I2C_STOP, true);
+}
+
+static int diolan_i2c_get_byte_ack(struct i2c_diolan_u2c *dev, bool ack,
+ u8 *byte)
+{
+ int ret;
+
+ ret = diolan_usb_cmd_data(dev, CMD_I2C_GET_BYTE_ACK, ack, true);
+ if (ret > 0)
+ *byte = dev->ibuffer[0];
+ else if (ret == 0)
+ ret = -EIO;
+
+ return ret;
+}
+
+static int diolan_i2c_put_byte_ack(struct i2c_diolan_u2c *dev, u8 byte)
+{
+ return diolan_usb_cmd_data(dev, CMD_I2C_PUT_BYTE_ACK, byte, false);
+}
+
+static int diolan_set_speed(struct i2c_diolan_u2c *dev, u8 speed)
+{
+ return diolan_usb_cmd_data(dev, CMD_I2C_SET_SPEED, speed, true);
+}
+
+/* Enable or disable clock synchronization (stretching) */
+static int diolan_set_clock_synch(struct i2c_diolan_u2c *dev, bool enable)
+{
+ return diolan_usb_cmd_data(dev, CMD_I2C_SET_CLK_SYNC, enable, true);
+}
+
+/* Set clock synchronization timeout in ms */
+static int diolan_set_clock_synch_timeout(struct i2c_diolan_u2c *dev, int ms)
+{
+ int to_val = ms * 10;
+
+ return diolan_usb_cmd_data2(dev, CMD_I2C_SET_CLK_SYNC_TO,
+ to_val & 0xff, (to_val >> 8) & 0xff, true);
+}
+
+static void diolan_fw_version(struct i2c_diolan_u2c *dev)
+{
+ int ret;
+
+ ret = diolan_usb_cmd(dev, CMD_GET_FW_VERSION, true);
+ if (ret >= 2)
+ dev_info(&dev->interface->dev,
+ "Diolan U2C firmware version %u.%u\n",
+ (unsigned int)dev->ibuffer[0],
+ (unsigned int)dev->ibuffer[1]);
+}
+
+static void diolan_get_serial(struct i2c_diolan_u2c *dev)
+{
+ int ret;
+ u32 serial;
+
+ ret = diolan_usb_cmd(dev, CMD_GET_SERIAL, true);
+ if (ret >= 4) {
+ serial = le32_to_cpu(*(u32 *)dev->ibuffer);
+ dev_info(&dev->interface->dev,
+ "Diolan U2C serial number %u\n", serial);
+ }
+}
+
+static int diolan_init(struct i2c_diolan_u2c *dev)
+{
+ int speed, ret;
+
+ if (frequency >= 200000) {
+ speed = U2C_I2C_SPEED_FAST;
+ frequency = U2C_I2C_FREQ_FAST;
+ } else if (frequency >= 100000 || frequency == 0) {
+ speed = U2C_I2C_SPEED_STD;
+ frequency = U2C_I2C_FREQ_STD;
+ } else {
+ speed = U2C_I2C_SPEED(frequency);
+ if (speed > U2C_I2C_SPEED_2KHZ)
+ speed = U2C_I2C_SPEED_2KHZ;
+ frequency = U2C_I2C_FREQ(speed);
+ }
+
+ dev_info(&dev->interface->dev,
+ "Diolan U2C at USB bus %03d address %03d speed %d Hz\n",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency);
+
+ diolan_flush_input(dev);
+ diolan_fw_version(dev);
+ diolan_get_serial(dev);
+
+ /* Set I2C speed */
+ ret = diolan_set_speed(dev, speed);
+ if (ret < 0)
+ return ret;
+
+ /* Configure I2C clock synchronization */
+ ret = diolan_set_clock_synch(dev, speed != U2C_I2C_SPEED_FAST);
+ if (ret < 0)
+ return ret;
+
+ if (speed != U2C_I2C_SPEED_FAST)
+ ret = diolan_set_clock_synch_timeout(dev, DIOLAN_SYNC_TIMEOUT);
+
+ return ret;
+}
+
+/* i2c layer */
+
+static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_diolan_u2c *dev = i2c_get_adapdata(adapter);
+ struct i2c_msg *pmsg;
+ int i, j;
+ int ret, sret;
+
+ ret = diolan_i2c_start(dev);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ if (i) {
+ ret = diolan_i2c_repeated_start(dev);
+ if (ret < 0)
+ goto abort;
+ }
+ if (pmsg->flags & I2C_M_RD) {
+ ret =
+ diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1);
+ if (ret < 0)
+ goto abort;
+ for (j = 0; j < pmsg->len; j++) {
+ u8 byte;
+ bool ack = j < pmsg->len - 1;
+
+ /*
+ * Don't send NACK if this is the first byte
+ * of a SMBUS_BLOCK message.
+ */
+ if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN))
+ ack = true;
+
+ ret = diolan_i2c_get_byte_ack(dev, ack, &byte);
+ if (ret < 0)
+ goto abort;
+ /*
+ * Adjust count if first received byte is length
+ */
+ if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) {
+ if (byte == 0
+ || byte > I2C_SMBUS_BLOCK_MAX) {
+ ret = -EPROTO;
+ goto abort;
+ }
+ pmsg->len += byte;
+ }
+ pmsg->buf[j] = byte;
+ }
+ } else {
+ ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1);
+ if (ret < 0)
+ goto abort;
+ for (j = 0; j < pmsg->len; j++) {
+ ret = diolan_i2c_put_byte_ack(dev,
+ pmsg->buf[j]);
+ if (ret < 0)
+ goto abort;
+ }
+ }
+ }
+abort:
+ sret = diolan_i2c_stop(dev);
+ if (sret < 0 && ret >= 0)
+ ret = sret;
+ return ret;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 diolan_usb_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm diolan_usb_algorithm = {
+ .master_xfer = diolan_usb_xfer,
+ .functionality = diolan_usb_func,
+};
+
+/* device layer */
+
+static const struct usb_device_id diolan_u2c_table[] = {
+ { USB_DEVICE(USB_VENDOR_ID_DIOLAN, USB_DEVICE_ID_DIOLAN_U2C) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, diolan_u2c_table);
+
+static void diolan_u2c_free(struct i2c_diolan_u2c *dev)
+{
+ usb_put_dev(dev->usb_dev);
+ kfree(dev);
+}
+
+static int diolan_u2c_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct i2c_diolan_u2c *dev;
+ int ret;
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "no memory for device state\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ /* setup i2c adapter description */
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &diolan_usb_algorithm;
+ i2c_set_adapdata(&dev->adapter, dev);
+ snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+ DRIVER_NAME " at bus %03d device %03d",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ dev->adapter.dev.parent = &dev->interface->dev;
+
+ /* initialize diolan i2c interface */
+ ret = diolan_init(dev);
+ if (ret < 0) {
+ dev_err(&interface->dev, "failed to initialize adapter\n");
+ goto error_free;
+ }
+
+ /* and finally attach to i2c layer */
+ ret = i2c_add_adapter(&dev->adapter);
+ if (ret < 0) {
+ dev_err(&interface->dev, "failed to add I2C adapter\n");
+ goto error_free;
+ }
+
+ dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n");
+
+ return 0;
+
+error_free:
+ usb_set_intfdata(interface, NULL);
+ diolan_u2c_free(dev);
+error:
+ return ret;
+}
+
+static void diolan_u2c_disconnect(struct usb_interface *interface)
+{
+ struct i2c_diolan_u2c *dev = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&dev->adapter);
+ usb_set_intfdata(interface, NULL);
+ diolan_u2c_free(dev);
+
+ dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver diolan_u2c_driver = {
+ .name = DRIVER_NAME,
+ .probe = diolan_u2c_probe,
+ .disconnect = diolan_u2c_disconnect,
+ .id_table = diolan_u2c_table,
+};
+
+static int __init diolan_u2c_init(void)
+{
+ /* register this driver with the USB subsystem */
+ return usb_register(&diolan_u2c_driver);
+}
+
+static void __exit diolan_u2c_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&diolan_u2c_driver);
+}
+
+module_init(diolan_u2c_init);
+module_exit(diolan_u2c_exit);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION(DRIVER_NAME " driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
new file mode 100644
index 00000000..656b028d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -0,0 +1,940 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+
+#define PCH_EVENT_SET 0 /* I2C Interrupt Event Set Status */
+#define PCH_EVENT_NONE 1 /* I2C Interrupt Event Clear Status */
+#define PCH_MAX_CLK 100000 /* Maximum Clock speed in MHz */
+#define PCH_BUFFER_MODE_ENABLE 0x0002 /* flag for Buffer mode enable */
+#define PCH_EEPROM_SW_RST_MODE_ENABLE 0x0008 /* EEPROM SW RST enable flag */
+
+#define PCH_I2CSADR 0x00 /* I2C slave address register */
+#define PCH_I2CCTL 0x04 /* I2C control register */
+#define PCH_I2CSR 0x08 /* I2C status register */
+#define PCH_I2CDR 0x0C /* I2C data register */
+#define PCH_I2CMON 0x10 /* I2C bus monitor register */
+#define PCH_I2CBC 0x14 /* I2C bus transfer rate setup counter */
+#define PCH_I2CMOD 0x18 /* I2C mode register */
+#define PCH_I2CBUFSLV 0x1C /* I2C buffer mode slave address register */
+#define PCH_I2CBUFSUB 0x20 /* I2C buffer mode subaddress register */
+#define PCH_I2CBUFFOR 0x24 /* I2C buffer mode format register */
+#define PCH_I2CBUFCTL 0x28 /* I2C buffer mode control register */
+#define PCH_I2CBUFMSK 0x2C /* I2C buffer mode interrupt mask register */
+#define PCH_I2CBUFSTA 0x30 /* I2C buffer mode status register */
+#define PCH_I2CBUFLEV 0x34 /* I2C buffer mode level register */
+#define PCH_I2CESRFOR 0x38 /* EEPROM software reset mode format register */
+#define PCH_I2CESRCTL 0x3C /* EEPROM software reset mode ctrl register */
+#define PCH_I2CESRMSK 0x40 /* EEPROM software reset mode */
+#define PCH_I2CESRSTA 0x44 /* EEPROM software reset mode status register */
+#define PCH_I2CTMR 0x48 /* I2C timer register */
+#define PCH_I2CSRST 0xFC /* I2C reset register */
+#define PCH_I2CNF 0xF8 /* I2C noise filter register */
+
+#define BUS_IDLE_TIMEOUT 20
+#define PCH_I2CCTL_I2CMEN 0x0080
+#define TEN_BIT_ADDR_DEFAULT 0xF000
+#define TEN_BIT_ADDR_MASK 0xF0
+#define PCH_START 0x0020
+#define PCH_ESR_START 0x0001
+#define PCH_BUFF_START 0x1
+#define PCH_REPSTART 0x0004
+#define PCH_ACK 0x0008
+#define PCH_GETACK 0x0001
+#define CLR_REG 0x0
+#define I2C_RD 0x1
+#define I2CMCF_BIT 0x0080
+#define I2CMIF_BIT 0x0002
+#define I2CMAL_BIT 0x0010
+#define I2CBMFI_BIT 0x0001
+#define I2CBMAL_BIT 0x0002
+#define I2CBMNA_BIT 0x0004
+#define I2CBMTO_BIT 0x0008
+#define I2CBMIS_BIT 0x0010
+#define I2CESRFI_BIT 0X0001
+#define I2CESRTO_BIT 0x0002
+#define I2CESRFIIE_BIT 0x1
+#define I2CESRTOIE_BIT 0x2
+#define I2CBMDZ_BIT 0x0040
+#define I2CBMAG_BIT 0x0020
+#define I2CMBB_BIT 0x0020
+#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
+ I2CBMTO_BIT | I2CBMIS_BIT)
+#define I2C_ADDR_MSK 0xFF
+#define I2C_MSB_2B_MSK 0x300
+#define FAST_MODE_CLK 400
+#define FAST_MODE_EN 0x0001
+#define SUB_ADDR_LEN_MAX 4
+#define BUF_LEN_MAX 32
+#define PCH_BUFFER_MODE 0x1
+#define EEPROM_SW_RST_MODE 0x0002
+#define NORMAL_INTR_ENBL 0x0300
+#define EEPROM_RST_INTR_ENBL (I2CESRFIIE_BIT | I2CESRTOIE_BIT)
+#define EEPROM_RST_INTR_DISBL 0x0
+#define BUFFER_MODE_INTR_ENBL 0x001F
+#define BUFFER_MODE_INTR_DISBL 0x0
+#define NORMAL_MODE 0x0
+#define BUFFER_MODE 0x1
+#define EEPROM_SR_MODE 0x2
+#define I2C_TX_MODE 0x0010
+#define PCH_BUF_TX 0xFFF7
+#define PCH_BUF_RD 0x0008
+#define I2C_ERROR_MASK (I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \
+ I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT)
+#define I2CMAL_EVENT 0x0001
+#define I2CMCF_EVENT 0x0002
+#define I2CBMFI_EVENT 0x0004
+#define I2CBMAL_EVENT 0x0008
+#define I2CBMNA_EVENT 0x0010
+#define I2CBMTO_EVENT 0x0020
+#define I2CBMIS_EVENT 0x0040
+#define I2CESRFI_EVENT 0x0080
+#define I2CESRTO_EVENT 0x0100
+#define PCI_DEVICE_ID_PCH_I2C 0x8817
+
+#define pch_dbg(adap, fmt, arg...) \
+ dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_err(adap, fmt, arg...) \
+ dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_err(pdev, fmt, arg...) \
+ dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_dbg(pdev, fmt, arg...) \
+ dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+/*
+Set the number of I2C instance max
+Intel EG20T PCH : 1ch
+OKI SEMICONDUCTOR ML7213 IOH : 2ch
+*/
+#define PCH_I2C_MAX_DEV 2
+
+/**
+ * struct i2c_algo_pch_data - for I2C driver functionalities
+ * @pch_adapter: stores the reference to i2c_adapter structure
+ * @p_adapter_info: stores the reference to adapter_info structure
+ * @pch_base_address: specifies the remapped base address
+ * @pch_buff_mode_en: specifies if buffer mode is enabled
+ * @pch_event_flag: specifies occurrence of interrupt events
+ * @pch_i2c_xfer_in_progress: specifies whether the transfer is completed
+ */
+struct i2c_algo_pch_data {
+ struct i2c_adapter pch_adapter;
+ struct adapter_info *p_adapter_info;
+ void __iomem *pch_base_address;
+ int pch_buff_mode_en;
+ u32 pch_event_flag;
+ bool pch_i2c_xfer_in_progress;
+};
+
+/**
+ * struct adapter_info - This structure holds the adapter information for the
+ PCH i2c controller
+ * @pch_data: stores a list of i2c_algo_pch_data
+ * @pch_i2c_suspended: specifies whether the system is suspended or not
+ * perhaps with more lines and words.
+ * @ch_num: specifies the number of i2c instance
+ *
+ * pch_data has as many elements as maximum I2C channels
+ */
+struct adapter_info {
+ struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
+ bool pch_i2c_suspended;
+ int ch_num;
+};
+
+
+static int pch_i2c_speed = 100; /* I2C bus speed in Kbps */
+static int pch_clk = 50000; /* specifies I2C clock speed in KHz */
+static wait_queue_head_t pch_event;
+static DEFINE_MUTEX(pch_mutex);
+
+/* Definition for ML7213 by OKI SEMICONDUCTOR */
+#define PCI_VENDOR_ID_ROHM 0x10DB
+#define PCI_DEVICE_ID_ML7213_I2C 0x802D
+#define PCI_DEVICE_ID_ML7223_I2C 0x8010
+
+static struct pci_device_id __devinitdata pch_pcidev_id[] = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
+ {0,}
+};
+
+static irqreturn_t pch_i2c_handler(int irq, void *pData);
+
+static inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+ u32 val;
+ val = ioread32(addr + offset);
+ val |= bitmask;
+ iowrite32(val, addr + offset);
+}
+
+static inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+ u32 val;
+ val = ioread32(addr + offset);
+ val &= (~bitmask);
+ iowrite32(val, addr + offset);
+}
+
+/**
+ * pch_i2c_init() - hardware initialization of I2C module
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_init(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ u32 pch_i2cbc;
+ u32 pch_i2ctmr;
+ u32 reg_value;
+
+ /* reset I2C controller */
+ iowrite32(0x01, p + PCH_I2CSRST);
+ msleep(20);
+ iowrite32(0x0, p + PCH_I2CSRST);
+
+ /* Initialize I2C registers */
+ iowrite32(0x21, p + PCH_I2CNF);
+
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);
+
+ if (pch_i2c_speed != 400)
+ pch_i2c_speed = 100;
+
+ reg_value = PCH_I2CCTL_I2CMEN;
+ if (pch_i2c_speed == FAST_MODE_CLK) {
+ reg_value |= FAST_MODE_EN;
+ pch_dbg(adap, "Fast mode enabled\n");
+ }
+
+ if (pch_clk > PCH_MAX_CLK)
+ pch_clk = 62500;
+
+ pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8);
+ /* Set transfer speed in I2CBC */
+ iowrite32(pch_i2cbc, p + PCH_I2CBC);
+
+ pch_i2ctmr = (pch_clk) / 8;
+ iowrite32(pch_i2ctmr, p + PCH_I2CTMR);
+
+ reg_value |= NORMAL_INTR_ENBL; /* Enable interrupts in normal mode */
+ iowrite32(reg_value, p + PCH_I2CCTL);
+
+ pch_dbg(adap,
+ "I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts\n",
+ ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr);
+
+ init_waitqueue_head(&pch_event);
+}
+
+static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
+{
+ return cmp1.tv64 < cmp2.tv64;
+}
+
+/**
+ * pch_i2c_wait_for_bus_idle() - check the status of bus.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ * @timeout: waiting time counter (us).
+ */
+static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
+ s32 timeout)
+{
+ void __iomem *p = adap->pch_base_address;
+
+ /* MAX timeout value is timeout*1000*1000nsec */
+ ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
+ do {
+ if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
+ break;
+ msleep(20);
+ } while (ktime_lt(ktime_get(), ns_val));
+
+ pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+
+ if (timeout == 0) {
+ pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_i2c_start() - Generate I2C start condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1.
+ */
+static void pch_i2c_start(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_wait_for_xfer_complete() - initiates a wait for the tx complete event
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap)
+{
+ s32 ret;
+ ret = wait_event_timeout(pch_event,
+ (adap->pch_event_flag != 0), msecs_to_jiffies(50));
+ if (ret < 0) {
+ pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
+ return ret;
+ }
+
+ if (ret == 0) {
+ pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
+ return -ETIMEDOUT;
+ }
+
+ if (adap->pch_event_flag & I2C_ERROR_MASK) {
+ pch_err(adap, "error bits set: %x\n", adap->pch_event_flag);
+ return -EIO;
+ }
+
+ adap->pch_event_flag = 0;
+
+ return 0;
+}
+
+/**
+ * pch_i2c_getack() - to confirm ACK/NACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap)
+{
+ u32 reg_val;
+ void __iomem *p = adap->pch_base_address;
+ reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK;
+
+ if (reg_val != 0) {
+ pch_err(adap, "return%d\n", -EPROTO);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_i2c_stop() - generate stop condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_stop(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ /* clear the start bit */
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_repstart() - generate repeated start condition in normal mode
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_repstart(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART);
+}
+
+/**
+ * pch_i2c_writebytes() - write data to I2C bus in normal mode
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @last: specifies whether last message or not.
+ * In the case of compound mode it will be 1 for last message,
+ * otherwise 0.
+ * @first: specifies whether first message or not.
+ * 1 for first message otherwise 0.
+ */
+static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, u32 last, u32 first)
+{
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+ u8 *buf;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ u32 addr_8_lsb;
+ s32 wrcount;
+ void __iomem *p = adap->pch_base_address;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master tx */
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+ pch_dbg(adap, "I2CCTL = %x msgs->len = %d\n", ioread32(p + PCH_I2CCTL),
+ length);
+
+ if (first) {
+ if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+ return -ETIME;
+ }
+
+ if (msgs->flags & I2C_M_TEN) {
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+ if (pch_i2c_wait_for_xfer_complete(adap) == 0 &&
+ pch_i2c_getack(adap) == 0) {
+ addr_8_lsb = (addr & I2C_ADDR_MSK);
+ iowrite32(addr_8_lsb, p + PCH_I2CDR);
+ } else {
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
+ } else {
+ /* set 7 bit slave address and R/W bit as 0 */
+ iowrite32(addr << 1, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+ }
+
+ if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
+ (pch_i2c_getack(adap) == 0)) {
+ for (wrcount = 0; wrcount < length; ++wrcount) {
+ /* write buffer value to I2C data register */
+ iowrite32(buf[wrcount], p + PCH_I2CDR);
+ pch_dbg(adap, "writing %x to Data register\n",
+ buf[wrcount]);
+
+ if (pch_i2c_wait_for_xfer_complete(adap) != 0)
+ return -ETIME;
+
+ if (pch_i2c_getack(adap))
+ return -EIO;
+ }
+
+ /* check if this is the last message */
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+ } else {
+ pch_i2c_stop(adap);
+ return -EIO;
+ }
+
+ pch_dbg(adap, "return=%d\n", wrcount);
+
+ return wrcount;
+}
+
+/**
+ * pch_i2c_sendack() - send ACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendack(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_sendnack() - send NACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_readbytes() - read data from I2C bus in normal mode.
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @msgs: Pointer to i2c_msg structure.
+ * @last: specifies whether last message or not.
+ * @first: specifies whether first message or not.
+ */
+static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ u32 last, u32 first)
+{
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+ u8 *buf;
+ u32 count;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ void __iomem *p = adap->pch_base_address;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master reception */
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+ if (first) {
+ if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+ return -ETIME;
+ }
+
+ if (msgs->flags & I2C_M_TEN) {
+ addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD));
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+
+ } else {
+ /* 7 address bits + R/W bit */
+ addr = (((addr) << 1) | (I2C_RD));
+ iowrite32(addr, p + PCH_I2CDR);
+ }
+
+ /* check if it is the first message */
+ if (first)
+ pch_i2c_start(adap);
+
+ if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
+ (pch_i2c_getack(adap) == 0)) {
+ pch_dbg(adap, "return %d\n", 0);
+
+ if (length == 0) {
+ pch_i2c_stop(adap);
+ ioread32(p + PCH_I2CDR); /* Dummy read needs */
+
+ count = length;
+ } else {
+ int read_index;
+ int loop;
+ pch_i2c_sendack(adap);
+
+ /* Dummy read */
+ for (loop = 1, read_index = 0; loop < length; loop++) {
+ buf[read_index] = ioread32(p + PCH_I2CDR);
+
+ if (loop != 1)
+ read_index++;
+
+ if (pch_i2c_wait_for_xfer_complete(adap) != 0) {
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
+ } /* end for */
+
+ pch_i2c_sendnack(adap);
+
+ buf[read_index] = ioread32(p + PCH_I2CDR);
+
+ if (length != 1)
+ read_index++;
+
+ if (pch_i2c_wait_for_xfer_complete(adap) == 0) {
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+
+ buf[read_index++] = ioread32(p + PCH_I2CDR);
+ count = read_index;
+ } else {
+ count = -ETIME;
+ }
+
+ }
+ } else {
+ count = -ETIME;
+ pch_i2c_stop(adap);
+ }
+
+ return count;
+}
+
+/**
+ * pch_i2c_cb() - Interrupt handler Call back function
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
+{
+ u32 sts;
+ void __iomem *p = adap->pch_base_address;
+
+ sts = ioread32(p + PCH_I2CSR);
+ sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT);
+ if (sts & I2CMAL_BIT)
+ adap->pch_event_flag |= I2CMAL_EVENT;
+
+ if (sts & I2CMCF_BIT)
+ adap->pch_event_flag |= I2CMCF_EVENT;
+
+ /* clear the applicable bits */
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts);
+
+ pch_dbg(adap, "PCH_I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+
+ wake_up(&pch_event);
+}
+
+/**
+ * pch_i2c_handler() - interrupt handler for the PCH I2C controller
+ * @irq: irq number.
+ * @pData: cookie passed back to the handler function.
+ */
+static irqreturn_t pch_i2c_handler(int irq, void *pData)
+{
+ u32 reg_val;
+ int flag;
+ int i;
+ struct adapter_info *adap_info = pData;
+ void __iomem *p;
+ u32 mode;
+
+ for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
+ p = adap_info->pch_data[i].pch_base_address;
+ mode = ioread32(p + PCH_I2CMOD);
+ mode &= BUFFER_MODE | EEPROM_SR_MODE;
+ if (mode != NORMAL_MODE) {
+ pch_err(adap_info->pch_data,
+ "I2C-%d mode(%d) is not supported\n", mode, i);
+ continue;
+ }
+ reg_val = ioread32(p + PCH_I2CSR);
+ if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
+ pch_i2c_cb(&adap_info->pch_data[i]);
+ flag = 1;
+ }
+ }
+
+ return flag ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * pch_i2c_xfer() - Reading adnd writing data through I2C bus
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @msgs: Pointer to i2c_msg structure.
+ * @num: number of messages.
+ */
+static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, s32 num)
+{
+ struct i2c_msg *pmsg;
+ u32 i = 0;
+ u32 status;
+ u32 msglen;
+ u32 subaddrlen;
+ s32 ret;
+
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+ ret = mutex_lock_interruptible(&pch_mutex);
+ if (ret)
+ return -ERESTARTSYS;
+
+ if (adap->p_adapter_info->pch_i2c_suspended) {
+ mutex_unlock(&pch_mutex);
+ return -EBUSY;
+ }
+
+ pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d\n",
+ adap->p_adapter_info->pch_i2c_suspended);
+ /* transfer not completed */
+ adap->pch_i2c_xfer_in_progress = true;
+
+ pmsg = &msgs[0];
+ pmsg->flags |= adap->pch_buff_mode_en;
+ status = pmsg->flags;
+ pch_dbg(adap,
+ "After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
+ /* calculate sub address length and message length */
+ /* these are applicable only for buffer mode */
+ subaddrlen = pmsg->buf[0];
+ /* calculate actual message length excluding
+ * the sub address fields */
+ msglen = (pmsg->len) - (subaddrlen + 1);
+ if (status & (I2C_M_RD)) {
+ pch_dbg(adap, "invoking pch_i2c_readbytes\n");
+ ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ } else {
+ pch_dbg(adap, "invoking pch_i2c_writebytes\n");
+ ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ }
+
+ adap->pch_i2c_xfer_in_progress = false; /* transfer completed */
+
+ mutex_unlock(&pch_mutex);
+
+ return ret;
+}
+
+/**
+ * pch_i2c_func() - return the functionality of the I2C driver
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static u32 pch_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static struct i2c_algorithm pch_algorithm = {
+ .master_xfer = pch_i2c_xfer,
+ .functionality = pch_i2c_func
+};
+
+/**
+ * pch_i2c_disbl_int() - Disable PCH I2C interrupts
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL);
+
+ iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK);
+
+ iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK);
+}
+
+static int __devinit pch_i2c_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *base_addr;
+ int ret;
+ int i, j;
+ struct adapter_info *adap_info;
+ struct i2c_adapter *pch_adap;
+
+ pch_pci_dbg(pdev, "Entered.\n");
+
+ adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
+ if (adap_info == NULL) {
+ pch_pci_err(pdev, "Memory allocation FAILED\n");
+ return -ENOMEM;
+ }
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ pch_pci_err(pdev, "pci_enable_device FAILED\n");
+ goto err_pci_enable;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ pch_pci_err(pdev, "pci_request_regions FAILED\n");
+ goto err_pci_req;
+ }
+
+ base_addr = pci_iomap(pdev, 1, 0);
+
+ if (base_addr == NULL) {
+ pch_pci_err(pdev, "pci_iomap FAILED\n");
+ ret = -ENOMEM;
+ goto err_pci_iomap;
+ }
+
+ /* Set the number of I2C channel instance */
+ adap_info->ch_num = id->driver_data;
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ pch_adap = &adap_info->pch_data[i].pch_adapter;
+ adap_info->pch_i2c_suspended = false;
+
+ adap_info->pch_data[i].p_adapter_info = adap_info;
+
+ pch_adap->owner = THIS_MODULE;
+ pch_adap->class = I2C_CLASS_HWMON;
+ strcpy(pch_adap->name, KBUILD_MODNAME);
+ pch_adap->algo = &pch_algorithm;
+ pch_adap->algo_data = &adap_info->pch_data[i];
+
+ /* base_addr + offset; */
+ adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
+
+ pch_adap->dev.parent = &pdev->dev;
+
+ ret = i2c_add_adapter(pch_adap);
+ if (ret) {
+ pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
+ goto err_i2c_add_adapter;
+ }
+
+ pch_i2c_init(&adap_info->pch_data[i]);
+ }
+ ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+ KBUILD_MODNAME, adap_info);
+ if (ret) {
+ pch_pci_err(pdev, "request_irq FAILED\n");
+ goto err_i2c_add_adapter;
+ }
+
+ pci_set_drvdata(pdev, adap_info);
+ pch_pci_dbg(pdev, "returns %d.\n", ret);
+ return 0;
+
+err_i2c_add_adapter:
+ for (j = 0; j < i; j++)
+ i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
+ pci_iounmap(pdev, base_addr);
+err_pci_iomap:
+ pci_release_regions(pdev);
+err_pci_req:
+ pci_disable_device(pdev);
+err_pci_enable:
+ kfree(adap_info);
+ return ret;
+}
+
+static void __devexit pch_i2c_remove(struct pci_dev *pdev)
+{
+ int i;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ free_irq(pdev->irq, adap_info);
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ pch_i2c_disbl_int(&adap_info->pch_data[i]);
+ i2c_del_adapter(&adap_info->pch_data[i].pch_adapter);
+ }
+
+ if (adap_info->pch_data[0].pch_base_address)
+ pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
+
+ for (i = 0; i < adap_info->ch_num; i++)
+ adap_info->pch_data[i].pch_base_address = 0;
+
+ pci_set_drvdata(pdev, NULL);
+
+ pci_release_regions(pdev);
+
+ pci_disable_device(pdev);
+ kfree(adap_info);
+}
+
+#ifdef CONFIG_PM
+static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int ret;
+ int i;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+ void __iomem *p = adap_info->pch_data[0].pch_base_address;
+
+ adap_info->pch_i2c_suspended = true;
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
+ /* Wait until all channel transfers are completed */
+ msleep(20);
+ }
+ }
+
+ /* Disable the i2c interrupts */
+ for (i = 0; i < adap_info->ch_num; i++)
+ pch_i2c_disbl_int(&adap_info->pch_data[i]);
+
+ pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
+ "invoked function pch_i2c_disbl_int successfully\n",
+ ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
+ ioread32(p + PCH_I2CESRSTA));
+
+ ret = pci_save_state(pdev);
+
+ if (ret) {
+ pch_pci_err(pdev, "pci_save_state\n");
+ return ret;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int pch_i2c_resume(struct pci_dev *pdev)
+{
+ int i;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (pci_enable_device(pdev) < 0) {
+ pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED\n");
+ return -EIO;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ for (i = 0; i < adap_info->ch_num; i++)
+ pch_i2c_init(&adap_info->pch_data[i]);
+
+ adap_info->pch_i2c_suspended = false;
+
+ return 0;
+}
+#else
+#define pch_i2c_suspend NULL
+#define pch_i2c_resume NULL
+#endif
+
+static struct pci_driver pch_pcidriver = {
+ .name = KBUILD_MODNAME,
+ .id_table = pch_pcidev_id,
+ .probe = pch_i2c_probe,
+ .remove = __devexit_p(pch_i2c_remove),
+ .suspend = pch_i2c_suspend,
+ .resume = pch_i2c_resume
+};
+
+static int __init pch_pci_init(void)
+{
+ return pci_register_driver(&pch_pcidriver);
+}
+module_init(pch_pci_init);
+
+static void __exit pch_pci_exit(void)
+{
+ pci_unregister_driver(&pch_pcidriver);
+}
+module_exit(pch_pci_exit);
+
+MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>");
+module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
+module_param(pch_clk, int, (S_IRUSR | S_IWUSR));
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
new file mode 100644
index 00000000..37e2e82a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -0,0 +1,347 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+ 1998-99 Hans Berglund
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+ Frodo Looijaard <frodol@dds.nl> */
+
+/* Partially rewriten by Oleg I. Vdovikin for mmapped support of
+ for Alpha Processor Inc. UP-2000(+) boards */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+
+#include <linux/isa.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include "../algos/i2c-algo-pcf.h"
+
+#define DEFAULT_BASE 0x330
+
+static int base;
+static u8 __iomem *base_iomem;
+
+static int irq;
+static int clock = 0x1c;
+static int own = 0x55;
+static int mmapped;
+
+/* vdovikin: removed static struct i2c_pcf_isa gpi; code -
+ this module in real supports only one device, due to missing arguments
+ in some functions, called from the algo-pcf module. Sometimes it's
+ need to be rewriten - but for now just remove this for simpler reading */
+
+static wait_queue_head_t pcf_wait;
+static int pcf_pending;
+static spinlock_t lock;
+
+static struct i2c_adapter pcf_isa_ops;
+
+/* ----- local functions ---------------------------------------------- */
+
+static void pcf_isa_setbyte(void *data, int ctl, int val)
+{
+ u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
+
+ /* enable irq if any specified for serial operation */
+ if (ctl && irq && (val & I2C_PCF_ESO)) {
+ val |= I2C_PCF_ENI;
+ }
+
+ pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val);
+ iowrite8(val, address);
+#ifdef __alpha__
+ /* API UP2000 needs some hardware fudging to make the write stick */
+ iowrite8(val, address);
+#endif
+}
+
+static int pcf_isa_getbyte(void *data, int ctl)
+{
+ u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
+ int val = ioread8(address);
+
+ pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val);
+ return (val);
+}
+
+static int pcf_isa_getown(void *data)
+{
+ return (own);
+}
+
+
+static int pcf_isa_getclock(void *data)
+{
+ return (clock);
+}
+
+static void pcf_isa_waitforpin(void *data)
+{
+ DEFINE_WAIT(wait);
+ int timeout = 2;
+ unsigned long flags;
+
+ if (irq > 0) {
+ spin_lock_irqsave(&lock, flags);
+ if (pcf_pending == 0) {
+ spin_unlock_irqrestore(&lock, flags);
+ prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
+ if (schedule_timeout(timeout*HZ)) {
+ spin_lock_irqsave(&lock, flags);
+ if (pcf_pending == 1) {
+ pcf_pending = 0;
+ }
+ spin_unlock_irqrestore(&lock, flags);
+ }
+ finish_wait(&pcf_wait, &wait);
+ } else {
+ pcf_pending = 0;
+ spin_unlock_irqrestore(&lock, flags);
+ }
+ } else {
+ udelay(100);
+ }
+}
+
+
+static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
+ spin_lock(&lock);
+ pcf_pending = 1;
+ spin_unlock(&lock);
+ wake_up_interruptible(&pcf_wait);
+ return IRQ_HANDLED;
+}
+
+
+static int pcf_isa_init(void)
+{
+ spin_lock_init(&lock);
+ if (!mmapped) {
+ if (!request_region(base, 2, pcf_isa_ops.name)) {
+ printk(KERN_ERR "%s: requested I/O region (%#x:2) is "
+ "in use\n", pcf_isa_ops.name, base);
+ return -ENODEV;
+ }
+ base_iomem = ioport_map(base, 2);
+ if (!base_iomem) {
+ printk(KERN_ERR "%s: remap of I/O region %#x failed\n",
+ pcf_isa_ops.name, base);
+ release_region(base, 2);
+ return -ENODEV;
+ }
+ } else {
+ if (!request_mem_region(base, 2, pcf_isa_ops.name)) {
+ printk(KERN_ERR "%s: requested memory region (%#x:2) "
+ "is in use\n", pcf_isa_ops.name, base);
+ return -ENODEV;
+ }
+ base_iomem = ioremap(base, 2);
+ if (base_iomem == NULL) {
+ printk(KERN_ERR "%s: remap of memory region %#x "
+ "failed\n", pcf_isa_ops.name, base);
+ release_mem_region(base, 2);
+ return -ENODEV;
+ }
+ }
+ pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base,
+ base_iomem);
+
+ if (irq > 0) {
+ if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name,
+ NULL) < 0) {
+ printk(KERN_ERR "%s: Request irq%d failed\n",
+ pcf_isa_ops.name, irq);
+ irq = 0;
+ } else
+ enable_irq(irq);
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+static struct i2c_algo_pcf_data pcf_isa_data = {
+ .setpcf = pcf_isa_setbyte,
+ .getpcf = pcf_isa_getbyte,
+ .getown = pcf_isa_getown,
+ .getclock = pcf_isa_getclock,
+ .waitforpin = pcf_isa_waitforpin,
+};
+
+static struct i2c_adapter pcf_isa_ops = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo_data = &pcf_isa_data,
+ .name = "i2c-elektor",
+};
+
+static int __devinit elektor_match(struct device *dev, unsigned int id)
+{
+#ifdef __alpha__
+ /* check to see we have memory mapped PCF8584 connected to the
+ Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
+ if (base == 0) {
+ struct pci_dev *cy693_dev;
+
+ cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
+ PCI_DEVICE_ID_CONTAQ_82C693, NULL);
+ if (cy693_dev) {
+ unsigned char config;
+ /* yeap, we've found cypress, let's check config */
+ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
+
+ dev_dbg(dev, "found cy82c693, config "
+ "register 0x47 = 0x%02x\n", config);
+
+ /* UP2000 board has this register set to 0xe1,
+ but the most significant bit as seems can be
+ reset during the proper initialisation
+ sequence if guys from API decides to do that
+ (so, we can even enable Tsunami Pchip
+ window for the upper 1 Gb) */
+
+ /* so just check for ROMCS at 0xe0000,
+ ROMCS enabled for writes
+ and external XD Bus buffer in use. */
+ if ((config & 0x7f) == 0x61) {
+ /* seems to be UP2000 like board */
+ base = 0xe0000;
+ mmapped = 1;
+ /* UP2000 drives ISA with
+ 8.25 MHz (PCI/4) clock
+ (this can be read from cypress) */
+ clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
+ dev_info(dev, "found API UP2000 like "
+ "board, will probe PCF8584 "
+ "later\n");
+ }
+ }
+ pci_dev_put(cy693_dev);
+ }
+ }
+#endif
+
+ /* sanity checks for mmapped I/O */
+ if (mmapped && base < 0xc8000) {
+ dev_err(dev, "incorrect base address (%#x) specified "
+ "for mmapped I/O\n", base);
+ return 0;
+ }
+
+ if (base == 0) {
+ base = DEFAULT_BASE;
+ }
+ return 1;
+}
+
+static int __devinit elektor_probe(struct device *dev, unsigned int id)
+{
+ init_waitqueue_head(&pcf_wait);
+ if (pcf_isa_init())
+ return -ENODEV;
+ pcf_isa_ops.dev.parent = dev;
+ if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+ goto fail;
+
+ dev_info(dev, "found device at %#x\n", base);
+
+ return 0;
+
+ fail:
+ if (irq > 0) {
+ disable_irq(irq);
+ free_irq(irq, NULL);
+ }
+
+ if (!mmapped) {
+ ioport_unmap(base_iomem);
+ release_region(base, 2);
+ } else {
+ iounmap(base_iomem);
+ release_mem_region(base, 2);
+ }
+ return -ENODEV;
+}
+
+static int __devexit elektor_remove(struct device *dev, unsigned int id)
+{
+ i2c_del_adapter(&pcf_isa_ops);
+
+ if (irq > 0) {
+ disable_irq(irq);
+ free_irq(irq, NULL);
+ }
+
+ if (!mmapped) {
+ ioport_unmap(base_iomem);
+ release_region(base, 2);
+ } else {
+ iounmap(base_iomem);
+ release_mem_region(base, 2);
+ }
+
+ return 0;
+}
+
+static struct isa_driver i2c_elektor_driver = {
+ .match = elektor_match,
+ .probe = elektor_probe,
+ .remove = __devexit_p(elektor_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-elektor",
+ },
+};
+
+static int __init i2c_pcfisa_init(void)
+{
+ return isa_register_driver(&i2c_elektor_driver, 1);
+}
+
+static void __exit i2c_pcfisa_exit(void)
+{
+ isa_unregister_driver(&i2c_elektor_driver);
+}
+
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
+MODULE_LICENSE("GPL");
+
+module_param(base, int, 0);
+module_param(irq, int, 0);
+module_param(clock, int, 0);
+module_param(own, int, 0);
+module_param(mmapped, int, 0);
+
+module_init(i2c_pcfisa_init);
+module_exit(i2c_pcfisa_exit);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 00000000..a651779d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,225 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 Atmel 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.
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#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>
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ if (state)
+ gpio_direction_input(pdata->sda_pin);
+ else
+ gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ if (state)
+ gpio_direction_input(pdata->scl_pin);
+ else
+ gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->scl_pin, state);
+}
+
+static int i2c_gpio_getsda(void *data)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->sda_pin);
+}
+
+static int i2c_gpio_getscl(void *data)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->scl_pin);
+}
+
+static int __devinit i2c_gpio_probe(struct platform_device *pdev)
+{
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_algo_bit_data *bit_data;
+ struct i2c_adapter *adap;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENXIO;
+
+ ret = -ENOMEM;
+ adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!adap)
+ goto err_alloc_adap;
+ bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
+ if (!bit_data)
+ goto err_alloc_bit_data;
+
+ ret = gpio_request(pdata->sda_pin, "sda");
+ if (ret)
+ goto err_request_sda;
+ ret = gpio_request(pdata->scl_pin, "scl");
+ if (ret)
+ goto err_request_scl;
+
+ if (pdata->sda_is_open_drain) {
+ gpio_direction_output(pdata->sda_pin, 1);
+ bit_data->setsda = i2c_gpio_setsda_val;
+ } else {
+ gpio_direction_input(pdata->sda_pin);
+ bit_data->setsda = i2c_gpio_setsda_dir;
+ }
+
+ if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+ gpio_direction_output(pdata->scl_pin, 1);
+ bit_data->setscl = i2c_gpio_setscl_val;
+ } else {
+ gpio_direction_input(pdata->scl_pin);
+ bit_data->setscl = i2c_gpio_setscl_dir;
+ }
+
+ if (!pdata->scl_is_output_only)
+ bit_data->getscl = i2c_gpio_getscl;
+ bit_data->getsda = i2c_gpio_getsda;
+
+ if (pdata->udelay)
+ bit_data->udelay = pdata->udelay;
+ else if (pdata->scl_is_output_only)
+ bit_data->udelay = 50; /* 10 kHz */
+ else
+ bit_data->udelay = 5; /* 100 kHz */
+
+ if (pdata->timeout)
+ bit_data->timeout = pdata->timeout;
+ else
+ bit_data->timeout = HZ / 10; /* 100 ms */
+
+ bit_data->data = pdata;
+
+ adap->owner = THIS_MODULE;
+ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+ adap->algo_data = bit_data;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->dev.parent = &pdev->dev;
+
+ /*
+ * If "dev->id" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ adap->nr = (pdev->id != -1) ? pdev->id : 0;
+ ret = i2c_bit_add_numbered_bus(adap);
+ if (ret)
+ goto err_add_bus;
+
+ platform_set_drvdata(pdev, adap);
+
+ dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
+ pdata->sda_pin, pdata->scl_pin,
+ pdata->scl_is_output_only
+ ? ", no clock stretching" : "");
+
+ return 0;
+
+err_add_bus:
+ gpio_free(pdata->scl_pin);
+err_request_scl:
+ gpio_free(pdata->sda_pin);
+err_request_sda:
+ kfree(bit_data);
+err_alloc_bit_data:
+ kfree(adap);
+err_alloc_adap:
+ return ret;
+}
+
+static int __devexit i2c_gpio_remove(struct platform_device *pdev)
+{
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_adapter *adap;
+
+ adap = platform_get_drvdata(pdev);
+ pdata = pdev->dev.platform_data;
+
+ i2c_del_adapter(adap);
+ gpio_free(pdata->scl_pin);
+ gpio_free(pdata->sda_pin);
+ kfree(adap->algo_data);
+ kfree(adap);
+
+ return 0;
+}
+
+static struct platform_driver i2c_gpio_driver = {
+ .driver = {
+ .name = "i2c-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2c_gpio_probe,
+ .remove = __devexit_p(i2c_gpio_remove),
+};
+
+static int __init i2c_gpio_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&i2c_gpio_driver);
+ if (ret)
+ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+ platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-gpio");
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
new file mode 100644
index 00000000..3df1bc80
--- /dev/null
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -0,0 +1,498 @@
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008 Paul Mundt
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Copyright (C) 2008 Atom Create Engineering Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file "COPYING" in the main directory
+ * of this archive for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#define SMCR 0x00
+#define SMCR_START (1 << 0)
+#define SMCR_IRIC (1 << 1)
+#define SMCR_BBSY (1 << 2)
+#define SMCR_ACKE (1 << 3)
+#define SMCR_RST (1 << 4)
+#define SMCR_IEIC (1 << 6)
+
+#define SMSMADR 0x02
+
+#define SMMR 0x04
+#define SMMR_MODE0 (1 << 0)
+#define SMMR_MODE1 (1 << 1)
+#define SMMR_CAP (1 << 3)
+#define SMMR_TMMD (1 << 4)
+#define SMMR_SP (1 << 7)
+
+#define SMSADR 0x06
+#define SMTRDR 0x46
+
+struct highlander_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_adapter adapter;
+ struct completion cmd_complete;
+ unsigned long last_read_time;
+ int irq;
+ u8 *buf;
+ size_t buf_len;
+};
+
+static int iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+ u16 smmr;
+
+ smmr = ioread16(dev->base + SMMR);
+ smmr |= SMMR_TMMD;
+
+ if (iic_force_normal)
+ smmr &= ~SMMR_SP;
+ else
+ smmr |= SMMR_SP;
+
+ iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *dst++ = be16_to_cpup((__be16 *)src);
+ src += 2;
+ }
+
+ if (len)
+ *dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *(__be16 *)dst = cpu_to_be16p(src++);
+ dst += 2;
+ }
+
+ if (len)
+ *dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+ u8 command, int len)
+{
+ unsigned int i;
+ u16 cmd = (command << 8) | command;
+
+ for (i = 0; i < len; i += 2) {
+ if (len - i == 1)
+ cmd = command << 8;
+ iowrite16(cmd, dev->base + SMSADR + i);
+ dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+ }
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+ return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+ u16 tmp = ioread16(dev->base + SMCR);
+
+ if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+ dev_warn(dev->dev, "ack abnormality\n");
+ return highlander_i2c_reset(dev);
+ }
+
+ return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+ struct highlander_i2c_dev *dev = dev_id;
+
+ highlander_i2c_done(dev);
+ complete(&dev->cmd_complete);
+
+ return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+ u16 smcr;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ for (;;) {
+ smcr = ioread16(dev->base + SMCR);
+
+ /*
+ * Don't bother checking ACKE here, this and the reset
+ * are handled in highlander_i2c_wait_xfer_done() when
+ * waiting for the ACK.
+ */
+
+ if (smcr & SMCR_IRIC)
+ return;
+ if (time_after(jiffies, timeout))
+ break;
+
+ cpu_relax();
+ cond_resched();
+ }
+
+ dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+ if (dev->irq)
+ wait_for_completion_timeout(&dev->cmd_complete,
+ msecs_to_jiffies(iic_timeout));
+ else
+ /* busy looping, the IRQ of champions */
+ highlander_i2c_poll(dev);
+
+ return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ if (highlander_i2c_wait_xfer_done(dev)) {
+ dev_err(dev->dev, "Arbitration loss\n");
+ return -EAGAIN;
+ }
+
+ /*
+ * The R0P7780LC0011RL FPGA needs a significant delay between
+ * data read cycles, otherwise the transciever gets confused and
+ * garbage is returned when the read is subsequently aborted.
+ *
+ * It is not sufficient to wait for BBSY.
+ *
+ * While this generally only applies to the older SH7780-based
+ * Highlanders, the same issue can be observed on SH7785 ones,
+ * albeit less frequently. SH7780-based Highlanders may need
+ * this to be as high as 1000 ms.
+ */
+ if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)))
+ msleep(jiffies_to_msecs((dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ smbus_read_data(data, dev->buf, dev->buf_len);
+
+ dev->last_read_time = jiffies;
+
+ return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ smbus_write_data(dev->buf, data, dev->buf_len);
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+ u16 tmp;
+
+ init_completion(&dev->cmd_complete);
+
+ dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+ addr, command, read_write, size);
+
+ /*
+ * Set up the buffer and transfer size
+ */
+ switch (size) {
+ case I2C_SMBUS_BYTE_DATA:
+ dev->buf = &data->byte;
+ dev->buf_len = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ dev->buf = &data->block[1];
+ dev->buf_len = data->block[0];
+ break;
+ default:
+ dev_err(dev->dev, "unsupported command %d\n", size);
+ return -EINVAL;
+ }
+
+ /*
+ * Encode the mode setting
+ */
+ tmp = ioread16(dev->base + SMMR);
+ tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+ switch (dev->buf_len) {
+ case 1:
+ /* default */
+ break;
+ case 8:
+ tmp |= SMMR_MODE0;
+ break;
+ case 16:
+ tmp |= SMMR_MODE1;
+ break;
+ case 32:
+ tmp |= (SMMR_MODE0 | SMMR_MODE1);
+ break;
+ default:
+ dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+ return -EINVAL;
+ }
+
+ iowrite16(tmp, dev->base + SMMR);
+
+ /* Ensure we're in a sane state */
+ highlander_i2c_done(dev);
+
+ /* Set slave address */
+ iowrite16((addr << 1) | read_write, dev->base + SMSMADR);
+
+ highlander_i2c_command(dev, command, dev->buf_len);
+
+ if (read_write == I2C_SMBUS_READ)
+ return highlander_i2c_read(dev);
+ else
+ return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+ .smbus_xfer = highlander_i2c_smbus_xfer,
+ .functionality = highlander_i2c_func,
+};
+
+static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -ENODEV;
+ }
+
+ dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+ if (unlikely(!dev))
+ return -ENOMEM;
+
+ dev->base = ioremap_nocache(res->start, resource_size(res));
+ if (unlikely(!dev->base)) {
+ ret = -ENXIO;
+ goto err;
+ }
+
+ dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dev);
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (iic_force_poll)
+ dev->irq = 0;
+
+ if (dev->irq) {
+ ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
+ pdev->name, dev);
+ if (unlikely(ret))
+ goto err_unmap;
+
+ highlander_i2c_irq_enable(dev);
+ } else {
+ dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+ highlander_i2c_irq_disable(dev);
+ }
+
+ dev->last_read_time = jiffies; /* initial read jiffies */
+
+ highlander_i2c_setup(dev);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+ adap->algo = &highlander_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+
+ /*
+ * Reset the adapter
+ */
+ ret = highlander_i2c_reset(dev);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "controller didn't come up\n");
+ goto err_free_irq;
+ }
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+err_unmap:
+ iounmap(dev->base);
+err:
+ kfree(dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+ .driver = {
+ .name = "i2c-highlander",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = highlander_i2c_probe,
+ .remove = __devexit_p(highlander_i2c_remove),
+};
+
+static int __init highlander_i2c_init(void)
+{
+ return platform_driver_register(&highlander_i2c_driver);
+}
+
+static void __exit highlander_i2c_exit(void)
+{
+ platform_driver_unregister(&highlander_i2c_driver);
+}
+
+module_init(highlander_i2c_init);
+module_exit(highlander_i2c_exit);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+ "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+ "Delay between data read cycles (default 0 ms)");
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
new file mode 100644
index 00000000..9ff1695d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -0,0 +1,178 @@
+/*
+ i2c Support for the Apple `Hydra' Mac I/O
+
+ Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org>
+
+ Based on i2c Support for Via Technologies 82C586B South Bridge
+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ 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/pci.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/hydra.h>
+
+
+#define HYDRA_CPD_PD0 0x00000001 /* CachePD lines */
+#define HYDRA_CPD_PD1 0x00000002
+#define HYDRA_CPD_PD2 0x00000004
+#define HYDRA_CPD_PD3 0x00000008
+
+#define HYDRA_SCLK HYDRA_CPD_PD0
+#define HYDRA_SDAT HYDRA_CPD_PD1
+#define HYDRA_SCLK_OE 0x00000010
+#define HYDRA_SDAT_OE 0x00000020
+
+static inline void pdregw(void *data, u32 val)
+{
+ struct Hydra *hydra = (struct Hydra *)data;
+ writel(val, &hydra->CachePD);
+}
+
+static inline u32 pdregr(void *data)
+{
+ struct Hydra *hydra = (struct Hydra *)data;
+ return readl(&hydra->CachePD);
+}
+
+static void hydra_bit_setscl(void *data, int state)
+{
+ u32 val = pdregr(data);
+ if (state)
+ val &= ~HYDRA_SCLK_OE;
+ else {
+ val &= ~HYDRA_SCLK;
+ val |= HYDRA_SCLK_OE;
+ }
+ pdregw(data, val);
+}
+
+static void hydra_bit_setsda(void *data, int state)
+{
+ u32 val = pdregr(data);
+ if (state)
+ val &= ~HYDRA_SDAT_OE;
+ else {
+ val &= ~HYDRA_SDAT;
+ val |= HYDRA_SDAT_OE;
+ }
+ pdregw(data, val);
+}
+
+static int hydra_bit_getscl(void *data)
+{
+ return (pdregr(data) & HYDRA_SCLK) != 0;
+}
+
+static int hydra_bit_getsda(void *data)
+{
+ return (pdregr(data) & HYDRA_SDAT) != 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct i2c_algo_bit_data hydra_bit_data = {
+ .setsda = hydra_bit_setsda,
+ .setscl = hydra_bit_setscl,
+ .getsda = hydra_bit_getsda,
+ .getscl = hydra_bit_getscl,
+ .udelay = 5,
+ .timeout = HZ
+};
+
+static struct i2c_adapter hydra_adap = {
+ .owner = THIS_MODULE,
+ .name = "Hydra i2c",
+ .algo_data = &hydra_bit_data,
+};
+
+static const struct pci_device_id hydra_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, hydra_ids);
+
+static int __devinit hydra_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ unsigned long base = pci_resource_start(dev, 0);
+ int res;
+
+ if (!request_mem_region(base+offsetof(struct Hydra, CachePD), 4,
+ hydra_adap.name))
+ return -EBUSY;
+
+ hydra_bit_data.data = pci_ioremap_bar(dev, 0);
+ if (hydra_bit_data.data == NULL) {
+ release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
+ return -ENODEV;
+ }
+
+ pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */
+ hydra_adap.dev.parent = &dev->dev;
+ res = i2c_bit_add_bus(&hydra_adap);
+ if (res < 0) {
+ iounmap(hydra_bit_data.data);
+ release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
+ return res;
+ }
+ return 0;
+}
+
+static void __devexit hydra_remove(struct pci_dev *dev)
+{
+ pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */
+ i2c_del_adapter(&hydra_adap);
+ iounmap(hydra_bit_data.data);
+ release_mem_region(pci_resource_start(dev, 0)+
+ offsetof(struct Hydra, CachePD), 4);
+}
+
+
+static struct pci_driver hydra_driver = {
+ .name = "hydra_smbus",
+ .id_table = hydra_ids,
+ .probe = hydra_probe,
+ .remove = __devexit_p(hydra_remove),
+};
+
+static int __init i2c_hydra_init(void)
+{
+ return pci_register_driver(&hydra_driver);
+}
+
+
+static void __exit i2c_hydra_exit(void)
+{
+ pci_unregister_driver(&hydra_driver);
+}
+
+
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_hydra_init);
+module_exit(i2c_hydra_exit);
+
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
new file mode 100644
index 00000000..ab26840d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -0,0 +1,946 @@
+/*
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
+ <mdsxyz123@yahoo.com>
+ Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2010 Intel Corporation,
+ David Woodhouse <dwmw2@infradead.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.
+*/
+
+/*
+ Supports the following Intel I/O Controller Hubs (ICH):
+
+ I/O Block I2C
+ region SMBus Block proc. block
+ Chip name PCI ID size PEC buffer call read
+ ----------------------------------------------------------------------
+ 82801AA (ICH) 0x2413 16 no no no no
+ 82801AB (ICH0) 0x2423 16 no no no no
+ 82801BA (ICH2) 0x2443 16 no no no no
+ 82801CA (ICH3) 0x2483 32 soft no no no
+ 82801DB (ICH4) 0x24c3 32 hard yes no no
+ 82801E (ICH5) 0x24d3 32 hard yes yes yes
+ 6300ESB 0x25a4 32 hard yes yes yes
+ 82801F (ICH6) 0x266a 32 hard yes yes yes
+ 6310ESB/6320ESB 0x269b 32 hard yes yes yes
+ 82801G (ICH7) 0x27da 32 hard yes yes yes
+ 82801H (ICH8) 0x283e 32 hard yes yes yes
+ 82801I (ICH9) 0x2930 32 hard yes yes yes
+ EP80579 (Tolapai) 0x5032 32 hard yes yes yes
+ ICH10 0x3a30 32 hard yes yes yes
+ ICH10 0x3a60 32 hard yes yes yes
+ 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes
+ 6 Series (PCH) 0x1c22 32 hard yes yes yes
+ Patsburg (PCH) 0x1d22 32 hard yes yes yes
+ Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes
+ Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes
+ Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
+ DH89xxCC (PCH) 0x2330 32 hard yes yes yes
+ Panther Point (PCH) 0x1e22 32 hard yes yes yes
+
+ Features supported by this driver:
+ Software PEC no
+ Hardware PEC yes
+ Block buffer yes
+ Block process call transaction no
+ I2C block read transaction yes (doesn't use the block buffer)
+ Slave mode no
+
+ See the file Documentation/i2c/busses/i2c-i801 for details.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+
+/* I801 SMBus address offsets */
+#define SMBHSTSTS(p) (0 + (p)->smba)
+#define SMBHSTCNT(p) (2 + (p)->smba)
+#define SMBHSTCMD(p) (3 + (p)->smba)
+#define SMBHSTADD(p) (4 + (p)->smba)
+#define SMBHSTDAT0(p) (5 + (p)->smba)
+#define SMBHSTDAT1(p) (6 + (p)->smba)
+#define SMBBLKDAT(p) (7 + (p)->smba)
+#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */
+#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */
+#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */
+
+/* PCI Address Constants */
+#define SMBBAR 4
+#define SMBHSTCFG 0x040
+
+/* Host configuration bits for SMBHSTCFG */
+#define SMBHSTCFG_HST_EN 1
+#define SMBHSTCFG_SMB_SMI_EN 2
+#define SMBHSTCFG_I2C_EN 4
+
+/* Auxiliary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC 1
+#define SMBAUXCTL_E32B 2
+
+/* kill bit for SMBHSTCNT */
+#define SMBHSTCNT_KILL 2
+
+/* Other settings */
+#define MAX_TIMEOUT 100
+#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
+
+/* I801 command constants */
+#define I801_QUICK 0x00
+#define I801_BYTE 0x04
+#define I801_BYTE_DATA 0x08
+#define I801_WORD_DATA 0x0C
+#define I801_PROC_CALL 0x10 /* unimplemented */
+#define I801_BLOCK_DATA 0x14
+#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
+#define I801_BLOCK_LAST 0x34
+#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */
+#define I801_START 0x40
+#define I801_PEC_EN 0x80 /* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE 0x80
+#define SMBHSTSTS_INUSE_STS 0x40
+#define SMBHSTSTS_SMBALERT_STS 0x20
+#define SMBHSTSTS_FAILED 0x10
+#define SMBHSTSTS_BUS_ERR 0x08
+#define SMBHSTSTS_DEV_ERR 0x04
+#define SMBHSTSTS_INTR 0x02
+#define SMBHSTSTS_HOST_BUSY 0x01
+
+#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
+ SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
+ SMBHSTSTS_INTR)
+
+/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+
+struct i801_priv {
+ struct i2c_adapter adapter;
+ unsigned long smba;
+ unsigned char original_hstcfg;
+ struct pci_dev *pci_dev;
+ unsigned int features;
+};
+
+static struct pci_driver i801_driver;
+
+#define FEATURE_SMBUS_PEC (1 << 0)
+#define FEATURE_BLOCK_BUFFER (1 << 1)
+#define FEATURE_BLOCK_PROC (1 << 2)
+#define FEATURE_I2C_BLOCK_READ (1 << 3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF (1 << 15)
+
+static const char *i801_feature_names[] = {
+ "SMBus PEC",
+ "Block buffer",
+ "Block process call",
+ "I2C block read",
+};
+
+static unsigned int disable_features;
+module_param(disable_features, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_features, "Disable selected driver features");
+
+/* Make sure the SMBus host is ready to start transmitting.
+ Return 0 if it is, -EBUSY if it is not. */
+static int i801_check_pre(struct i801_priv *priv)
+{
+ int status;
+
+ status = inb_p(SMBHSTSTS(priv));
+ if (status & SMBHSTSTS_HOST_BUSY) {
+ dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
+ return -EBUSY;
+ }
+
+ status &= STATUS_FLAGS;
+ if (status) {
+ dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
+ status);
+ outb_p(status, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+ if (status) {
+ dev_err(&priv->pci_dev->dev,
+ "Failed clearing status flags (%02x)\n",
+ status);
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+/* Convert the status register to an error code, and clear it. */
+static int i801_check_post(struct i801_priv *priv, int status, int timeout)
+{
+ int result = 0;
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout) {
+ dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
+ /* try to stop the current command */
+ dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
+ outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
+ SMBHSTCNT(priv));
+ msleep(1);
+ outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
+ SMBHSTCNT(priv));
+
+ /* Check if it worked */
+ status = inb_p(SMBHSTSTS(priv));
+ if ((status & SMBHSTSTS_HOST_BUSY) ||
+ !(status & SMBHSTSTS_FAILED))
+ dev_err(&priv->pci_dev->dev,
+ "Failed terminating the transaction\n");
+ outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
+ return -ETIMEDOUT;
+ }
+
+ if (status & SMBHSTSTS_FAILED) {
+ result = -EIO;
+ dev_err(&priv->pci_dev->dev, "Transaction failed\n");
+ }
+ if (status & SMBHSTSTS_DEV_ERR) {
+ result = -ENXIO;
+ dev_dbg(&priv->pci_dev->dev, "No response\n");
+ }
+ if (status & SMBHSTSTS_BUS_ERR) {
+ result = -EAGAIN;
+ dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
+ }
+
+ if (result) {
+ /* Clear error flags */
+ outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+ if (status) {
+ dev_warn(&priv->pci_dev->dev, "Failed clearing status "
+ "flags at end of transaction (%02x)\n",
+ status);
+ }
+ }
+
+ return result;
+}
+
+static int i801_transaction(struct i801_priv *priv, int xact)
+{
+ int status;
+ int result;
+ int timeout = 0;
+
+ result = i801_check_pre(priv);
+ if (result < 0)
+ return result;
+
+ /* the current contents of SMBHSTCNT can be overwritten, since PEC,
+ * INTREN, SMBSCMD are passed in xact */
+ outb_p(xact | I801_START, SMBHSTCNT(priv));
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ status = inb_p(SMBHSTSTS(priv));
+ } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
+
+ result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+ if (result < 0)
+ return result;
+
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ return 0;
+}
+
+/* wait for INTR bit as advised by Intel */
+static void i801_wait_hwpec(struct i801_priv *priv)
+{
+ int timeout = 0;
+ int status;
+
+ do {
+ msleep(1);
+ status = inb_p(SMBHSTSTS(priv));
+ } while ((!(status & SMBHSTSTS_INTR))
+ && (timeout++ < MAX_TIMEOUT));
+
+ if (timeout > MAX_TIMEOUT)
+ dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
+
+ outb_p(status, SMBHSTSTS(priv));
+}
+
+static int i801_block_transaction_by_block(struct i801_priv *priv,
+ union i2c_smbus_data *data,
+ char read_write, int hwpec)
+{
+ int i, len;
+ int status;
+
+ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
+
+ /* Use 32-byte buffer to process this transaction */
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ outb_p(len, SMBHSTDAT0(priv));
+ for (i = 0; i < len; i++)
+ outb_p(data->block[i+1], SMBBLKDAT(priv));
+ }
+
+ status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |
+ I801_PEC_EN * hwpec);
+ if (status)
+ return status;
+
+ if (read_write == I2C_SMBUS_READ) {
+ len = inb_p(SMBHSTDAT0(priv));
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+
+ data->block[0] = len;
+ for (i = 0; i < len; i++)
+ data->block[i + 1] = inb_p(SMBBLKDAT(priv));
+ }
+ return 0;
+}
+
+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
+ union i2c_smbus_data *data,
+ char read_write, int command,
+ int hwpec)
+{
+ int i, len;
+ int smbcmd;
+ int status;
+ int result;
+ int timeout;
+
+ result = i801_check_pre(priv);
+ if (result < 0)
+ return result;
+
+ len = data->block[0];
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(len, SMBHSTDAT0(priv));
+ outb_p(data->block[1], SMBBLKDAT(priv));
+ }
+
+ for (i = 1; i <= len; i++) {
+ if (i == len && read_write == I2C_SMBUS_READ) {
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+ smbcmd = I801_I2C_BLOCK_LAST;
+ else
+ smbcmd = I801_BLOCK_LAST;
+ } else {
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA
+ && read_write == I2C_SMBUS_READ)
+ smbcmd = I801_I2C_BLOCK_DATA;
+ else
+ smbcmd = I801_BLOCK_DATA;
+ }
+ outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
+
+ if (i == 1)
+ outb_p(inb(SMBHSTCNT(priv)) | I801_START,
+ SMBHSTCNT(priv));
+
+ /* We will always wait for a fraction of a second! */
+ timeout = 0;
+ do {
+ msleep(1);
+ status = inb_p(SMBHSTSTS(priv));
+ } while ((!(status & SMBHSTSTS_BYTE_DONE))
+ && (timeout++ < MAX_TIMEOUT));
+
+ result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+ if (result < 0)
+ return result;
+
+ if (i == 1 && read_write == I2C_SMBUS_READ
+ && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+ len = inb_p(SMBHSTDAT0(priv));
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&priv->pci_dev->dev,
+ "Illegal SMBus block read size %d\n",
+ len);
+ /* Recover */
+ while (inb_p(SMBHSTSTS(priv)) &
+ SMBHSTSTS_HOST_BUSY)
+ outb_p(SMBHSTSTS_BYTE_DONE,
+ SMBHSTSTS(priv));
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ return -EPROTO;
+ }
+ data->block[0] = len;
+ }
+
+ /* Retrieve/store value in SMBBLKDAT */
+ if (read_write == I2C_SMBUS_READ)
+ data->block[i] = inb_p(SMBBLKDAT(priv));
+ if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
+ outb_p(data->block[i+1], SMBBLKDAT(priv));
+
+ /* signals SMBBLKDAT ready */
+ outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ }
+
+ return 0;
+}
+
+static int i801_set_block_buffer_mode(struct i801_priv *priv)
+{
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
+ return -EIO;
+ return 0;
+}
+
+/* Block transaction function */
+static int i801_block_transaction(struct i801_priv *priv,
+ union i2c_smbus_data *data, char read_write,
+ int command, int hwpec)
+{
+ int result = 0;
+ unsigned char hostc;
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* set I2C_EN bit in configuration register */
+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
+ hostc | SMBHSTCFG_I2C_EN);
+ } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+ dev_err(&priv->pci_dev->dev,
+ "I2C block read is unsupported!\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (read_write == I2C_SMBUS_WRITE
+ || command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (data->block[0] < 1)
+ data->block[0] = 1;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ } else {
+ data->block[0] = 32; /* max for 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 ((priv->features & FEATURE_BLOCK_BUFFER)
+ && command != I2C_SMBUS_I2C_BLOCK_DATA
+ && i801_set_block_buffer_mode(priv) == 0)
+ result = i801_block_transaction_by_block(priv, data,
+ read_write, hwpec);
+ else
+ result = i801_block_transaction_byte_by_byte(priv, data,
+ read_write,
+ command, hwpec);
+
+ if (result == 0 && hwpec)
+ i801_wait_hwpec(priv);
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA
+ && read_write == I2C_SMBUS_WRITE) {
+ /* restore saved configuration register value */
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
+ }
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 i801_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int hwpec;
+ int block = 0;
+ int ret, xact = 0;
+ struct i801_priv *priv = i2c_get_adapdata(adap);
+
+ hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+ && size != I2C_SMBUS_QUICK
+ && size != I2C_SMBUS_I2C_BLOCK_DATA;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD(priv));
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0(priv));
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ }
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading */
+ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+ if (read_write == I2C_SMBUS_READ) {
+ /* NB: page 240 of ICH5 datasheet also shows
+ * that DATA1 is the cmd field when reading */
+ outb_p(command, SMBHSTDAT1(priv));
+ } else
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
+ default:
+ dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+ size);
+ return -EOPNOTSUPP;
+ }
+
+ if (hwpec) /* enable/disable hardware PEC */
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
+ else
+ outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+ SMBAUXCTL(priv));
+
+ if (block)
+ ret = i801_block_transaction(priv, data, read_write, size,
+ hwpec);
+ else
+ ret = i801_transaction(priv, xact | ENABLE_INT9);
+
+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ time, so we forcibly disable it after every transaction. Turn off
+ E32B for the same reason. */
+ if (hwpec || block)
+ outb_p(inb_p(SMBAUXCTL(priv)) &
+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+
+ if (block)
+ return ret;
+ if (ret)
+ return ret;
+ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
+ return 0;
+
+ switch (xact & 0x7f) {
+ case I801_BYTE: /* Result put in SMBHSTDAT0 */
+ case I801_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0(priv));
+ break;
+ case I801_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0(priv)) +
+ (inb_p(SMBHSTDAT1(priv)) << 8);
+ break;
+ }
+ return 0;
+}
+
+
+static u32 i801_func(struct i2c_adapter *adapter)
+{
+ struct i801_priv *priv = i2c_get_adapdata(adapter);
+
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+ ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+ ((priv->features & FEATURE_I2C_BLOCK_READ) ?
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = i801_access,
+ .functionality = i801_func,
+};
+
+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) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) },
+ { 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_5_3400_SERIES_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, i801_ids);
+
+#if defined CONFIG_X86 && defined CONFIG_DMI
+static unsigned char apanel_addr;
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+ ssize_t offset;
+ const unsigned char signature[] = "FJKEYINF";
+
+ for (offset = 0; offset < 0x10000; offset += 0x10) {
+ if (check_signature(bios + offset, signature,
+ sizeof(signature)-1))
+ return bios + offset;
+ }
+ return NULL;
+}
+
+static void __init input_apanel_init(void)
+{
+ void __iomem *bios;
+ const void __iomem *p;
+
+ bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+ p = bios_signature(bios);
+ if (p) {
+ /* just use the first address */
+ apanel_addr = readb(p + 8 + 3) >> 1;
+ }
+ iounmap(bios);
+}
+
+struct dmi_onboard_device_info {
+ const char *name;
+ u8 type;
+ unsigned short i2c_addr;
+ const char *i2c_type;
+};
+
+static struct dmi_onboard_device_info __devinitdata dmi_devices[] = {
+ { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
+ { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
+ { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
+};
+
+static void __devinit dmi_check_onboard_device(u8 type, const char *name,
+ struct i2c_adapter *adap)
+{
+ int i;
+ struct i2c_board_info info;
+
+ for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
+ /* & ~0x80, ignore enabled/disabled bit */
+ if ((type & ~0x80) != dmi_devices[i].type)
+ continue;
+ if (strcasecmp(name, dmi_devices[i].name))
+ continue;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = dmi_devices[i].i2c_addr;
+ strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
+ i2c_new_device(adap, &info);
+ break;
+ }
+}
+
+/* We use our own function to check for onboard devices instead of
+ dmi_find_device() as some buggy BIOS's have the devices we are interested
+ in marked as disabled */
+static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
+ void *adap)
+{
+ int i, count;
+
+ if (dm->type != 10)
+ return;
+
+ count = (dm->length - sizeof(struct dmi_header)) / 2;
+ for (i = 0; i < count; i++) {
+ const u8 *d = (char *)(dm + 1) + (i * 2);
+ const char *name = ((char *) dm) + dm->length;
+ u8 type = d[0];
+ u8 s = d[1];
+
+ if (!s)
+ continue;
+ s--;
+ while (s > 0 && name[0]) {
+ name += strlen(name) + 1;
+ s--;
+ }
+ if (name[0] == 0) /* Bogus string reference */
+ continue;
+
+ dmi_check_onboard_device(type, name, adap);
+ }
+}
+
+/* Register optional slaves */
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
+{
+ /* Only register slaves on main SMBus channel */
+ if (priv->features & FEATURE_IDF)
+ return;
+
+ if (apanel_addr) {
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = apanel_addr;
+ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+ i2c_new_device(&priv->adapter, &info);
+ }
+
+ if (dmi_name_in_vendors("FUJITSU"))
+ dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+}
+#else
+static void __init input_apanel_init(void) {}
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
+#endif /* CONFIG_X86 && CONFIG_DMI */
+
+static int __devinit i801_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ unsigned char temp;
+ int err, i;
+ struct i801_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_adapdata(&priv->adapter, priv);
+ priv->adapter.owner = THIS_MODULE;
+ priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ priv->adapter.algo = &smbus_algorithm;
+
+ priv->pci_dev = dev;
+ switch (dev->device) {
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2:
+ priv->features |= FEATURE_IDF;
+ /* fall through */
+ default:
+ priv->features |= FEATURE_I2C_BLOCK_READ;
+ /* fall through */
+ case PCI_DEVICE_ID_INTEL_82801DB_3:
+ priv->features |= FEATURE_SMBUS_PEC;
+ priv->features |= FEATURE_BLOCK_BUFFER;
+ /* fall through */
+ case PCI_DEVICE_ID_INTEL_82801CA_3:
+ case PCI_DEVICE_ID_INTEL_82801BA_2:
+ case PCI_DEVICE_ID_INTEL_82801AB_3:
+ case PCI_DEVICE_ID_INTEL_82801AA_3:
+ break;
+ }
+
+ /* Disable features on user request */
+ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
+ if (priv->features & disable_features & (1 << i))
+ dev_notice(&dev->dev, "%s disabled by user\n",
+ i801_feature_names[i]);
+ }
+ priv->features &= ~disable_features;
+
+ err = pci_enable_device(dev);
+ if (err) {
+ dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
+ err);
+ goto exit;
+ }
+
+ /* Determine the address of the SMBus area */
+ priv->smba = pci_resource_start(dev, SMBBAR);
+ if (!priv->smba) {
+ dev_err(&dev->dev, "SMBus base address uninitialized, "
+ "upgrade BIOS\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
+ if (err) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ err = pci_request_region(dev, SMBBAR, i801_driver.name);
+ if (err) {
+ dev_err(&dev->dev, "Failed to request SMBus region "
+ "0x%lx-0x%Lx\n", priv->smba,
+ (unsigned long long)pci_resource_end(dev, SMBBAR));
+ goto exit;
+ }
+
+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
+ priv->original_hstcfg = temp;
+ temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
+ if (!(temp & SMBHSTCFG_HST_EN)) {
+ dev_info(&dev->dev, "Enabling SMBus device\n");
+ temp |= SMBHSTCFG_HST_EN;
+ }
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
+
+ if (temp & SMBHSTCFG_SMB_SMI_EN)
+ dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
+ else
+ dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
+
+ /* Clear special mode bits */
+ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+ outb_p(inb_p(SMBAUXCTL(priv)) &
+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+
+ /* set up the sysfs linkage to our parent device */
+ priv->adapter.dev.parent = &dev->dev;
+
+ /* Retry up to 3 times on lost arbitration */
+ priv->adapter.retries = 3;
+
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+ "SMBus I801 adapter at %04lx", priv->smba);
+ err = i2c_add_adapter(&priv->adapter);
+ if (err) {
+ dev_err(&dev->dev, "Failed to add SMBus adapter\n");
+ goto exit_release;
+ }
+
+ i801_probe_optional_slaves(priv);
+
+ pci_set_drvdata(dev, priv);
+ return 0;
+
+exit_release:
+ pci_release_region(dev, SMBBAR);
+exit:
+ kfree(priv);
+ return err;
+}
+
+static void __devexit i801_remove(struct pci_dev *dev)
+{
+ struct i801_priv *priv = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&priv->adapter);
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+ pci_release_region(dev, SMBBAR);
+ pci_set_drvdata(dev, NULL);
+ kfree(priv);
+ /*
+ * do not call pci_disable_device(dev) since it can cause hard hangs on
+ * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+ */
+}
+
+#ifdef CONFIG_PM
+static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
+{
+ struct i801_priv *priv = pci_get_drvdata(dev);
+
+ pci_save_state(dev);
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+ pci_set_power_state(dev, pci_choose_state(dev, mesg));
+ return 0;
+}
+
+static int i801_resume(struct pci_dev *dev)
+{
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+ return pci_enable_device(dev);
+}
+#else
+#define i801_suspend NULL
+#define i801_resume NULL
+#endif
+
+static struct pci_driver i801_driver = {
+ .name = "i801_smbus",
+ .id_table = i801_ids,
+ .probe = i801_probe,
+ .remove = __devexit_p(i801_remove),
+ .suspend = i801_suspend,
+ .resume = i801_resume,
+};
+
+static int __init i2c_i801_init(void)
+{
+ if (dmi_name_in_vendors("FUJITSU"))
+ input_apanel_init();
+ return pci_register_driver(&i801_driver);
+}
+
+static void __exit i2c_i801_exit(void)
+{
+ pci_unregister_driver(&i801_driver);
+}
+
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, "
+ "Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("I801 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_i801_init);
+module_exit(i2c_i801_exit);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
new file mode 100644
index 00000000..3c110fbc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -0,0 +1,829 @@
+/*
+ * drivers/i2c/busses/i2c-ibm_iic.c
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003, 2004 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Copyright (c) 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * Based on original work by
+ * Ian DaSilva <idasilva@mvista.com>
+ * Armin Kuster <akuster@mvista.com>
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * Original driver version was highly leveraged from i2c-elektor.c
+ *
+ * Copyright 1995-97 Simon G. Vogl
+ * 1998-99 Hans Berglund
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
+ * and even Frodo Looijaard <frodol@dds.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+
+#include "i2c-ibm_iic.h"
+
+#define DRIVER_VERSION "2.2"
+
+MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static int iic_force_poll;
+module_param(iic_force_poll, bool, 0);
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+
+static int iic_force_fast;
+module_param(iic_force_fast, bool, 0);
+MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)");
+
+#define DBG_LEVEL 0
+
+#ifdef DBG
+#undef DBG
+#endif
+
+#ifdef DBG2
+#undef DBG2
+#endif
+
+#if DBG_LEVEL > 0
+# define DBG(f,x...) printk(KERN_DEBUG "ibm-iic" f, ##x)
+#else
+# define DBG(f,x...) ((void)0)
+#endif
+#if DBG_LEVEL > 1
+# define DBG2(f,x...) DBG(f, ##x)
+#else
+# define DBG2(f,x...) ((void)0)
+#endif
+#if DBG_LEVEL > 2
+static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header);
+ printk(KERN_DEBUG
+ " cntl = 0x%02x, mdcntl = 0x%02x\n"
+ " sts = 0x%02x, extsts = 0x%02x\n"
+ " clkdiv = 0x%02x, xfrcnt = 0x%02x\n"
+ " xtcntlss = 0x%02x, directcntl = 0x%02x\n",
+ in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
+ in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
+ in_8(&iic->xtcntlss), in_8(&iic->directcntl));
+}
+# define DUMP_REGS(h,dev) dump_iic_regs((h),(dev))
+#else
+# define DUMP_REGS(h,dev) ((void)0)
+#endif
+
+/* Bus timings (in ns) for bit-banging */
+static struct i2c_timings {
+ unsigned int hd_sta;
+ unsigned int su_sto;
+ unsigned int low;
+ unsigned int high;
+ unsigned int buf;
+} timings [] = {
+/* Standard mode (100 KHz) */
+{
+ .hd_sta = 4000,
+ .su_sto = 4000,
+ .low = 4700,
+ .high = 4000,
+ .buf = 4700,
+},
+/* Fast mode (400 KHz) */
+{
+ .hd_sta = 600,
+ .su_sto = 600,
+ .low = 1300,
+ .high = 600,
+ .buf = 1300,
+}};
+
+/* Enable/disable interrupt generation */
+static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
+{
+ out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
+}
+
+/*
+ * Initialize IIC interface.
+ */
+static void iic_dev_init(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+ DBG("%d: init\n", dev->idx);
+
+ /* Clear master address */
+ out_8(&iic->lmadr, 0);
+ out_8(&iic->hmadr, 0);
+
+ /* Clear slave address */
+ out_8(&iic->lsadr, 0);
+ out_8(&iic->hsadr, 0);
+
+ /* Clear status & extended status */
+ out_8(&iic->sts, STS_SCMP | STS_IRQA);
+ out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA
+ | EXTSTS_ICT | EXTSTS_XFRA);
+
+ /* Set clock divider */
+ out_8(&iic->clkdiv, dev->clckdiv);
+
+ /* Clear transfer count */
+ out_8(&iic->xfrcnt, 0);
+
+ /* Clear extended control and status */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC
+ | XTCNTLSS_SWS);
+
+ /* Clear control register */
+ out_8(&iic->cntl, 0);
+
+ /* Enable interrupts if possible */
+ iic_interrupt_mode(dev, dev->irq >= 0);
+
+ /* Set mode control */
+ out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS
+ | (dev->fast_mode ? MDCNTL_FSM : 0));
+
+ DUMP_REGS("iic_init", dev);
+}
+
+/*
+ * Reset IIC interface
+ */
+static void iic_dev_reset(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ int i;
+ u8 dc;
+
+ DBG("%d: soft reset\n", dev->idx);
+ DUMP_REGS("reset", dev);
+
+ /* Place chip in the reset state */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+ /* Check if bus is free */
+ dc = in_8(&iic->directcntl);
+ if (!DIRCTNL_FREE(dc)){
+ DBG("%d: trying to regain bus control\n", dev->idx);
+
+ /* Try to set bus free state */
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+ /* Wait until we regain bus control */
+ for (i = 0; i < 100; ++i){
+ dc = in_8(&iic->directcntl);
+ if (DIRCTNL_FREE(dc))
+ break;
+
+ /* Toggle SCL line */
+ dc ^= DIRCNTL_SCC;
+ out_8(&iic->directcntl, dc);
+ udelay(10);
+ dc ^= DIRCNTL_SCC;
+ out_8(&iic->directcntl, dc);
+
+ /* be nice */
+ cond_resched();
+ }
+ }
+
+ /* Remove reset */
+ out_8(&iic->xtcntlss, 0);
+
+ /* Reinitialize interface */
+ iic_dev_init(dev);
+}
+
+/*
+ * Do 0-length transaction using bit-banging through IIC_DIRECTCNTL register.
+ */
+
+/* Wait for SCL and/or SDA to be high */
+static int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask)
+{
+ unsigned long x = jiffies + HZ / 28 + 2;
+ while ((in_8(&iic->directcntl) & mask) != mask){
+ if (unlikely(time_after(jiffies, x)))
+ return -1;
+ cond_resched();
+ }
+ return 0;
+}
+
+static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ const struct i2c_timings* t = &timings[dev->fast_mode ? 1 : 0];
+ u8 mask, v, sda;
+ int i, res;
+
+ /* Only 7-bit addresses are supported */
+ if (unlikely(p->flags & I2C_M_TEN)){
+ DBG("%d: smbus_quick - 10 bit addresses are not supported\n",
+ dev->idx);
+ return -EINVAL;
+ }
+
+ DBG("%d: smbus_quick(0x%02x)\n", dev->idx, p->addr);
+
+ /* Reset IIC interface */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+ /* Wait for bus to become free */
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSDA | DIRCNTL_MSC)))
+ goto err;
+ ndelay(t->buf);
+
+ /* START */
+ out_8(&iic->directcntl, DIRCNTL_SCC);
+ sda = 0;
+ ndelay(t->hd_sta);
+
+ /* Send address */
+ v = (u8)((p->addr << 1) | ((p->flags & I2C_M_RD) ? 1 : 0));
+ for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
+ out_8(&iic->directcntl, sda);
+ ndelay(t->low / 2);
+ sda = (v & mask) ? DIRCNTL_SDAC : 0;
+ out_8(&iic->directcntl, sda);
+ ndelay(t->low / 2);
+
+ out_8(&iic->directcntl, DIRCNTL_SCC | sda);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+ goto err;
+ ndelay(t->high);
+ }
+
+ /* ACK */
+ out_8(&iic->directcntl, sda);
+ ndelay(t->low / 2);
+ out_8(&iic->directcntl, DIRCNTL_SDAC);
+ ndelay(t->low / 2);
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+ goto err;
+ res = (in_8(&iic->directcntl) & DIRCNTL_MSDA) ? -EREMOTEIO : 1;
+ ndelay(t->high);
+
+ /* STOP */
+ out_8(&iic->directcntl, 0);
+ ndelay(t->low);
+ out_8(&iic->directcntl, DIRCNTL_SCC);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+ goto err;
+ ndelay(t->su_sto);
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+ ndelay(t->buf);
+
+ DBG("%d: smbus_quick -> %s\n", dev->idx, res ? "NACK" : "ACK");
+out:
+ /* Remove reset */
+ out_8(&iic->xtcntlss, 0);
+
+ /* Reinitialize interface */
+ iic_dev_init(dev);
+
+ return res;
+err:
+ DBG("%d: smbus_quick - bus is stuck\n", dev->idx);
+ res = -EREMOTEIO;
+ goto out;
+}
+
+/*
+ * IIC interrupt handler
+ */
+static irqreturn_t iic_handler(int irq, void *dev_id)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+ DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
+ dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
+
+ /* Acknowledge IRQ and wakeup iic_wait_for_tc */
+ out_8(&iic->sts, STS_IRQA | STS_SCMP);
+ wake_up_interruptible(&dev->wq);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Get master transfer result and clear errors if any.
+ * Returns the number of actually transferred bytes or error (<0)
+ */
+static int iic_xfer_result(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+ if (unlikely(in_8(&iic->sts) & STS_ERR)){
+ DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
+ in_8(&iic->extsts));
+
+ /* Clear errors and possible pending IRQs */
+ out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
+ EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
+
+ /* Flush master data buffer */
+ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+
+ /* Is bus free?
+ * If error happened during combined xfer
+ * IIC interface is usually stuck in some strange
+ * state, the only way out - soft reset.
+ */
+ if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ DBG("%d: bus is stuck, resetting\n", dev->idx);
+ iic_dev_reset(dev);
+ }
+ return -EREMOTEIO;
+ }
+ else
+ return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
+}
+
+/*
+ * Try to abort active transfer.
+ */
+static void iic_abort_xfer(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ unsigned long x;
+
+ DBG("%d: iic_abort_xfer\n", dev->idx);
+
+ out_8(&iic->cntl, CNTL_HMT);
+
+ /*
+ * Wait for the abort command to complete.
+ * It's not worth to be optimized, just poll (timeout >= 1 tick)
+ */
+ x = jiffies + 2;
+ while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ if (time_after(jiffies, x)){
+ DBG("%d: abort timeout, resetting...\n", dev->idx);
+ iic_dev_reset(dev);
+ return;
+ }
+ schedule();
+ }
+
+ /* Just to clear errors */
+ iic_xfer_result(dev);
+}
+
+/*
+ * Wait for master transfer to complete.
+ * It puts current process to sleep until we get interrupt or timeout expires.
+ * Returns the number of transferred bytes or error (<0)
+ */
+static int iic_wait_for_tc(struct ibm_iic_private* dev){
+
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ int ret = 0;
+
+ if (dev->irq >= 0){
+ /* Interrupt mode */
+ ret = wait_event_interruptible_timeout(dev->wq,
+ !(in_8(&iic->sts) & STS_PT), dev->adap.timeout);
+
+ if (unlikely(ret < 0))
+ DBG("%d: wait interrupted\n", dev->idx);
+ else if (unlikely(in_8(&iic->sts) & STS_PT)){
+ DBG("%d: wait timeout\n", dev->idx);
+ ret = -ETIMEDOUT;
+ }
+ }
+ else {
+ /* Polling mode */
+ unsigned long x = jiffies + dev->adap.timeout;
+
+ while (in_8(&iic->sts) & STS_PT){
+ if (unlikely(time_after(jiffies, x))){
+ DBG("%d: poll timeout\n", dev->idx);
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ if (unlikely(signal_pending(current))){
+ DBG("%d: poll interrupted\n", dev->idx);
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ }
+
+ if (unlikely(ret < 0))
+ iic_abort_xfer(dev);
+ else
+ ret = iic_xfer_result(dev);
+
+ DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
+
+ return ret;
+}
+
+/*
+ * Low level master transfer routine
+ */
+static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
+ int combined_xfer)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ char* buf = pm->buf;
+ int i, j, loops, ret = 0;
+ int len = pm->len;
+
+ u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
+ if (pm->flags & I2C_M_RD)
+ cntl |= CNTL_RW;
+
+ loops = (len + 3) / 4;
+ for (i = 0; i < loops; ++i, len -= 4){
+ int count = len > 4 ? 4 : len;
+ u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
+
+ if (!(cntl & CNTL_RW))
+ for (j = 0; j < count; ++j)
+ out_8((void __iomem *)&iic->mdbuf, *buf++);
+
+ if (i < loops - 1)
+ cmd |= CNTL_CHT;
+ else if (combined_xfer)
+ cmd |= CNTL_RPST;
+
+ DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
+
+ /* Start transfer */
+ out_8(&iic->cntl, cmd);
+
+ /* Wait for completion */
+ ret = iic_wait_for_tc(dev);
+
+ if (unlikely(ret < 0))
+ break;
+ else if (unlikely(ret != count)){
+ DBG("%d: xfer_bytes, requested %d, transferred %d\n",
+ dev->idx, count, ret);
+
+ /* If it's not a last part of xfer, abort it */
+ if (combined_xfer || (i < loops - 1))
+ iic_abort_xfer(dev);
+
+ ret = -EREMOTEIO;
+ break;
+ }
+
+ if (cntl & CNTL_RW)
+ for (j = 0; j < count; ++j)
+ *buf++ = in_8((void __iomem *)&iic->mdbuf);
+ }
+
+ return ret > 0 ? 0 : ret;
+}
+
+/*
+ * Set target slave address for master transfer
+ */
+static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ u16 addr = msg->addr;
+
+ DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
+ addr, msg->flags & I2C_M_TEN ? 10 : 7);
+
+ if (msg->flags & I2C_M_TEN){
+ out_8(&iic->cntl, CNTL_AMD);
+ out_8(&iic->lmadr, addr);
+ out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
+ }
+ else {
+ out_8(&iic->cntl, 0);
+ out_8(&iic->lmadr, addr << 1);
+ }
+}
+
+static inline int iic_invalid_address(const struct i2c_msg* p)
+{
+ return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
+}
+
+static inline int iic_address_neq(const struct i2c_msg* p1,
+ const struct i2c_msg* p2)
+{
+ return (p1->addr != p2->addr)
+ || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
+}
+
+/*
+ * Generic master transfer entrypoint.
+ * Returns the number of processed messages or error (<0)
+ */
+static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ int i, ret = 0;
+
+ DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
+
+ if (!num)
+ return 0;
+
+ /* Check the sanity of the passed messages.
+ * Uhh, generic i2c layer is more suitable place for such code...
+ */
+ if (unlikely(iic_invalid_address(&msgs[0]))){
+ DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
+ msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
+ return -EINVAL;
+ }
+ for (i = 0; i < num; ++i){
+ if (unlikely(msgs[i].len <= 0)){
+ if (num == 1 && !msgs[0].len){
+ /* Special case for I2C_SMBUS_QUICK emulation.
+ * IBM IIC doesn't support 0-length transactions
+ * so we have to emulate them using bit-banging.
+ */
+ return iic_smbus_quick(dev, &msgs[0]);
+ }
+ DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
+ msgs[i].len, i);
+ return -EINVAL;
+ }
+ if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){
+ DBG("%d: invalid addr in msg[%d]\n", dev->idx, i);
+ return -EINVAL;
+ }
+ }
+
+ /* Check bus state */
+ if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
+ DBG("%d: iic_xfer, bus is not free\n", dev->idx);
+
+ /* Usually it means something serious has happened.
+ * We *cannot* have unfinished previous transfer
+ * so it doesn't make any sense to try to stop it.
+ * Probably we were not able to recover from the
+ * previous error.
+ * The only *reasonable* thing I can think of here
+ * is soft reset. --ebs
+ */
+ iic_dev_reset(dev);
+
+ if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
+ return -EREMOTEIO;
+ }
+ }
+ else {
+ /* Flush master data buffer (just in case) */
+ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+ }
+
+ /* Load slave address */
+ iic_address(dev, &msgs[0]);
+
+ /* Do real transfer */
+ for (i = 0; i < num && !ret; ++i)
+ ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
+
+ return ret < 0 ? ret : num;
+}
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm iic_algo = {
+ .master_xfer = iic_xfer,
+ .functionality = iic_func
+};
+
+/*
+ * Calculates IICx_CLCKDIV value for a specific OPB clock frequency
+ */
+static inline u8 iic_clckdiv(unsigned int opb)
+{
+ /* Compatibility kludge, should go away after all cards
+ * are fixed to fill correct value for opbfreq.
+ * Previous driver version used hardcoded divider value 4,
+ * it corresponds to OPB frequency from the range (40, 50] MHz
+ */
+ if (!opb){
+ printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq,"
+ " fix your board specific setup\n");
+ opb = 50000000;
+ }
+
+ /* Convert to MHz */
+ opb /= 1000000;
+
+ if (opb < 20 || opb > 150){
+ printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n",
+ opb);
+ opb = opb < 20 ? 20 : 150;
+ }
+ return (u8)((opb + 9) / 10 - 1);
+}
+
+static int __devinit iic_request_irq(struct platform_device *ofdev,
+ struct ibm_iic_private *dev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ int irq;
+
+ if (iic_force_poll)
+ return 0;
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
+ return 0;
+ }
+
+ /* Disable interrupts until we finish initialization, assumes
+ * level-sensitive IRQ setup...
+ */
+ iic_interrupt_mode(dev, 0);
+ if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
+ dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
+ /* Fallback to the polling mode */
+ return 0;
+ }
+
+ return irq;
+}
+
+/*
+ * Register single IIC interface
+ */
+static int __devinit iic_probe(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ struct ibm_iic_private *dev;
+ struct i2c_adapter *adap;
+ const u32 *freq;
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&ofdev->dev, "failed to allocate device data\n");
+ return -ENOMEM;
+ }
+
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ dev->vaddr = of_iomap(np, 0);
+ if (dev->vaddr == NULL) {
+ dev_err(&ofdev->dev, "failed to iomap device\n");
+ ret = -ENXIO;
+ goto error_cleanup;
+ }
+
+ init_waitqueue_head(&dev->wq);
+
+ dev->irq = iic_request_irq(ofdev, dev);
+ if (!dev->irq)
+ dev_warn(&ofdev->dev, "using polling mode\n");
+
+ /* Board specific settings */
+ if (iic_force_fast || of_get_property(np, "fast-mode", NULL))
+ dev->fast_mode = 1;
+
+ freq = of_get_property(np, "clock-frequency", NULL);
+ if (freq == NULL) {
+ freq = of_get_property(np->parent, "clock-frequency", NULL);
+ if (freq == NULL) {
+ dev_err(&ofdev->dev, "Unable to get bus frequency\n");
+ ret = -EINVAL;
+ goto error_cleanup;
+ }
+ }
+
+ dev->clckdiv = iic_clckdiv(*freq);
+ dev_dbg(&ofdev->dev, "clckdiv = %d\n", dev->clckdiv);
+
+ /* Initialize IIC interface */
+ iic_dev_init(dev);
+
+ /* Register it with i2c layer */
+ adap = &dev->adap;
+ adap->dev.parent = &ofdev->dev;
+ adap->dev.of_node = of_node_get(np);
+ strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
+ i2c_set_adapdata(adap, dev);
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = &iic_algo;
+ adap->timeout = HZ;
+
+ ret = i2c_add_adapter(adap);
+ if (ret < 0) {
+ dev_err(&ofdev->dev, "failed to register i2c adapter\n");
+ goto error_cleanup;
+ }
+
+ dev_info(&ofdev->dev, "using %s mode\n",
+ dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
+
+ /* Now register all the child nodes */
+ of_i2c_register_devices(adap);
+
+ return 0;
+
+error_cleanup:
+ if (dev->irq) {
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ }
+
+ if (dev->vaddr)
+ iounmap(dev->vaddr);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(dev);
+ return ret;
+}
+
+/*
+ * Cleanup initialized IIC interface
+ */
+static int __devexit iic_remove(struct platform_device *ofdev)
+{
+ struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ i2c_del_adapter(&dev->adap);
+
+ if (dev->irq) {
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ }
+
+ iounmap(dev->vaddr);
+ kfree(dev);
+
+ return 0;
+}
+
+static const struct of_device_id ibm_iic_match[] = {
+ { .compatible = "ibm,iic", },
+ {}
+};
+
+static struct platform_driver ibm_iic_driver = {
+ .driver = {
+ .name = "ibm-iic",
+ .owner = THIS_MODULE,
+ .of_match_table = ibm_iic_match,
+ },
+ .probe = iic_probe,
+ .remove = __devexit_p(iic_remove),
+};
+
+static int __init iic_init(void)
+{
+ return platform_driver_register(&ibm_iic_driver);
+}
+
+static void __exit iic_exit(void)
+{
+ platform_driver_unregister(&ibm_iic_driver);
+}
+
+module_init(iic_init);
+module_exit(iic_exit);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
new file mode 100644
index 00000000..fdaa4829
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -0,0 +1,123 @@
+/*
+ * drivers/i2c/busses/i2c-ibm_iic.h
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Ian DaSilva <idasilva@mvista.com>
+ * Armin Kuster <akuster@mvista.com>
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __I2C_IBM_IIC_H_
+#define __I2C_IBM_IIC_H_
+
+#include <linux/i2c.h>
+
+struct iic_regs {
+ u16 mdbuf;
+ u16 sbbuf;
+ u8 lmadr;
+ u8 hmadr;
+ u8 cntl;
+ u8 mdcntl;
+ u8 sts;
+ u8 extsts;
+ u8 lsadr;
+ u8 hsadr;
+ u8 clkdiv;
+ u8 intmsk;
+ u8 xfrcnt;
+ u8 xtcntlss;
+ u8 directcntl;
+};
+
+struct ibm_iic_private {
+ struct i2c_adapter adap;
+ volatile struct iic_regs __iomem *vaddr;
+ wait_queue_head_t wq;
+ int idx;
+ int irq;
+ int fast_mode;
+ u8 clckdiv;
+};
+
+/* IICx_CNTL register */
+#define CNTL_HMT 0x80
+#define CNTL_AMD 0x40
+#define CNTL_TCT_MASK 0x30
+#define CNTL_TCT_SHIFT 4
+#define CNTL_RPST 0x08
+#define CNTL_CHT 0x04
+#define CNTL_RW 0x02
+#define CNTL_PT 0x01
+
+/* IICx_MDCNTL register */
+#define MDCNTL_FSDB 0x80
+#define MDCNTL_FMDB 0x40
+#define MDCNTL_EGC 0x20
+#define MDCNTL_FSM 0x10
+#define MDCNTL_ESM 0x08
+#define MDCNTL_EINT 0x04
+#define MDCNTL_EUBS 0x02
+#define MDCNTL_HSCL 0x01
+
+/* IICx_STS register */
+#define STS_SSS 0x80
+#define STS_SLPR 0x40
+#define STS_MDBS 0x20
+#define STS_MDBF 0x10
+#define STS_SCMP 0x08
+#define STS_ERR 0x04
+#define STS_IRQA 0x02
+#define STS_PT 0x01
+
+/* IICx_EXTSTS register */
+#define EXTSTS_IRQP 0x80
+#define EXTSTS_BCS_MASK 0x70
+#define EXTSTS_BCS_FREE 0x40
+#define EXTSTS_IRQD 0x08
+#define EXTSTS_LA 0x04
+#define EXTSTS_ICT 0x02
+#define EXTSTS_XFRA 0x01
+
+/* IICx_INTRMSK register */
+#define INTRMSK_EIRC 0x80
+#define INTRMSK_EIRS 0x40
+#define INTRMSK_EIWC 0x20
+#define INTRMSK_EIWS 0x10
+#define INTRMSK_EIHE 0x08
+#define INTRMSK_EIIC 0x04
+#define INTRMSK_EITA 0x02
+#define INTRMSK_EIMTC 0x01
+
+/* IICx_XFRCNT register */
+#define XFRCNT_MTC_MASK 0x07
+
+/* IICx_XTCNTLSS register */
+#define XTCNTLSS_SRC 0x80
+#define XTCNTLSS_SRS 0x40
+#define XTCNTLSS_SWC 0x20
+#define XTCNTLSS_SWS 0x10
+#define XTCNTLSS_SRST 0x01
+
+/* IICx_DIRECTCNTL register */
+#define DIRCNTL_SDAC 0x08
+#define DIRCNTL_SCC 0x04
+#define DIRCNTL_MSDA 0x02
+#define DIRCNTL_MSC 0x01
+
+/* Check if we really control the I2C bus and bus is free */
+#define DIRCTNL_FREE(v) (((v) & 0x0f) == 0x0f)
+
+#endif /* __I2C_IBM_IIC_H_ */
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
new file mode 100644
index 00000000..364c4dea
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2002 Motorola GSG-China
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Author:
+ * Darius Augulis, Teltonika Inc.
+ *
+ * Desc.:
+ * Implementation of I2C Adapter/Algorithm Driver
+ * for I2C Bus integrated in Freescale i.MX/MXC processors
+ *
+ * Derived from Motorola GSG China I2C example driver
+ *
+ * Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de
+ * Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de
+ * Copyright (C) 2007 RightHand Technologies, Inc.
+ * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
+ *
+ */
+
+/** Includes *******************************************************************
+*******************************************************************************/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#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>
+#include <mach/i2c.h>
+
+/** Defines ********************************************************************
+*******************************************************************************/
+
+/* This will be the driver name the kernel reports */
+#define DRIVER_NAME "imx-i2c"
+
+/* Default value */
+#define IMX_I2C_BIT_RATE 100000 /* 100kHz */
+
+/* IMX I2C registers */
+#define IMX_I2C_IADR 0x00 /* i2c slave address */
+#define IMX_I2C_IFDR 0x04 /* i2c frequency divider */
+#define IMX_I2C_I2CR 0x08 /* i2c control */
+#define IMX_I2C_I2SR 0x0C /* i2c status */
+#define IMX_I2C_I2DR 0x10 /* i2c transfer data */
+
+/* Bits of IMX I2C registers */
+#define I2SR_RXAK 0x01
+#define I2SR_IIF 0x02
+#define I2SR_SRW 0x04
+#define I2SR_IAL 0x10
+#define I2SR_IBB 0x20
+#define I2SR_IAAS 0x40
+#define I2SR_ICF 0x80
+#define I2CR_RSTA 0x04
+#define I2CR_TXAK 0x08
+#define I2CR_MTX 0x10
+#define I2CR_MSTA 0x20
+#define I2CR_IIEN 0x40
+#define I2CR_IEN 0x80
+
+
+/** Variables ******************************************************************
+*******************************************************************************/
+
+/*
+ * sorted list of clock divider, register value pairs
+ * taken from table 26-5, p.26-9, Freescale i.MX
+ * Integrated Portable System Processor Reference Manual
+ * Document Number: MC9328MXLRM, Rev. 5.1, 06/2007
+ *
+ * Duplicated divider values removed from list
+ */
+
+static u16 i2c_clk_div[50][2] = {
+ { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
+ { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
+ { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
+ { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B },
+ { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A },
+ { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 },
+ { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 },
+ { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 },
+ { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 },
+ { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B },
+ { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
+ { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
+ { 3072, 0x1E }, { 3840, 0x1F }
+};
+
+struct imx_i2c_struct {
+ struct i2c_adapter adapter;
+ struct resource *res;
+ struct clk *clk;
+ void __iomem *base;
+ int irq;
+ wait_queue_head_t queue;
+ unsigned long i2csr;
+ unsigned int disable_delay;
+ int stopped;
+ unsigned int ifdr; /* IMX_I2C_IFDR */
+ unsigned int cur_clk;
+};
+
+/** Functions for IMX I2C adapter driver ***************************************
+*******************************************************************************/
+
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
+{
+ unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
+ unsigned long dwRetryMaxCnt=5000;
+ unsigned long dwRetryCnt=0;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ while (1) {
+ temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ if (for_busy && (temp & I2SR_IBB))
+ break;
+ if (!for_busy && !(temp & I2SR_IBB))
+ break;
+ if (fatal_signal_pending(current)) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> I2C Interrupted\n", __func__);
+ return -EINTR;
+ }
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> I2C bus is busy\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if(in_atomic() || in_interrupt() ) {
+ if(++dwRetryCnt>dwRetryMaxCnt) {
+ printk(KERN_ERR"%s retry over %d times \n",__FUNCTION__,dwRetryMaxCnt);
+ break;
+ }
+ udelay(100);
+ }
+ else {
+ schedule();
+ }
+ }
+
+ return 0;
+}
+
+static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
+{
+ if(in_atomic() || in_interrupt()) {
+ unsigned long dwRetryMaxCnt=1000;
+ unsigned long dwRetryCnt=0;
+
+ do {
+ i2c_imx->i2csr |= readb(i2c_imx->base + IMX_I2C_I2SR);
+ if(i2c_imx->i2csr & I2SR_IIF) {
+ break;
+ }
+
+ if(dwRetryCnt++>dwRetryMaxCnt) {
+ printk(KERN_ERR"%s retry over %d times !!\n",__FUNCTION__,dwRetryMaxCnt);
+ break;
+ }
+ udelay(100);
+ }while(1) ;
+
+ }
+ else {
+ wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
+ }
+
+ if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
+ i2c_imx->i2csr = 0;
+ return 0;
+}
+
+static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
+{
+ if (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_RXAK) {
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
+ return -EIO; /* No ACK */
+ }
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
+ return 0;
+}
+
+static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+ unsigned int rate)
+{
+ unsigned int i2c_clk_rate;
+ unsigned int div;
+ int i;
+
+ /* Divider value calculation */
+ i2c_clk_rate = clk_get_rate(i2c_imx->clk);
+ if (i2c_imx->cur_clk == i2c_clk_rate)
+ return;
+ else
+ i2c_imx->cur_clk = i2c_clk_rate;
+ div = (i2c_clk_rate + rate - 1) / rate;
+ if (div < i2c_clk_div[0][0])
+ i = 0;
+ else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+ i = ARRAY_SIZE(i2c_clk_div) - 1;
+ else
+ for (i = 0; i2c_clk_div[i][0] < div; i++)
+ ;
+
+ /* Store divider value */
+ i2c_imx->ifdr = i2c_clk_div[i][1];
+
+ /*
+ * There dummy delay is calculated.
+ * It should be about one I2C clock period long.
+ * This delay is used in I2C bus disable function
+ * to fix chip hardware bug.
+ */
+ i2c_imx->disable_delay = (500000U * i2c_clk_div[i][0]
+ + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
+
+ /* dev_dbg() can't be used, because adapter is not yet registered */
+#ifdef CONFIG_I2C_DEBUG_BUS
+ printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n",
+ __func__, i2c_clk_rate, div);
+ printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+ __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
+#endif
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+ unsigned int temp = 0;
+ struct imxi2c_platform_data *pdata;
+ int result;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ /* Currently on Arik/Rigel, the I2C clk is from IPG_PERCLK which is
+ * sourced from IPG_CLK. In low bus freq mode, IPG_CLK is at 12MHz
+ * and IPG_PERCLK is down to 4MHz.
+ * Update I2C divider before set i2c clock.
+ */
+ pdata = i2c_imx->adapter.dev.parent->platform_data;
+ if (pdata && pdata->bitrate)
+ i2c_imx_set_clk(i2c_imx, pdata->bitrate);
+ else
+ i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
+
+ clk_enable(i2c_imx->clk);
+ writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
+ /* Enable I2C controller */
+ writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+ writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+
+ /* Wait controller to be stable */
+ udelay(50);
+
+ /* Start I2C transaction */
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp |= I2CR_MSTA;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ result = i2c_imx_bus_busy(i2c_imx, 1);
+ if (result)
+ return result;
+ i2c_imx->stopped = 0;
+
+ temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ return result;
+}
+
+static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+{
+ unsigned int temp = 0;
+
+ if (!i2c_imx->stopped) {
+ /* Stop I2C transaction */
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ }
+ if (cpu_is_mx1()) {
+ /*
+ * This delay caused by an i.MXL hardware bug.
+ * If no (or too short) delay, no "STOP" bit will be generated.
+ */
+ udelay(i2c_imx->disable_delay);
+ }
+
+ 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);
+ clk_disable(i2c_imx->clk);
+}
+
+static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
+{
+ struct imx_i2c_struct *i2c_imx = dev_id;
+ unsigned int temp;
+
+ temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ if (temp & I2SR_IIF) {
+ /* save status register */
+ i2c_imx->i2csr = temp;
+ temp &= ~I2SR_IIF;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2SR);
+ wake_up(&i2c_imx->queue);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+{
+ int i, result;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
+ __func__, msgs->addr << 1);
+
+ /* write slave address */
+ writeb(msgs->addr << 1, i2c_imx->base + IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ result = i2c_imx_acked(i2c_imx);
+ if (result)
+ return result;
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> write data\n", __func__);
+
+ /* write data */
+ for (i = 0; i < msgs->len; i++) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> write byte: B%d=0x%X\n",
+ __func__, i, msgs->buf[i]);
+ writeb(msgs->buf[i], i2c_imx->base + IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ result = i2c_imx_acked(i2c_imx);
+ if (result)
+ return result;
+ }
+ return 0;
+}
+
+static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+{
+ int i, result;
+ unsigned int temp;
+
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> write slave address: addr=0x%x\n",
+ __func__, (msgs->addr << 1) | 0x01);
+
+ /* write slave address */
+ writeb((msgs->addr << 1) | 0x01, i2c_imx->base + IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ result = i2c_imx_acked(i2c_imx);
+ if (result)
+ return result;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
+
+ /* setup bus to read data */
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp &= ~I2CR_MTX;
+ if (msgs->len - 1)
+ temp &= ~I2CR_TXAK;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ readb(i2c_imx->base + IMX_I2C_I2DR); /* dummy read */
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
+
+ /* read data */
+ for (i = 0; i < msgs->len; i++) {
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ if (i == (msgs->len - 1)) {
+ /* It must generate STOP before read I2DR to prevent
+ controller from generating another clock cycle */
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> clear MSTA\n", __func__);
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx->stopped = 1;
+ } else if (i == (msgs->len - 2)) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> set TXAK\n", __func__);
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp |= I2CR_TXAK;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ }
+ msgs->buf[i] = readb(i2c_imx->base + IMX_I2C_I2DR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> read byte: B%d=0x%X\n",
+ __func__, i, msgs->buf[i]);
+ }
+ return 0;
+}
+
+static int i2c_imx_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ unsigned int i, temp;
+ int result;
+ struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ /* Start I2C transfer */
+ result = i2c_imx_start(i2c_imx);
+ if (result)
+ goto fail0;
+
+ /* read/write data */
+ for (i = 0; i < num; i++) {
+ if (i) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> repeated start\n", __func__);
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp |= I2CR_RSTA;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ result = i2c_imx_bus_busy(i2c_imx, 1);
+ if (result)
+ goto fail0;
+ }
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> transfer message: %d\n", __func__, i);
+ /* write/read data */
+#ifdef CONFIG_I2C_DEBUG_BUS
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, "
+ "MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__,
+ (temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
+ (temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
+ (temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
+ temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
+ "IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__,
+ (temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
+ (temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
+ (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
+ (temp & I2SR_RXAK ? 1 : 0));
+#endif
+ if (msgs[i].flags & I2C_M_RD)
+ result = i2c_imx_read(i2c_imx, &msgs[i]);
+ else
+ result = i2c_imx_write(i2c_imx, &msgs[i]);
+ if (result)
+ goto fail0;
+ }
+
+fail0:
+ /* Stop I2C transfer */
+ i2c_imx_stop(i2c_imx);
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+ (result < 0) ? "error" : "success msg",
+ (result < 0) ? result : num);
+ return (result < 0) ? result : num;
+}
+
+static u32 i2c_imx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm i2c_imx_algo = {
+ .master_xfer = i2c_imx_xfer,
+ .functionality = i2c_imx_func,
+};
+
+static int __init i2c_imx_probe(struct platform_device *pdev)
+{
+ struct imx_i2c_struct *i2c_imx;
+ struct resource *res;
+ struct imxi2c_platform_data *pdata;
+ void __iomem *base;
+ resource_size_t res_size;
+ int irq;
+ int ret;
+
+ dev_dbg(&pdev->dev, "<%s>\n", __func__);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ return -ENOENT;
+ }
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "can't get irq number\n");
+ return -ENOENT;
+ }
+
+ pdata = pdev->dev.platform_data;
+
+ if (pdata && pdata->init) {
+ ret = pdata->init(&pdev->dev);
+ if (ret)
+ return ret;
+ }
+
+ 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 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 fail2;
+ }
+
+ /* Setup i2c_imx driver structure */
+ strcpy(i2c_imx->adapter.name, pdev->name);
+ i2c_imx->adapter.owner = THIS_MODULE;
+ i2c_imx->adapter.algo = &i2c_imx_algo;
+ i2c_imx->adapter.dev.parent = &pdev->dev;
+ i2c_imx->adapter.nr = pdev->id;
+ i2c_imx->irq = irq;
+ i2c_imx->base = base;
+ i2c_imx->res = res;
+
+ /* Get I2C clock */
+ i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
+ if (IS_ERR(i2c_imx->clk)) {
+ ret = PTR_ERR(i2c_imx->clk);
+ dev_err(&pdev->dev, "can't get I2C clock\n");
+ goto fail3;
+ }
+
+ /* Request IRQ */
+ ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq);
+ goto fail4;
+ }
+
+ /* Init queue */
+ init_waitqueue_head(&i2c_imx->queue);
+
+ /* Set up adapter data */
+ i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
+
+ /* Set up clock divider */
+ if (pdata && pdata->bitrate)
+ i2c_imx_set_clk(i2c_imx, pdata->bitrate);
+ else
+ i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
+
+ /* Set up chip registers to defaults */
+ writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+ writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+
+ /* Add I2C adapter */
+ ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "registration failed\n");
+ goto fail5;
+ }
+
+ /* Set up platform driver data */
+ platform_set_drvdata(pdev, i2c_imx);
+
+ dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq);
+ dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
+ i2c_imx->res->start, i2c_imx->res->end);
+ dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n",
+ res_size, i2c_imx->res->start);
+ dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
+ i2c_imx->adapter.name);
+ dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
+
+ return 0; /* Return OK */
+
+fail5:
+ free_irq(i2c_imx->irq, i2c_imx);
+fail4:
+ clk_put(i2c_imx->clk);
+fail3:
+ kfree(i2c_imx);
+fail2:
+ iounmap(base);
+fail1:
+ release_mem_region(res->start, resource_size(res));
+fail0:
+ if (pdata && pdata->exit)
+ pdata->exit(&pdev->dev);
+ return ret; /* Return error number */
+}
+
+static int __exit i2c_imx_remove(struct platform_device *pdev)
+{
+ struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
+ struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+
+ /* remove adapter */
+ dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
+ i2c_del_adapter(&i2c_imx->adapter);
+ platform_set_drvdata(pdev, NULL);
+
+ /* free interrupt */
+ free_irq(i2c_imx->irq, i2c_imx);
+
+ /* setup chip registers to defaults */
+ writeb(0, i2c_imx->base + IMX_I2C_IADR);
+ writeb(0, i2c_imx->base + IMX_I2C_IFDR);
+ writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+ writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+
+ /* Shut down hardware */
+ if (pdata && pdata->exit)
+ pdata->exit(&pdev->dev);
+
+ clk_put(i2c_imx->clk);
+
+ 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 = {
+ .remove = __exit_p(i2c_imx_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init i2c_adap_imx_init(void)
+{
+ return platform_driver_probe(&i2c_imx_driver, i2c_imx_probe);
+}
+subsys_initcall(i2c_adap_imx_init);
+
+static void __exit i2c_adap_imx_exit(void)
+{
+ platform_driver_unregister(&i2c_imx_driver);
+}
+module_exit(i2c_adap_imx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Darius Augulis");
+MODULE_DESCRIPTION("I2C adapter driver for IMX I2C bus");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c
new file mode 100644
index 00000000..e828ac85
--- /dev/null
+++ b/drivers/i2c/busses/i2c-intel-mid.c
@@ -0,0 +1,1135 @@
+/*
+ * Support for Moorestown/Medfield I2C chip
+ *
+ * Copyright (c) 2009 Intel Corporation.
+ * Copyright (c) 2009 Synopsys. Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License, version
+ * 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 51
+ * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME "i2c-intel-mid"
+#define VERSION "Version 0.5ac2"
+#define PLATFORM "Moorestown/Medfield"
+
+/* Tables use: 0 Moorestown, 1 Medfield */
+#define NUM_PLATFORMS 2
+enum platform_enum {
+ MOORESTOWN = 0,
+ MEDFIELD = 1,
+};
+
+enum mid_i2c_status {
+ STATUS_IDLE = 0,
+ STATUS_READ_START,
+ STATUS_READ_IN_PROGRESS,
+ STATUS_READ_SUCCESS,
+ STATUS_WRITE_START,
+ STATUS_WRITE_SUCCESS,
+ STATUS_XFER_ABORT,
+ STATUS_STANDBY
+};
+
+/**
+ * struct intel_mid_i2c_private - per device I²C context
+ * @adap: core i2c layer adapter information
+ * @dev: device reference for power management
+ * @base: register base
+ * @speed: speed mode for this port
+ * @complete: completion object for transaction wait
+ * @abort: reason for last abort
+ * @rx_buf: pointer into working receive buffer
+ * @rx_buf_len: receive buffer length
+ * @status: adapter state machine
+ * @msg: the message we are currently processing
+ * @platform: the MID device type we are part of
+ * @lock: transaction serialization
+ *
+ * We allocate one of these per device we discover, it holds the core
+ * i2c layer objects and the data we need to track privately.
+ */
+struct intel_mid_i2c_private {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ int speed;
+ struct completion complete;
+ int abort;
+ u8 *rx_buf;
+ int rx_buf_len;
+ enum mid_i2c_status status;
+ struct i2c_msg *msg;
+ enum platform_enum platform;
+ struct mutex lock;
+};
+
+#define NUM_SPEEDS 3
+
+#define ACTIVE 0
+#define STANDBY 1
+
+
+/* Control register */
+#define IC_CON 0x00
+#define SLV_DIS (1 << 6) /* Disable slave mode */
+#define RESTART (1 << 5) /* Send a Restart condition */
+#define ADDR_10BIT (1 << 4) /* 10-bit addressing */
+#define STANDARD_MODE (1 << 1) /* standard mode */
+#define FAST_MODE (2 << 1) /* fast mode */
+#define HIGH_MODE (3 << 1) /* high speed mode */
+#define MASTER_EN (1 << 0) /* Master mode */
+
+/* Target address register */
+#define IC_TAR 0x04
+#define IC_TAR_10BIT_ADDR (1 << 12) /* 10-bit addressing */
+#define IC_TAR_SPECIAL (1 << 11) /* Perform special I2C cmd */
+#define IC_TAR_GC_OR_START (1 << 10) /* 0: Gerneral Call Address */
+ /* 1: START BYTE */
+/* Slave Address Register */
+#define IC_SAR 0x08 /* Not used in Master mode */
+
+/* High Speed Master Mode Code Address Register */
+#define IC_HS_MADDR 0x0c
+
+/* Rx/Tx Data Buffer and Command Register */
+#define IC_DATA_CMD 0x10
+#define IC_RD (1 << 8) /* 1: Read 0: Write */
+
+/* Standard Speed Clock SCL High Count Register */
+#define IC_SS_SCL_HCNT 0x14
+
+/* Standard Speed Clock SCL Low Count Register */
+#define IC_SS_SCL_LCNT 0x18
+
+/* Fast Speed Clock SCL High Count Register */
+#define IC_FS_SCL_HCNT 0x1c
+
+/* Fast Spedd Clock SCL Low Count Register */
+#define IC_FS_SCL_LCNT 0x20
+
+/* High Speed Clock SCL High Count Register */
+#define IC_HS_SCL_HCNT 0x24
+
+/* High Speed Clock SCL Low Count Register */
+#define IC_HS_SCL_LCNT 0x28
+
+/* Interrupt Status Register */
+#define IC_INTR_STAT 0x2c /* Read only */
+#define R_GEN_CALL (1 << 11)
+#define R_START_DET (1 << 10)
+#define R_STOP_DET (1 << 9)
+#define R_ACTIVITY (1 << 8)
+#define R_RX_DONE (1 << 7)
+#define R_TX_ABRT (1 << 6)
+#define R_RD_REQ (1 << 5)
+#define R_TX_EMPTY (1 << 4)
+#define R_TX_OVER (1 << 3)
+#define R_RX_FULL (1 << 2)
+#define R_RX_OVER (1 << 1)
+#define R_RX_UNDER (1 << 0)
+
+/* Interrupt Mask Register */
+#define IC_INTR_MASK 0x30 /* Read and Write */
+#define M_GEN_CALL (1 << 11)
+#define M_START_DET (1 << 10)
+#define M_STOP_DET (1 << 9)
+#define M_ACTIVITY (1 << 8)
+#define M_RX_DONE (1 << 7)
+#define M_TX_ABRT (1 << 6)
+#define M_RD_REQ (1 << 5)
+#define M_TX_EMPTY (1 << 4)
+#define M_TX_OVER (1 << 3)
+#define M_RX_FULL (1 << 2)
+#define M_RX_OVER (1 << 1)
+#define M_RX_UNDER (1 << 0)
+
+/* Raw Interrupt Status Register */
+#define IC_RAW_INTR_STAT 0x34 /* Read Only */
+#define GEN_CALL (1 << 11) /* General call */
+#define START_DET (1 << 10) /* (RE)START occurred */
+#define STOP_DET (1 << 9) /* STOP occurred */
+#define ACTIVITY (1 << 8) /* Bus busy */
+#define RX_DONE (1 << 7) /* Not used in Master mode */
+#define TX_ABRT (1 << 6) /* Transmit Abort */
+#define RD_REQ (1 << 5) /* Not used in Master mode */
+#define TX_EMPTY (1 << 4) /* TX FIFO <= threshold */
+#define TX_OVER (1 << 3) /* TX FIFO overflow */
+#define RX_FULL (1 << 2) /* RX FIFO >= threshold */
+#define RX_OVER (1 << 1) /* RX FIFO overflow */
+#define RX_UNDER (1 << 0) /* RX FIFO empty */
+
+/* Receive FIFO Threshold Register */
+#define IC_RX_TL 0x38
+
+/* Transmit FIFO Treshold Register */
+#define IC_TX_TL 0x3c
+
+/* Clear Combined and Individual Interrupt Register */
+#define IC_CLR_INTR 0x40
+#define CLR_INTR (1 << 0)
+
+/* Clear RX_UNDER Interrupt Register */
+#define IC_CLR_RX_UNDER 0x44
+#define CLR_RX_UNDER (1 << 0)
+
+/* Clear RX_OVER Interrupt Register */
+#define IC_CLR_RX_OVER 0x48
+#define CLR_RX_OVER (1 << 0)
+
+/* Clear TX_OVER Interrupt Register */
+#define IC_CLR_TX_OVER 0x4c
+#define CLR_TX_OVER (1 << 0)
+
+#define IC_CLR_RD_REQ 0x50
+
+/* Clear TX_ABRT Interrupt Register */
+#define IC_CLR_TX_ABRT 0x54
+#define CLR_TX_ABRT (1 << 0)
+#define IC_CLR_RX_DONE 0x58
+
+/* Clear ACTIVITY Interrupt Register */
+#define IC_CLR_ACTIVITY 0x5c
+#define CLR_ACTIVITY (1 << 0)
+
+/* Clear STOP_DET Interrupt Register */
+#define IC_CLR_STOP_DET 0x60
+#define CLR_STOP_DET (1 << 0)
+
+/* Clear START_DET Interrupt Register */
+#define IC_CLR_START_DET 0x64
+#define CLR_START_DET (1 << 0)
+
+/* Clear GEN_CALL Interrupt Register */
+#define IC_CLR_GEN_CALL 0x68
+#define CLR_GEN_CALL (1 << 0)
+
+/* Enable Register */
+#define IC_ENABLE 0x6c
+#define ENABLE (1 << 0)
+
+/* Status Register */
+#define IC_STATUS 0x70 /* Read Only */
+#define STAT_SLV_ACTIVITY (1 << 6) /* Slave not in idle */
+#define STAT_MST_ACTIVITY (1 << 5) /* Master not in idle */
+#define STAT_RFF (1 << 4) /* RX FIFO Full */
+#define STAT_RFNE (1 << 3) /* RX FIFO Not Empty */
+#define STAT_TFE (1 << 2) /* TX FIFO Empty */
+#define STAT_TFNF (1 << 1) /* TX FIFO Not Full */
+#define STAT_ACTIVITY (1 << 0) /* Activity Status */
+
+/* Transmit FIFO Level Register */
+#define IC_TXFLR 0x74 /* Read Only */
+#define TXFLR (1 << 0) /* TX FIFO level */
+
+/* Receive FIFO Level Register */
+#define IC_RXFLR 0x78 /* Read Only */
+#define RXFLR (1 << 0) /* RX FIFO level */
+
+/* Transmit Abort Source Register */
+#define IC_TX_ABRT_SOURCE 0x80
+#define ABRT_SLVRD_INTX (1 << 15)
+#define ABRT_SLV_ARBLOST (1 << 14)
+#define ABRT_SLVFLUSH_TXFIFO (1 << 13)
+#define ARB_LOST (1 << 12)
+#define ABRT_MASTER_DIS (1 << 11)
+#define ABRT_10B_RD_NORSTRT (1 << 10)
+#define ABRT_SBYTE_NORSTRT (1 << 9)
+#define ABRT_HS_NORSTRT (1 << 8)
+#define ABRT_SBYTE_ACKDET (1 << 7)
+#define ABRT_HS_ACKDET (1 << 6)
+#define ABRT_GCALL_READ (1 << 5)
+#define ABRT_GCALL_NOACK (1 << 4)
+#define ABRT_TXDATA_NOACK (1 << 3)
+#define ABRT_10ADDR2_NOACK (1 << 2)
+#define ABRT_10ADDR1_NOACK (1 << 1)
+#define ABRT_7B_ADDR_NOACK (1 << 0)
+
+/* Enable Status Register */
+#define IC_ENABLE_STATUS 0x9c
+#define IC_EN (1 << 0) /* I2C in an enabled state */
+
+/* Component Parameter Register 1*/
+#define IC_COMP_PARAM_1 0xf4
+#define APB_DATA_WIDTH (0x3 << 0)
+
+/* added by xiaolin --begin */
+#define SS_MIN_SCL_HIGH 4000
+#define SS_MIN_SCL_LOW 4700
+#define FS_MIN_SCL_HIGH 600
+#define FS_MIN_SCL_LOW 1300
+#define HS_MIN_SCL_HIGH_100PF 60
+#define HS_MIN_SCL_LOW_100PF 120
+
+#define STANDARD 0
+#define FAST 1
+#define HIGH 2
+
+#define NUM_SPEEDS 3
+
+static int speed_mode[6] = {
+ FAST,
+ FAST,
+ FAST,
+ STANDARD,
+ FAST,
+ FAST
+};
+
+static int ctl_num = 6;
+module_param_array(speed_mode, int, &ctl_num, S_IRUGO);
+MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)");
+
+/**
+ * intel_mid_i2c_disable - Disable I2C controller
+ * @adap: struct pointer to i2c_adapter
+ *
+ * Return Value:
+ * 0 success
+ * -EBUSY if device is busy
+ * -ETIMEDOUT if i2c cannot be disabled within the given time
+ *
+ * I2C bus state should be checked prior to disabling the hardware. If bus is
+ * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable
+ * I2C controller.
+ */
+static int intel_mid_i2c_disable(struct i2c_adapter *adap)
+{
+ struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+ int err = 0;
+ int count = 0;
+ int ret1, ret2;
+ static const u16 delay[NUM_SPEEDS] = {100, 25, 3};
+
+ /* Set IC_ENABLE to 0 */
+ writel(0, i2c->base + IC_ENABLE);
+
+ /* Check if device is busy */
+ dev_dbg(&adap->dev, "mrst i2c disable\n");
+ while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1)
+ || (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) {
+ udelay(delay[i2c->speed]);
+ writel(0, i2c->base + IC_ENABLE);
+ dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n",
+ count, i2c->speed);
+ if (count++ > 10) {
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ /* Clear all interrupts */
+ readl(i2c->base + IC_CLR_INTR);
+ readl(i2c->base + IC_CLR_STOP_DET);
+ readl(i2c->base + IC_CLR_START_DET);
+ readl(i2c->base + IC_CLR_ACTIVITY);
+ readl(i2c->base + IC_CLR_TX_ABRT);
+ readl(i2c->base + IC_CLR_RX_OVER);
+ readl(i2c->base + IC_CLR_RX_UNDER);
+ readl(i2c->base + IC_CLR_TX_OVER);
+ readl(i2c->base + IC_CLR_RX_DONE);
+ readl(i2c->base + IC_CLR_GEN_CALL);
+
+ /* Disable all interupts */
+ writel(0x0000, i2c->base + IC_INTR_MASK);
+
+ return err;
+}
+
+/**
+ * intel_mid_i2c_hwinit - Initialize the I2C hardware registers
+ * @dev: pci device struct pointer
+ *
+ * This function will be called in intel_mid_i2c_probe() before device
+ * registration.
+ *
+ * Return Values:
+ * 0 success
+ * -EBUSY i2c cannot be disabled
+ * -ETIMEDOUT i2c cannot be disabled
+ * -EFAULT If APB data width is not 32-bit wide
+ *
+ * I2C should be disabled prior to other register operation. If failed, an
+ * errno is returned. Mask and Clear all interrpts, this should be done at
+ * first. Set common registers which will not be modified during normal
+ * transfers, including: control register, FIFO threshold and clock freq.
+ * Check APB data width at last.
+ */
+static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c)
+{
+ int err;
+
+ static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
+ { 0x75, 0x15, 0x07 },
+ { 0x04c, 0x10, 0x06 }
+ };
+ static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
+ { 0x7C, 0x21, 0x0E },
+ { 0x053, 0x19, 0x0F }
+ };
+
+ /* Disable i2c first */
+ err = intel_mid_i2c_disable(&i2c->adap);
+ if (err)
+ return err;
+
+ /*
+ * Setup clock frequency and speed mode
+ * Enable restart condition,
+ * enable master FSM, disable slave FSM,
+ * use target address when initiating transfer
+ */
+
+ writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN,
+ i2c->base + IC_CON);
+ writel(hcnt[i2c->platform][i2c->speed],
+ i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3)));
+ writel(lcnt[i2c->platform][i2c->speed],
+ i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3)));
+
+ /* Set tranmit & receive FIFO threshold to zero */
+ writel(0x0, i2c->base + IC_RX_TL);
+ writel(0x0, i2c->base + IC_TX_TL);
+
+ return 0;
+}
+
+/**
+ * intel_mid_i2c_func - Return the supported three I2C operations.
+ * @adapter: i2c_adapter struct pointer
+ */
+static u32 intel_mid_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+/**
+ * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages
+ * are equal.
+ * @p1: first i2c_msg
+ * @p2: second i2c_msg
+ *
+ * Return Values:
+ * 0 if addresses are equal
+ * 1 if not equal
+ *
+ * Within a single transfer, the I2C client may need to send its address more
+ * than once. So a check if the addresses match is needed.
+ */
+static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1,
+ const struct i2c_msg *p2)
+{
+ if (p1->addr != p2->addr)
+ return 1;
+ if ((p1->flags ^ p2->flags) & I2C_M_TEN)
+ return 1;
+ return 0;
+}
+
+/**
+ * intel_mid_i2c_abort - To handle transfer abortions and print error messages.
+ * @adap: i2c_adapter struct pointer
+ *
+ * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be
+ * distingushed. At present, no circumstances have been found out that
+ * multiple errors would be occurred simutaneously, so we simply use the
+ * register value directly.
+ *
+ * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need
+ * a few extra steps)
+ */
+static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c)
+{
+ /* Read about source register */
+ int abort = i2c->abort;
+ struct i2c_adapter *adap = &i2c->adap;
+
+ /* Single transfer error check:
+ * According to databook, TX/RX FIFOs would be flushed when
+ * the abort interrupt occurred.
+ */
+ if (abort & ABRT_MASTER_DIS)
+ dev_err(&adap->dev,
+ "initiate master operation with master mode disabled.\n");
+ if (abort & ABRT_10B_RD_NORSTRT)
+ dev_err(&adap->dev,
+ "RESTART disabled and master sent READ cmd in 10-bit addressing.\n");
+
+ if (abort & ABRT_SBYTE_NORSTRT) {
+ dev_err(&adap->dev,
+ "RESTART disabled and user is trying to send START byte.\n");
+ writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE);
+ writel(RESTART, i2c->base + IC_CON);
+ writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR);
+ }
+
+ if (abort & ABRT_SBYTE_ACKDET)
+ dev_err(&adap->dev,
+ "START byte was not acknowledged.\n");
+ if (abort & ABRT_TXDATA_NOACK)
+ dev_dbg(&adap->dev,
+ "No acknowledgement received from slave.\n");
+ if (abort & ABRT_10ADDR2_NOACK)
+ dev_dbg(&adap->dev,
+ "The 2nd address byte of the 10-bit address was not acknowledged.\n");
+ if (abort & ABRT_10ADDR1_NOACK)
+ dev_dbg(&adap->dev,
+ "The 1st address byte of 10-bit address was not acknowledged.\n");
+ if (abort & ABRT_7B_ADDR_NOACK)
+ dev_dbg(&adap->dev,
+ "I2C slave device not acknowledged.\n");
+
+ /* Clear TX_ABRT bit */
+ readl(i2c->base + IC_CLR_TX_ABRT);
+ i2c->status = STATUS_XFER_ABORT;
+}
+
+/**
+ * xfer_read - Internal function to implement master read transfer.
+ * @adap: i2c_adapter struct pointer
+ * @buf: buffer in i2c_msg
+ * @length: number of bytes to be read
+ *
+ * Return Values:
+ * 0 if the read transfer succeeds
+ * -ETIMEDOUT if cannot read the "raw" interrupt register
+ * -EINVAL if a transfer abort occurred
+ *
+ * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to
+ * data transfer. The actual "read" operation will be performed if an RX_FULL
+ * interrupt occurred.
+ *
+ * Note there may be two interrupt signals captured, one should read
+ * IC_RAW_INTR_STAT to separate between errors and actual data.
+ */
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+ int i = length;
+ int err;
+
+ if (length >= 256) {
+ dev_err(&adap->dev,
+ "I2C FIFO cannot support larger than 256 bytes\n");
+ return -EMSGSIZE;
+ }
+
+ INIT_COMPLETION(i2c->complete);
+
+ readl(i2c->base + IC_CLR_INTR);
+ writel(0x0044, i2c->base + IC_INTR_MASK);
+
+ i2c->status = STATUS_READ_START;
+
+ while (i--)
+ writel(IC_RD, i2c->base + IC_DATA_CMD);
+
+ i2c->status = STATUS_READ_START;
+ err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+ if (!err) {
+ dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
+ intel_mid_i2c_hwinit(i2c);
+ return -ETIMEDOUT;
+ }
+ if (i2c->status == STATUS_READ_SUCCESS)
+ return 0;
+ else
+ return -EIO;
+}
+
+/**
+ * xfer_write - Internal function to implement master write transfer.
+ * @adap: i2c_adapter struct pointer
+ * @buf: buffer in i2c_msg
+ * @length: number of bytes to be read
+ *
+ * Return Values:
+ * 0 if the read transfer succeeds
+ * -ETIMEDOUT if we cannot read the "raw" interrupt register
+ * -EINVAL if a transfer abort occurred
+ *
+ * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to
+ * data transfer. The actual "write" operation will be performed when the
+ * RX_FULL interrupt signal occurs.
+ *
+ * Note there may be two interrupt signals captured, one should read
+ * IC_RAW_INTR_STAT to separate between errors and actual data.
+ */
+static int xfer_write(struct i2c_adapter *adap,
+ unsigned char *buf, int length)
+{
+ struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+ int i, err;
+
+ if (length >= 256) {
+ dev_err(&adap->dev,
+ "I2C FIFO cannot support larger than 256 bytes\n");
+ return -EMSGSIZE;
+ }
+
+ INIT_COMPLETION(i2c->complete);
+
+ readl(i2c->base + IC_CLR_INTR);
+ writel(0x0050, i2c->base + IC_INTR_MASK);
+
+ i2c->status = STATUS_WRITE_START;
+ for (i = 0; i < length; i++)
+ writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD);
+
+ i2c->status = STATUS_WRITE_START;
+ err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+ if (!err) {
+ dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
+ intel_mid_i2c_hwinit(i2c);
+ return -ETIMEDOUT;
+ } else {
+ if (i2c->status == STATUS_WRITE_SUCCESS)
+ return 0;
+ else
+ return -EIO;
+ }
+}
+
+static int intel_mid_i2c_setup(struct i2c_adapter *adap, struct i2c_msg *pmsg)
+{
+ struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+ int err;
+ u32 reg;
+ u32 bit_mask;
+ u32 mode;
+
+ /* Disable device first */
+ err = intel_mid_i2c_disable(adap);
+ if (err) {
+ dev_err(&adap->dev,
+ "Cannot disable i2c controller, timeout\n");
+ return err;
+ }
+
+ mode = (1 + i2c->speed) << 1;
+ /* set the speed mode */
+ reg = readl(i2c->base + IC_CON);
+ if ((reg & 0x06) != mode) {
+ dev_dbg(&adap->dev, "set mode %d\n", i2c->speed);
+ writel((reg & ~0x6) | mode, i2c->base + IC_CON);
+ }
+
+ reg = readl(i2c->base + IC_CON);
+ /* use 7-bit addressing */
+ if (pmsg->flags & I2C_M_TEN) {
+ if ((reg & ADDR_10BIT) != ADDR_10BIT) {
+ dev_dbg(&adap->dev, "set i2c 10 bit address mode\n");
+ writel(reg | ADDR_10BIT, i2c->base + IC_CON);
+ }
+ } else {
+ if ((reg & ADDR_10BIT) != 0x0) {
+ dev_dbg(&adap->dev, "set i2c 7 bit address mode\n");
+ writel(reg & ~ADDR_10BIT, i2c->base + IC_CON);
+ }
+ }
+ /* enable restart conditions */
+ reg = readl(i2c->base + IC_CON);
+ if ((reg & RESTART) != RESTART) {
+ dev_dbg(&adap->dev, "enable restart conditions\n");
+ writel(reg | RESTART, i2c->base + IC_CON);
+ }
+
+ /* enable master FSM */
+ reg = readl(i2c->base + IC_CON);
+ dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
+ writel(reg | MASTER_EN, i2c->base + IC_CON);
+ if ((reg & SLV_DIS) != SLV_DIS) {
+ dev_dbg(&adap->dev, "enable master FSM\n");
+ writel(reg | SLV_DIS, i2c->base + IC_CON);
+ dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
+ }
+
+ /* use target address when initiating transfer */
+ reg = readl(i2c->base + IC_TAR);
+ bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START;
+
+ if ((reg & bit_mask) != 0x0) {
+ dev_dbg(&adap->dev,
+ "WR: use target address when intiating transfer, i2c_tx_target\n");
+ writel(reg & ~bit_mask, i2c->base + IC_TAR);
+ }
+
+ /* set target address to the I2C slave address */
+ dev_dbg(&adap->dev,
+ "set target address to the I2C slave address, addr is %x\n",
+ pmsg->addr);
+ writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0),
+ i2c->base + IC_TAR);
+
+ /* Enable I2C controller */
+ writel(ENABLE, i2c->base + IC_ENABLE);
+
+ return 0;
+}
+
+/**
+ * intel_mid_i2c_xfer - Main master transfer routine.
+ * @adap: i2c_adapter struct pointer
+ * @pmsg: i2c_msg struct pointer
+ * @num: number of i2c_msg
+ *
+ * Return Values:
+ * + number of messages transferred
+ * -ETIMEDOUT If cannot disable I2C controller or read IC_STATUS
+ * -EINVAL If the address in i2c_msg is invalid
+ *
+ * This function will be registered in i2c-core and exposed to external
+ * I2C clients.
+ * 1. Disable I2C controller
+ * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT
+ * 3. Check if address in i2c_msg is valid
+ * 4. Enable I2C controller
+ * 5. Perform real transfer (call xfer_read or xfer_write)
+ * 6. Wait until the current transfer is finished (check bus state)
+ * 7. Mask and clear all interrupts
+ */
+static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg,
+ int num)
+{
+ struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+ int i, err = 0;
+
+ /* if number of messages equal 0*/
+ if (num == 0)
+ return 0;
+
+ pm_runtime_get(i2c->dev);
+
+ mutex_lock(&i2c->lock);
+ dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num);
+ dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr);
+
+
+ if (i2c->status != STATUS_IDLE) {
+ dev_err(&adap->dev, "Adapter %d in transfer/standby\n",
+ adap->nr);
+ mutex_unlock(&i2c->lock);
+ pm_runtime_put(i2c->dev);
+ return -1;
+ }
+
+
+ for (i = 1; i < num; i++) {
+ /* Message address equal? */
+ if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) {
+ dev_err(&adap->dev, "Invalid address in msg[%d]\n", i);
+ mutex_unlock(&i2c->lock);
+ pm_runtime_put(i2c->dev);
+ return -EINVAL;
+ }
+ }
+
+ if (intel_mid_i2c_setup(adap, pmsg)) {
+ mutex_unlock(&i2c->lock);
+ pm_runtime_put(i2c->dev);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num; i++) {
+ i2c->msg = pmsg;
+ i2c->status = STATUS_IDLE;
+ /* Read or Write */
+ if (pmsg->flags & I2C_M_RD) {
+ dev_dbg(&adap->dev, "I2C_M_RD\n");
+ err = xfer_read(adap, pmsg->buf, pmsg->len);
+ } else {
+ dev_dbg(&adap->dev, "I2C_M_WR\n");
+ err = xfer_write(adap, pmsg->buf, pmsg->len);
+ }
+ if (err < 0)
+ break;
+ dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i);
+ pmsg++; /* next message */
+ }
+
+ /* Mask interrupts */
+ writel(0x0000, i2c->base + IC_INTR_MASK);
+ /* Clear all interrupts */
+ readl(i2c->base + IC_CLR_INTR);
+
+ i2c->status = STATUS_IDLE;
+ mutex_unlock(&i2c->lock);
+ pm_runtime_put(i2c->dev);
+
+ return err;
+}
+
+static int intel_mid_i2c_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
+ int err;
+
+ if (i2c->status != STATUS_IDLE)
+ return -1;
+
+ intel_mid_i2c_disable(adap);
+
+ err = pci_save_state(pdev);
+ if (err) {
+ dev_err(dev, "pci_save_state failed\n");
+ return err;
+ }
+
+ err = pci_set_power_state(pdev, PCI_D3hot);
+ if (err) {
+ dev_err(dev, "pci_set_power_state failed\n");
+ return err;
+ }
+ i2c->status = STATUS_STANDBY;
+
+ return 0;
+}
+
+static int intel_mid_i2c_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
+ int err;
+
+ if (i2c->status != STATUS_STANDBY)
+ return 0;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "pci_enable_device failed\n");
+ return err;
+ }
+
+ i2c->status = STATUS_IDLE;
+
+ intel_mid_i2c_hwinit(i2c);
+ return err;
+}
+
+static void i2c_isr_read(struct intel_mid_i2c_private *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ int rx_num;
+ u32 len;
+ u8 *buf;
+
+ if (!(msg->flags & I2C_M_RD))
+ return;
+
+ if (i2c->status != STATUS_READ_IN_PROGRESS) {
+ len = msg->len;
+ buf = msg->buf;
+ } else {
+ len = i2c->rx_buf_len;
+ buf = i2c->rx_buf;
+ }
+
+ rx_num = readl(i2c->base + IC_RXFLR);
+
+ for (; len > 0 && rx_num > 0; len--, rx_num--)
+ *buf++ = readl(i2c->base + IC_DATA_CMD);
+
+ if (len > 0) {
+ i2c->status = STATUS_READ_IN_PROGRESS;
+ i2c->rx_buf_len = len;
+ i2c->rx_buf = buf;
+ } else
+ i2c->status = STATUS_READ_SUCCESS;
+
+ return;
+}
+
+static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev)
+{
+ struct intel_mid_i2c_private *i2c = dev;
+ u32 stat = readl(i2c->base + IC_INTR_STAT);
+
+ if (!stat)
+ return IRQ_NONE;
+
+ dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat);
+ stat &= 0x54;
+
+ if (i2c->status != STATUS_WRITE_START &&
+ i2c->status != STATUS_READ_START &&
+ i2c->status != STATUS_READ_IN_PROGRESS)
+ goto err;
+
+ if (stat & TX_ABRT)
+ i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE);
+
+ readl(i2c->base + IC_CLR_INTR);
+
+ if (stat & TX_ABRT) {
+ intel_mid_i2c_abort(i2c);
+ goto exit;
+ }
+
+ if (stat & RX_FULL) {
+ i2c_isr_read(i2c);
+ goto exit;
+ }
+
+ if (stat & TX_EMPTY) {
+ if (readl(i2c->base + IC_STATUS) & 0x4)
+ i2c->status = STATUS_WRITE_SUCCESS;
+ }
+
+exit:
+ if (i2c->status == STATUS_READ_SUCCESS ||
+ i2c->status == STATUS_WRITE_SUCCESS ||
+ i2c->status == STATUS_XFER_ABORT) {
+ /* Clear all interrupts */
+ readl(i2c->base + IC_CLR_INTR);
+ /* Mask interrupts */
+ writel(0, i2c->base + IC_INTR_MASK);
+ complete(&i2c->complete);
+ }
+err:
+ return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm intel_mid_i2c_algorithm = {
+ .master_xfer = intel_mid_i2c_xfer,
+ .functionality = intel_mid_i2c_func,
+};
+
+
+static const struct dev_pm_ops intel_mid_i2c_pm_ops = {
+ .runtime_suspend = intel_mid_i2c_runtime_suspend,
+ .runtime_resume = intel_mid_i2c_runtime_resume,
+};
+
+/**
+ * intel_mid_i2c_probe - I2C controller initialization routine
+ * @dev: pci device
+ * @id: device id
+ *
+ * Return Values:
+ * 0 success
+ * -ENODEV If cannot allocate pci resource
+ * -ENOMEM If the register base remapping failed, or
+ * if kzalloc failed
+ *
+ * Initialization steps:
+ * 1. Request for PCI resource
+ * 2. Remap the start address of PCI resource to register base
+ * 3. Request for device memory region
+ * 4. Fill in the struct members of intel_mid_i2c_private
+ * 5. Call intel_mid_i2c_hwinit() for hardware initialization
+ * 6. Register I2C adapter in i2c-core
+ */
+static int __devinit intel_mid_i2c_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct intel_mid_i2c_private *mrst;
+ unsigned long start, len;
+ int err, busnum;
+ void __iomem *base = NULL;
+
+ dev_dbg(&dev->dev, "Get into probe function for I2C\n");
+ err = pci_enable_device(dev);
+ if (err) {
+ dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n",
+ err);
+ goto exit;
+ }
+
+ /* Determine the address of the I2C area */
+ start = pci_resource_start(dev, 0);
+ len = pci_resource_len(dev, 0);
+ if (!start || len == 0) {
+ dev_err(&dev->dev, "base address not set\n");
+ err = -ENODEV;
+ goto exit;
+ }
+ dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n",
+ PLATFORM, start, len);
+
+ err = pci_request_region(dev, 0, DRIVER_NAME);
+ if (err) {
+ dev_err(&dev->dev, "failed to request I2C region "
+ "0x%lx-0x%lx\n", start,
+ (unsigned long)pci_resource_end(dev, 0));
+ goto exit;
+ }
+
+ base = ioremap_nocache(start, len);
+ if (!base) {
+ dev_err(&dev->dev, "I/O memory remapping failed\n");
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ /* Allocate the per-device data structure, intel_mid_i2c_private */
+ mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL);
+ if (mrst == NULL) {
+ dev_err(&dev->dev, "can't allocate interface\n");
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Initialize struct members */
+ snprintf(mrst->adap.name, sizeof(mrst->adap.name),
+ "Intel MID I2C at %lx", start);
+ mrst->adap.owner = THIS_MODULE;
+ mrst->adap.algo = &intel_mid_i2c_algorithm;
+ mrst->adap.dev.parent = &dev->dev;
+ mrst->dev = &dev->dev;
+ mrst->base = base;
+ mrst->speed = STANDARD;
+ mrst->abort = 0;
+ mrst->rx_buf_len = 0;
+ mrst->status = STATUS_IDLE;
+
+ pci_set_drvdata(dev, mrst);
+ i2c_set_adapdata(&mrst->adap, mrst);
+
+ mrst->adap.nr = busnum = id->driver_data;
+ if (dev->device <= 0x0804)
+ mrst->platform = MOORESTOWN;
+ else
+ mrst->platform = MEDFIELD;
+
+ dev_dbg(&dev->dev, "I2C%d\n", busnum);
+
+ if (ctl_num > busnum) {
+ if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS)
+ dev_warn(&dev->dev, "invalid speed %d ignored.\n",
+ speed_mode[busnum]);
+ else
+ mrst->speed = speed_mode[busnum];
+ }
+
+ /* Initialize i2c controller */
+ err = intel_mid_i2c_hwinit(mrst);
+ if (err < 0) {
+ dev_err(&dev->dev, "I2C interface initialization failed\n");
+ goto fail2;
+ }
+
+ mutex_init(&mrst->lock);
+ init_completion(&mrst->complete);
+
+ /* Clear all interrupts */
+ readl(mrst->base + IC_CLR_INTR);
+ writel(0x0000, mrst->base + IC_INTR_MASK);
+
+ err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED,
+ mrst->adap.name, mrst);
+ if (err) {
+ dev_err(&dev->dev, "Failed to request IRQ for I2C controller: "
+ "%s", mrst->adap.name);
+ goto fail2;
+ }
+
+ /* Adapter registration */
+ err = i2c_add_numbered_adapter(&mrst->adap);
+ if (err) {
+ dev_err(&dev->dev, "Adapter %s registration failed\n",
+ mrst->adap.name);
+ goto fail3;
+ }
+
+ dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n",
+ (mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield",
+ busnum);
+
+ pm_runtime_enable(&dev->dev);
+ return 0;
+
+fail3:
+ free_irq(dev->irq, mrst);
+fail2:
+ pci_set_drvdata(dev, NULL);
+ kfree(mrst);
+fail1:
+ iounmap(base);
+fail0:
+ pci_release_region(dev, 0);
+exit:
+ return err;
+}
+
+static void __devexit intel_mid_i2c_remove(struct pci_dev *dev)
+{
+ struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev);
+ intel_mid_i2c_disable(&mrst->adap);
+ if (i2c_del_adapter(&mrst->adap))
+ dev_err(&dev->dev, "Failed to delete i2c adapter");
+
+ free_irq(dev->irq, mrst);
+ pci_set_drvdata(dev, NULL);
+ iounmap(mrst->base);
+ kfree(mrst);
+ pci_release_region(dev, 0);
+}
+
+static struct pci_device_id intel_mid_i2c_ids[] = {
+ /* Moorestown */
+ { PCI_VDEVICE(INTEL, 0x0802), 0 },
+ { PCI_VDEVICE(INTEL, 0x0803), 1 },
+ { PCI_VDEVICE(INTEL, 0x0804), 2 },
+ /* Medfield */
+ { PCI_VDEVICE(INTEL, 0x0817), 3,},
+ { PCI_VDEVICE(INTEL, 0x0818), 4 },
+ { PCI_VDEVICE(INTEL, 0x0819), 5 },
+ { PCI_VDEVICE(INTEL, 0x082C), 0 },
+ { PCI_VDEVICE(INTEL, 0x082D), 1 },
+ { PCI_VDEVICE(INTEL, 0x082E), 2 },
+ { 0,}
+};
+MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids);
+
+static struct pci_driver intel_mid_i2c_driver = {
+ .name = DRIVER_NAME,
+ .id_table = intel_mid_i2c_ids,
+ .probe = intel_mid_i2c_probe,
+ .remove = __devexit_p(intel_mid_i2c_remove),
+};
+
+static int __init intel_mid_i2c_init(void)
+{
+ return pci_register_driver(&intel_mid_i2c_driver);
+}
+
+static void __exit intel_mid_i2c_exit(void)
+{
+ pci_unregister_driver(&intel_mid_i2c_driver);
+}
+
+module_init(intel_mid_i2c_init);
+module_exit(intel_mid_i2c_exit);
+
+MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
+MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
new file mode 100644
index 00000000..f09c9319
--- /dev/null
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -0,0 +1,545 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx & IXP46x */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ * <Peter dot Milne at D hyphen TACQ dot com>
+ *
+ * With acknowledgements to i2c-algo-ibm_ocp.c by
+ * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
+ *
+ * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
+ *
+ * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
+ *
+ * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
+ *
+ * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005:
+ *
+ * - Use driver model to pass per-chip info instead of hardcoding and #ifdefs
+ * - Use ioremap/__raw_readl/__raw_writel instead of direct dereference
+ * - Make it work with IXP46x chips
+ * - Cleanup function names, coding style, etc
+ *
+ * - writing to slave address causes latchup on iop331.
+ * fix: driver refuses to address self.
+ *
+ * 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, version 2.
+ */
+
+#include <linux/interrupt.h>
+#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/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include "i2c-iop3xx.h"
+
+/* global unit counter */
+static int i2c_id;
+
+static inline unsigned char
+iic_cook_addr(struct i2c_msg *msg)
+{
+ unsigned char addr;
+
+ addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ return addr;
+}
+
+static void
+iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ /* Follows devman 9.3 */
+ __raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET);
+ __raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET);
+ __raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+static void
+iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
+
+ /*
+ * Every time unit enable is asserted, GPOD needs to be cleared
+ * on IOP3XX to avoid data corruption on the bus.
+ */
+#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
+ if (iop3xx_adap->id == 0) {
+ gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+ } else {
+ gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+ }
+#endif
+ /* NB SR bits not same position as CR IE bits :-( */
+ iop3xx_adap->SR_enabled =
+ IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
+ IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY;
+
+ cr |= IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+ IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE;
+
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+static void
+iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+
+ cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE |
+ IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN);
+
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+/*
+ * NB: the handler has to clear the source of the interrupt!
+ * Then it passes the SR flags of interest to BH via adap data
+ */
+static irqreturn_t
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
+ u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
+
+ if ((sr &= iop3xx_adap->SR_enabled)) {
+ __raw_writel(sr, iop3xx_adap->ioaddr + SR_OFFSET);
+ iop3xx_adap->SR_received |= sr;
+ wake_up_interruptible(&iop3xx_adap->waitq);
+ }
+ return IRQ_HANDLED;
+}
+
+/* check all error conditions, clear them , report most important */
+static int
+iop3xx_i2c_error(u32 sr)
+{
+ int rc = 0;
+
+ if ((sr & IOP3XX_ISR_BERRD)) {
+ if ( !rc ) rc = -I2C_ERR_BERR;
+ }
+ if ((sr & IOP3XX_ISR_ALD)) {
+ if ( !rc ) rc = -I2C_ERR_ALD;
+ }
+ return rc;
+}
+
+static inline u32
+iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned long flags;
+ u32 sr;
+
+ spin_lock_irqsave(&iop3xx_adap->lock, flags);
+ sr = iop3xx_adap->SR_received;
+ iop3xx_adap->SR_received = 0;
+ spin_unlock_irqrestore(&iop3xx_adap->lock, flags);
+
+ return sr;
+}
+
+/*
+ * sleep until interrupted, then recover and analyse the SR
+ * saved by handler
+ */
+typedef int (* compare_func)(unsigned test, unsigned mask);
+/* returns 1 on correct comparison */
+
+static int
+iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ unsigned flags, unsigned* status,
+ compare_func compare)
+{
+ unsigned sr = 0;
+ int interrupted;
+ int done;
+ int rc = 0;
+
+ do {
+ interrupted = wait_event_interruptible_timeout (
+ iop3xx_adap->waitq,
+ (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )),
+ 1 * HZ;
+ );
+ if ((rc = iop3xx_i2c_error(sr)) < 0) {
+ *status = sr;
+ return rc;
+ } else if (!interrupted) {
+ *status = sr;
+ return -ETIMEDOUT;
+ }
+ } while(!done);
+
+ *status = sr;
+
+ return 0;
+}
+
+/*
+ * Concrete compare_funcs
+ */
+static int
+all_bits_clear(unsigned test, unsigned mask)
+{
+ return (test & mask) == 0;
+}
+
+static int
+any_bits_set(unsigned test, unsigned mask)
+{
+ return (test & mask) != 0;
+}
+
+static int
+iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_i2c_wait_event(
+ iop3xx_adap,
+ IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
+ status, any_bits_set);
+}
+
+static int
+iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_i2c_wait_event(
+ iop3xx_adap,
+ IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
+ status, any_bits_set);
+}
+
+static int
+iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_i2c_wait_event(
+ iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear);
+}
+
+static int
+iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ struct i2c_msg* msg)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+ int status;
+ int rc;
+
+ /* avoid writing to my slave address (hangs on 80331),
+ * forbidden in Intel developer manual
+ */
+ if (msg->addr == MYSAR) {
+ return -EBUSY;
+ }
+
+ __raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
+
+ cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
+ cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE;
+
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+ rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
+
+ return rc;
+}
+
+static int
+iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
+ int stop)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+ int status;
+ int rc = 0;
+
+ __raw_writel(byte, iop3xx_adap->ioaddr + DBR_OFFSET);
+ cr &= ~IOP3XX_ICR_MSTART;
+ if (stop) {
+ cr |= IOP3XX_ICR_MSTOP;
+ } else {
+ cr &= ~IOP3XX_ICR_MSTOP;
+ }
+ cr |= IOP3XX_ICR_TBYTE;
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+ rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
+
+ return rc;
+}
+
+static int
+iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
+ int stop)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+ int status;
+ int rc = 0;
+
+ cr &= ~IOP3XX_ICR_MSTART;
+
+ if (stop) {
+ cr |= IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK;
+ } else {
+ cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
+ }
+ cr |= IOP3XX_ICR_TBYTE;
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+
+ rc = iop3xx_i2c_wait_rx_done(iop3xx_adap, &status);
+
+ *byte = __raw_readl(iop3xx_adap->ioaddr + DBR_OFFSET);
+
+ return rc;
+}
+
+static int
+iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int ii;
+ int rc = 0;
+
+ for (ii = 0; rc == 0 && ii != count; ++ii)
+ rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
+ return rc;
+}
+
+static int
+iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int ii;
+ int rc = 0;
+
+ for (ii = 0; rc == 0 && ii != count; ++ii)
+ rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
+
+ return rc;
+}
+
+/*
+ * Description: This function implements combined transactions. Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * FROM THE SAME ADDRESS
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+static int
+iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int rc;
+
+ rc = iop3xx_i2c_send_target_addr(iop3xx_adap, pmsg);
+ if (rc < 0) {
+ return rc;
+ }
+
+ if ((pmsg->flags&I2C_M_RD)) {
+ return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len);
+ } else {
+ return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len);
+ }
+}
+
+/*
+ * master_xfer() - main read/write entry
+ */
+static int
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int im = 0;
+ int ret = 0;
+ int status;
+
+ iop3xx_i2c_wait_idle(iop3xx_adap, &status);
+ iop3xx_i2c_reset(iop3xx_adap);
+ iop3xx_i2c_enable(iop3xx_adap);
+
+ for (im = 0; ret == 0 && im != num; im++) {
+ ret = iop3xx_i2c_handle_msg(i2c_adap, &msgs[im]);
+ }
+
+ iop3xx_i2c_transaction_cleanup(iop3xx_adap);
+
+ if(ret)
+ return ret;
+
+ return im;
+}
+
+static u32
+iop3xx_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm iop3xx_i2c_algo = {
+ .master_xfer = iop3xx_i2c_master_xfer,
+ .functionality = iop3xx_i2c_func,
+};
+
+static int
+iop3xx_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *padapter = platform_get_drvdata(pdev);
+ struct i2c_algo_iop3xx_data *adapter_data =
+ (struct i2c_algo_iop3xx_data *)padapter->algo_data;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
+
+ /*
+ * Disable the actual HW unit
+ */
+ cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+ IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE);
+ __raw_writel(cr, adapter_data->ioaddr + CR_OFFSET);
+
+ iounmap(adapter_data->ioaddr);
+ release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
+ kfree(adapter_data);
+ kfree(padapter);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static int
+iop3xx_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret, irq;
+ struct i2c_adapter *new_adapter;
+ struct i2c_algo_iop3xx_data *adapter_data;
+
+ new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!new_adapter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL);
+ if (!adapter_data) {
+ ret = -ENOMEM;
+ goto free_adapter;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto free_both;
+ }
+
+ if (!request_mem_region(res->start, IOP3XX_I2C_IO_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto free_both;
+ }
+
+ /* set the adapter enumeration # */
+ adapter_data->id = i2c_id++;
+
+ adapter_data->ioaddr = ioremap(res->start, IOP3XX_I2C_IO_SIZE);
+ if (!adapter_data->ioaddr) {
+ ret = -ENOMEM;
+ goto release_region;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENXIO;
+ goto unmap;
+ }
+ ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
+ pdev->name, adapter_data);
+
+ if (ret) {
+ ret = -EIO;
+ goto unmap;
+ }
+
+ memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
+ new_adapter->owner = THIS_MODULE;
+ new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ new_adapter->dev.parent = &pdev->dev;
+ new_adapter->nr = pdev->id;
+
+ /*
+ * Default values...should these come in from board code?
+ */
+ new_adapter->timeout = HZ;
+ new_adapter->algo = &iop3xx_i2c_algo;
+
+ init_waitqueue_head(&adapter_data->waitq);
+ spin_lock_init(&adapter_data->lock);
+
+ iop3xx_i2c_reset(adapter_data);
+ iop3xx_i2c_enable(adapter_data);
+
+ platform_set_drvdata(pdev, new_adapter);
+ new_adapter->algo_data = adapter_data;
+
+ i2c_add_numbered_adapter(new_adapter);
+
+ return 0;
+
+unmap:
+ iounmap(adapter_data->ioaddr);
+
+release_region:
+ release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
+
+free_both:
+ kfree(adapter_data);
+
+free_adapter:
+ kfree(new_adapter);
+
+out:
+ return ret;
+}
+
+
+static struct platform_driver iop3xx_i2c_driver = {
+ .probe = iop3xx_i2c_probe,
+ .remove = iop3xx_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "IOP3xx-I2C",
+ },
+};
+
+static int __init
+i2c_iop3xx_init (void)
+{
+ return platform_driver_register(&iop3xx_i2c_driver);
+}
+
+static void __exit
+i2c_iop3xx_exit (void)
+{
+ platform_driver_unregister(&iop3xx_i2c_driver);
+ return;
+}
+
+module_init (i2c_iop3xx_init);
+module_exit (i2c_iop3xx_exit);
+
+MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
+MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IOP3xx-I2C");
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
new file mode 100644
index 00000000..097e2709
--- /dev/null
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -0,0 +1,107 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ * <Peter dot Milne at D hyphen TACQ dot com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+
+#ifndef I2C_IOP3XX_H
+#define I2C_IOP3XX_H 1
+
+/*
+ * iop321 hardware bit definitions
+ */
+#define IOP3XX_ICR_FAST_MODE 0x8000 /* 1=400kBps, 0=100kBps */
+#define IOP3XX_ICR_UNIT_RESET 0x4000 /* 1=RESET */
+#define IOP3XX_ICR_SAD_IE 0x2000 /* 1=Slave Detect Interrupt Enable */
+#define IOP3XX_ICR_ALD_IE 0x1000 /* 1=Arb Loss Detect Interrupt Enable */
+#define IOP3XX_ICR_SSD_IE 0x0800 /* 1=Slave STOP Detect Interrupt Enable */
+#define IOP3XX_ICR_BERR_IE 0x0400 /* 1=Bus Error Interrupt Enable */
+#define IOP3XX_ICR_RXFULL_IE 0x0200 /* 1=Receive Full Interrupt Enable */
+#define IOP3XX_ICR_TXEMPTY_IE 0x0100 /* 1=Transmit Empty Interrupt Enable */
+#define IOP3XX_ICR_GCD 0x0080 /* 1=General Call Disable */
+/*
+ * IOP3XX_ICR_GCD: 1 disables response as slave. "This bit must be set
+ * when sending a master mode general call message from the I2C unit"
+ */
+#define IOP3XX_ICR_UE 0x0040 /* 1=Unit Enable */
+/*
+ * "NOTE: To avoid I2C bus integrity problems,
+ * the user needs to ensure that the GPIO Output Data Register -
+ * GPOD bits associated with an I2C port are cleared prior to setting
+ * the enable bit for that I2C serial port.
+ * The user prepares to enable I2C port 0 and
+ * I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively.
+ */
+#define IOP3XX_ICR_SCLEN 0x0020 /* 1=SCL enable for master mode */
+#define IOP3XX_ICR_MABORT 0x0010 /* 1=Send a STOP with no data
+ * NB TBYTE must be clear */
+#define IOP3XX_ICR_TBYTE 0x0008 /* 1=Send/Receive a byte. i2c clears */
+#define IOP3XX_ICR_NACK 0x0004 /* 1=reply with NACK */
+#define IOP3XX_ICR_MSTOP 0x0002 /* 1=send a STOP after next data byte */
+#define IOP3XX_ICR_MSTART 0x0001 /* 1=initiate a START */
+
+
+#define IOP3XX_ISR_BERRD 0x0400 /* 1=BUS ERROR Detected */
+#define IOP3XX_ISR_SAD 0x0200 /* 1=Slave ADdress Detected */
+#define IOP3XX_ISR_GCAD 0x0100 /* 1=General Call Address Detected */
+#define IOP3XX_ISR_RXFULL 0x0080 /* 1=Receive Full */
+#define IOP3XX_ISR_TXEMPTY 0x0040 /* 1=Transmit Empty */
+#define IOP3XX_ISR_ALD 0x0020 /* 1=Arbitration Loss Detected */
+#define IOP3XX_ISR_SSD 0x0010 /* 1=Slave STOP Detected */
+#define IOP3XX_ISR_BBUSY 0x0008 /* 1=Bus BUSY */
+#define IOP3XX_ISR_UNITBUSY 0x0004 /* 1=Unit Busy */
+#define IOP3XX_ISR_NACK 0x0002 /* 1=Unit Rx or Tx a NACK */
+#define IOP3XX_ISR_RXREAD 0x0001 /* 1=READ 0=WRITE (R/W bit of slave addr */
+
+#define IOP3XX_ISR_CLEARBITS 0x07f0
+
+#define IOP3XX_ISAR_SAMASK 0x007f
+
+#define IOP3XX_IDBR_MASK 0x00ff
+
+#define IOP3XX_IBMR_SCL 0x0002
+#define IOP3XX_IBMR_SDA 0x0001
+
+#define IOP3XX_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
+#define IOP3XX_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
+
+#define MYSAR 0 /* default slave address */
+
+#define I2C_ERR 321
+#define I2C_ERR_BERR (I2C_ERR+0)
+#define I2C_ERR_ALD (I2C_ERR+1)
+
+
+#define CR_OFFSET 0
+#define SR_OFFSET 0x4
+#define SAR_OFFSET 0x8
+#define DBR_OFFSET 0xc
+#define CCR_OFFSET 0x10
+#define BMR_OFFSET 0x14
+
+#define IOP3XX_I2C_IO_SIZE 0x18
+
+struct i2c_algo_iop3xx_data {
+ void __iomem *ioaddr;
+ wait_queue_head_t waitq;
+ spinlock_t lock;
+ u32 SR_enabled, SR_received;
+ int id;
+};
+
+#endif /* I2C_IOP3XX_H */
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
new file mode 100644
index 00000000..0682f8f2
--- /dev/null
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -0,0 +1,325 @@
+/*
+ i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus
+ - Based on i2c-piix4.c
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+ - Intel SCH support
+ Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.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.
+
+ 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.
+*/
+
+/*
+ Supports:
+ Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L)
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+
+/* SCH SMBus address offsets */
+#define SMBHSTCNT (0 + sch_smba)
+#define SMBHSTSTS (1 + sch_smba)
+#define SMBHSTADD (4 + sch_smba) /* TSA */
+#define SMBHSTCMD (5 + sch_smba)
+#define SMBHSTDAT0 (6 + sch_smba)
+#define SMBHSTDAT1 (7 + sch_smba)
+#define SMBBLKDAT (0x20 + sch_smba)
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* I2C constants */
+#define SCH_QUICK 0x00
+#define SCH_BYTE 0x01
+#define SCH_BYTE_DATA 0x02
+#define SCH_WORD_DATA 0x03
+#define SCH_BLOCK_DATA 0x05
+
+static unsigned short sch_smba;
+static struct i2c_adapter sch_adapter;
+
+/*
+ * Start the i2c transaction -- the i2c_access will prepare the transaction
+ * and this function will execute it.
+ * return 0 for success and others for failure.
+ */
+static int sch_transaction(void)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
+ inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
+ inb(SMBHSTDAT1));
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ temp = inb(SMBHSTSTS) & 0x0f;
+ if (temp) {
+ /* Can not be busy since we checked it in sch_access */
+ if (temp & 0x01) {
+ dev_dbg(&sch_adapter.dev, "Completion (%02x). "
+ "Clear...\n", temp);
+ }
+ if (temp & 0x06) {
+ dev_dbg(&sch_adapter.dev, "SMBus error (%02x). "
+ "Resetting...\n", temp);
+ }
+ outb(temp, SMBHSTSTS);
+ temp = inb(SMBHSTSTS) & 0x0f;
+ if (temp) {
+ dev_err(&sch_adapter.dev,
+ "SMBus is not ready: (%02x)\n", temp);
+ return -EAGAIN;
+ }
+ }
+
+ /* start the transaction by setting bit 4 */
+ outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
+
+ do {
+ msleep(1);
+ temp = inb(SMBHSTSTS) & 0x0f;
+ } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+ if (temp & 0x04) {
+ result = -EIO;
+ dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
+ "locked until next hard reset. (sorry!)\n");
+ /* Clock stops and slave is stuck in mid-transmission */
+ } else if (temp & 0x02) {
+ result = -EIO;
+ dev_err(&sch_adapter.dev, "Error: no response!\n");
+ } else if (temp & 0x01) {
+ dev_dbg(&sch_adapter.dev, "Post complete!\n");
+ outb(temp, SMBHSTSTS);
+ temp = inb(SMBHSTSTS) & 0x07;
+ if (temp & 0x06) {
+ /* Completion clear failed */
+ dev_dbg(&sch_adapter.dev, "Failed reset at end of "
+ "transaction (%02x), Bus error!\n", temp);
+ }
+ } else {
+ result = -ENXIO;
+ dev_dbg(&sch_adapter.dev, "No such address.\n");
+ }
+ dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
+ inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
+ inb(SMBHSTDAT1));
+ return result;
+}
+
+/*
+ * This is the main access entry for i2c-sch access
+ * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write
+ * (0 for read and 1 for write), size is i2c transaction type and data is the
+ * union of transaction for data to be transferred or data read from bus.
+ * return 0 for success and others for failure.
+ */
+static s32 sch_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ int i, len, temp, rc;
+
+ /* Make sure the SMBus host is not busy */
+ temp = inb(SMBHSTSTS) & 0x0f;
+ if (temp & 0x08) {
+ dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp);
+ return -EAGAIN;
+ }
+ dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size,
+ (read_write)?"READ":"WRITE");
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ size = SCH_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb(command, SMBHSTCMD);
+ size = SCH_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ outb(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb(data->byte, SMBHSTDAT0);
+ size = SCH_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ outb(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb(data->word & 0xff, SMBHSTDAT0);
+ outb((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = SCH_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ outb(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ outb(len, SMBHSTDAT0);
+ for (i = 1; i <= len; i++)
+ outb(data->block[i], SMBBLKDAT+i-1);
+ }
+ size = SCH_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+ dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
+ outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT);
+
+ rc = sch_transaction();
+ if (rc) /* Error in transaction */
+ return rc;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == SCH_QUICK))
+ return 0;
+
+ switch (size) {
+ case SCH_BYTE:
+ case SCH_BYTE_DATA:
+ data->byte = inb(SMBHSTDAT0);
+ break;
+ case SCH_WORD_DATA:
+ data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8);
+ break;
+ case SCH_BLOCK_DATA:
+ data->block[0] = inb(SMBHSTDAT0);
+ if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb(SMBBLKDAT+i-1);
+ break;
+ }
+ return 0;
+}
+
+static u32 sch_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sch_access,
+ .functionality = sch_func,
+};
+
+static struct i2c_adapter sch_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static int __devinit smbus_sch_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ int retval;
+
+ res = platform_get_resource(dev, IORESOURCE_IO, 0);
+ if (!res)
+ return -EBUSY;
+
+ 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 */
+ sch_adapter.dev.parent = &dev->dev;
+
+ snprintf(sch_adapter.name, sizeof(sch_adapter.name),
+ "SMBus SCH adapter at %04x", sch_smba);
+
+ retval = i2c_add_adapter(&sch_adapter);
+ if (retval) {
+ dev_err(&dev->dev, "Couldn't register adapter!\n");
+ release_region(res->start, resource_size(res));
+ sch_smba = 0;
+ }
+
+ return retval;
+}
+
+static int __devexit smbus_sch_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ if (sch_smba) {
+ i2c_del_adapter(&sch_adapter);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, resource_size(res));
+ sch_smba = 0;
+ }
+
+ return 0;
+}
+
+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 platform_driver_register(&smbus_sch_driver);
+}
+
+static void __exit i2c_sch_exit(void)
+{
+ platform_driver_unregister(&smbus_sch_driver);
+}
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
+MODULE_DESCRIPTION("Intel SCH SMBus driver");
+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
new file mode 100644
index 00000000..5d8aed5e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -0,0 +1,168 @@
+/*
+ * drivers/i2c/busses/i2c-ixp2000.c
+ *
+ * I2C adapter for IXP2000 systems using GPIOs for I2C bus
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ * Based on IXDP2400 code by: Naeem M. Afzal <naeem.m.afzal@intel.com>
+ * Made generic by: Jeff Daly <jeffrey.daly@intel.com>
+ *
+ * Copyright (c) 2003-2004 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * From Jeff Daly:
+ *
+ * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any
+ * IXP2000 platform if it uses the HW GPIO in the same manner. Basically,
+ * SDA and SCL GPIOs have external pullups. Setting the respective GPIO to
+ * an input will make the signal a '1' via the pullup. Setting them to
+ * outputs will pull them down.
+ *
+ * The GPIOs are open drain signals and are used as configuration strap inputs
+ * during power-up so there's generally a buffer on the board that needs to be
+ * 'enabled' to drive the GPIOs.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#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>
+
+static inline int ixp2000_scl_pin(void *data)
+{
+ return ((struct ixp2000_i2c_pins*)data)->scl_pin;
+}
+
+static inline int ixp2000_sda_pin(void *data)
+{
+ return ((struct ixp2000_i2c_pins*)data)->sda_pin;
+}
+
+
+static void ixp2000_bit_setscl(void *data, int val)
+{
+ int i = 5000;
+
+ if (val) {
+ gpio_line_config(ixp2000_scl_pin(data), GPIO_IN);
+ while(!gpio_line_get(ixp2000_scl_pin(data)) && i--);
+ } else {
+ gpio_line_config(ixp2000_scl_pin(data), GPIO_OUT);
+ }
+}
+
+static void ixp2000_bit_setsda(void *data, int val)
+{
+ if (val) {
+ gpio_line_config(ixp2000_sda_pin(data), GPIO_IN);
+ } else {
+ gpio_line_config(ixp2000_sda_pin(data), GPIO_OUT);
+ }
+}
+
+static int ixp2000_bit_getscl(void *data)
+{
+ return gpio_line_get(ixp2000_scl_pin(data));
+}
+
+static int ixp2000_bit_getsda(void *data)
+{
+ return gpio_line_get(ixp2000_sda_pin(data));
+}
+
+struct ixp2000_i2c_data {
+ struct ixp2000_i2c_pins *gpio_pins;
+ struct i2c_adapter adapter;
+ struct i2c_algo_bit_data algo_data;
+};
+
+static int ixp2000_i2c_remove(struct platform_device *plat_dev)
+{
+ struct ixp2000_i2c_data *drv_data = platform_get_drvdata(plat_dev);
+
+ platform_set_drvdata(plat_dev, NULL);
+
+ i2c_del_adapter(&drv_data->adapter);
+
+ kfree(drv_data);
+
+ return 0;
+}
+
+static int ixp2000_i2c_probe(struct platform_device *plat_dev)
+{
+ int err;
+ struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data;
+ struct ixp2000_i2c_data *drv_data =
+ kzalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL);
+
+ if (!drv_data)
+ return -ENOMEM;
+ drv_data->gpio_pins = gpio;
+
+ drv_data->algo_data.data = gpio;
+ drv_data->algo_data.setsda = ixp2000_bit_setsda;
+ drv_data->algo_data.setscl = ixp2000_bit_setscl;
+ drv_data->algo_data.getsda = ixp2000_bit_getsda;
+ drv_data->algo_data.getscl = ixp2000_bit_getscl;
+ drv_data->algo_data.udelay = 6;
+ drv_data->algo_data.timeout = HZ;
+
+ strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
+ sizeof(drv_data->adapter.name));
+ drv_data->adapter.algo_data = &drv_data->algo_data,
+
+ drv_data->adapter.dev.parent = &plat_dev->dev;
+
+ gpio_line_config(gpio->sda_pin, GPIO_IN);
+ gpio_line_config(gpio->scl_pin, GPIO_IN);
+ gpio_line_set(gpio->scl_pin, 0);
+ gpio_line_set(gpio->sda_pin, 0);
+
+ if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) {
+ dev_err(&plat_dev->dev, "Could not install, error %d\n", err);
+ kfree(drv_data);
+ return err;
+ }
+
+ platform_set_drvdata(plat_dev, drv_data);
+
+ return 0;
+}
+
+static struct platform_driver ixp2000_i2c_driver = {
+ .probe = ixp2000_i2c_probe,
+ .remove = ixp2000_i2c_remove,
+ .driver = {
+ .name = "IXP2000-I2C",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ixp2000_i2c_init(void)
+{
+ return platform_driver_register(&ixp2000_i2c_driver);
+}
+
+static void __exit ixp2000_i2c_exit(void)
+{
+ platform_driver_unregister(&ixp2000_i2c_driver);
+}
+
+module_init(ixp2000_i2c_init);
+module_exit(ixp2000_i2c_exit);
+
+MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IXP2000-I2C");
+
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
new file mode 100644
index 00000000..107397a6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -0,0 +1,734 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx).
+ *
+ * Release 0.8
+ *
+ * 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/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>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/mpc52xx.h>
+#include <sysdev/fsl_soc.h>
+
+#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
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN 0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX 0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+
+#define CSR_MCF 0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB 0x20
+#define CSR_MAL 0x10
+#define CSR_SRW 0x04
+#define CSR_MIF 0x02
+#define CSR_RXAK 0x01
+
+struct mpc_i2c {
+ struct device *dev;
+ void __iomem *base;
+ u32 interrupt;
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ int irq;
+ u32 real_clk;
+};
+
+struct mpc_i2c_divider {
+ u16 divider;
+ u16 fdr; /* including dfsrr */
+};
+
+struct mpc_i2c_data {
+ void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler);
+ u32 prescaler;
+};
+
+static inline void writeccr(struct mpc_i2c *i2c, u32 x)
+{
+ writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+{
+ struct mpc_i2c *i2c = dev_id;
+ if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+ /* Read again to allow register to stabilise */
+ i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ wake_up(&i2c->queue);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the 9 pulses, so it's all OK.
+ */
+static void mpc_i2c_fixup(struct mpc_i2c *i2c)
+{
+ int k;
+ u32 delay_val = 1000000 / i2c->real_clk + 1;
+
+ if (delay_val < 2)
+ delay_val = 2;
+
+ for (k = 9; k; k--) {
+ writeccr(i2c, 0);
+ writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+ udelay(delay_val);
+ writeccr(i2c, CCR_MEN);
+ udelay(delay_val << 1);
+ }
+}
+
+static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
+{
+ unsigned long orig_jiffies = jiffies;
+ u32 x;
+ int result = 0;
+
+ if (!i2c->irq) {
+ while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+ schedule();
+ if (time_after(jiffies, orig_jiffies + timeout)) {
+ dev_dbg(i2c->dev, "timeout\n");
+ writeccr(i2c, 0);
+ result = -EIO;
+ break;
+ }
+ }
+ x = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ } else {
+ /* Interrupt mode */
+ result = wait_event_timeout(i2c->queue,
+ (i2c->interrupt & CSR_MIF), timeout);
+
+ if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+ dev_dbg(i2c->dev, "wait timeout\n");
+ writeccr(i2c, 0);
+ result = -ETIMEDOUT;
+ }
+
+ x = i2c->interrupt;
+ i2c->interrupt = 0;
+ }
+
+ if (result < 0)
+ return result;
+
+ if (!(x & CSR_MCF)) {
+ dev_dbg(i2c->dev, "unfinished\n");
+ return -EIO;
+ }
+
+ if (x & CSR_MAL) {
+ dev_dbg(i2c->dev, "MAL\n");
+ return -EIO;
+ }
+
+ if (writing && (x & CSR_RXAK)) {
+ dev_dbg(i2c->dev, "No RXAK\n");
+ /* generate stop */
+ writeccr(i2c, CCR_MEN);
+ return -EIO;
+ }
+ return 0;
+}
+
+#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},
+ {52, 0x63}, {56, 0x29}, {60, 0x41}, {64, 0x2a},
+ {68, 0x07}, {72, 0x2b}, {80, 0x2c}, {88, 0x09},
+ {96, 0x2d}, {104, 0x0a}, {112, 0x2e}, {120, 0x81},
+ {128, 0x2f}, {136, 0x47}, {144, 0x0c}, {160, 0x30},
+ {176, 0x49}, {192, 0x31}, {208, 0x4a}, {224, 0x32},
+ {240, 0x0f}, {256, 0x33}, {272, 0x87}, {288, 0x10},
+ {320, 0x34}, {352, 0x89}, {384, 0x35}, {416, 0x8a},
+ {448, 0x36}, {480, 0x13}, {512, 0x37}, {576, 0x14},
+ {640, 0x38}, {768, 0x39}, {896, 0x3a}, {960, 0x17},
+ {1024, 0x3b}, {1152, 0x18}, {1280, 0x3c}, {1536, 0x3d},
+ {1792, 0x3e}, {1920, 0x1b}, {2048, 0x3f}, {2304, 0x1c},
+ {2560, 0x1d}, {3072, 0x1e}, {3584, 0x7e}, {3840, 0x1f},
+ {4096, 0x7f}, {4608, 0x5c}, {5120, 0x5d}, {6144, 0x5e},
+ {7168, 0xbe}, {7680, 0x5f}, {8192, 0xbf}, {9216, 0x9c},
+ {10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
+};
+
+static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+ int prescaler, u32 *real_clk)
+{
+ const struct mpc_i2c_divider *div = NULL;
+ unsigned int pvr = mfspr(SPRN_PVR);
+ u32 divider;
+ int i;
+
+ if (clock == MPC_I2C_CLOCK_LEGACY) {
+ /* see below - default fdr = 0x3f -> div = 2048 */
+ *real_clk = mpc5xxx_get_bus_frequency(node) / 2048;
+ return -EINVAL;
+ }
+
+ /* Determine divider value */
+ divider = mpc5xxx_get_bus_frequency(node) / clock;
+
+ /*
+ * We want to choose an FDR/DFSR that generates an I2C bus speed that
+ * is equal to or lower than the requested speed.
+ */
+ for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_52xx); i++) {
+ div = &mpc_i2c_dividers_52xx[i];
+ /* Old MPC5200 rev A CPUs do not support the high bits */
+ if (div->fdr & 0xc0 && pvr == 0x80822011)
+ continue;
+ if (div->divider >= divider)
+ break;
+ }
+
+ *real_clk = mpc5xxx_get_bus_frequency(node) / div->divider;
+ return (int)div->fdr;
+}
+
+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, &i2c->real_clk);
+ fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
+
+ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+
+ if (ret >= 0)
+ dev_info(i2c->dev, "clock %u Hz (fdr=%d)\n", i2c->real_clk,
+ fdr);
+}
+#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_MPC512x */
+
+#ifdef CONFIG_FSL_SOC
+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},
+ {544, 0x0b03}, {576, 0x0104}, {608, 0x1603}, {640, 0x0105},
+ {672, 0x2003}, {704, 0x0b05}, {736, 0x2b03}, {768, 0x0106},
+ {800, 0x3603}, {832, 0x0b06}, {896, 0x012a}, {960, 0x0107},
+ {1024, 0x012b}, {1088, 0x1607}, {1152, 0x0108}, {1216, 0x2b07},
+ {1280, 0x0109}, {1408, 0x1609}, {1536, 0x010a}, {1664, 0x160a},
+ {1792, 0x012e}, {1920, 0x010b}, {2048, 0x012f}, {2176, 0x2b0b},
+ {2304, 0x010c}, {2560, 0x010d}, {2816, 0x2b0d}, {3072, 0x010e},
+ {3328, 0x2b0e}, {3584, 0x0132}, {3840, 0x010f}, {4096, 0x0133},
+ {4608, 0x0110}, {5120, 0x0111}, {6144, 0x0112}, {7168, 0x0136},
+ {7680, 0x0113}, {8192, 0x0137}, {9216, 0x0114}, {10240, 0x0115},
+ {12288, 0x0116}, {14336, 0x013a}, {15360, 0x0117}, {16384, 0x013b},
+ {18432, 0x0118}, {20480, 0x0119}, {24576, 0x011a}, {28672, 0x013e},
+ {30720, 0x011b}, {32768, 0x013f}, {36864, 0x011c}, {40960, 0x011d},
+ {49152, 0x011e}, {61440, 0x011f}
+};
+
+static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
+{
+ struct device_node *node = NULL;
+ u32 __iomem *reg;
+ u32 val = 0;
+
+ node = of_find_node_by_name(NULL, "global-utilities");
+ if (node) {
+ const u32 *prop = of_get_property(node, "reg", NULL);
+ if (prop) {
+ /*
+ * Map and check POR Device Status Register 2
+ * (PORDEVSR2) at 0xE0014
+ */
+ reg = ioremap(get_immrbase() + *prop + 0x14, 0x4);
+ if (!reg)
+ printk(KERN_ERR
+ "Error: couldn't map PORDEVSR2\n");
+ else
+ val = in_be32(reg) & 0x00000080; /* sec-cfg */
+ iounmap(reg);
+ }
+ }
+ if (node)
+ of_node_put(node);
+
+ return val;
+}
+
+static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+ u32 prescaler, u32 *real_clk)
+{
+ const struct mpc_i2c_divider *div = NULL;
+ u32 divider;
+ int i;
+
+ if (clock == MPC_I2C_CLOCK_LEGACY) {
+ /* see below - default fdr = 0x1031 -> div = 16 * 3072 */
+ *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072);
+ return -EINVAL;
+ }
+
+ /* Determine proper divider value */
+ if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
+ prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
+ if (!prescaler)
+ prescaler = 1;
+
+ divider = fsl_get_sys_freq() / clock / prescaler;
+
+ pr_debug("I2C: src_clock=%d clock=%d divider=%d\n",
+ fsl_get_sys_freq(), clock, divider);
+
+ /*
+ * We want to choose an FDR/DFSR that generates an I2C bus speed that
+ * is equal to or lower than the requested speed.
+ */
+ for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_8xxx); i++) {
+ div = &mpc_i2c_dividers_8xxx[i];
+ if (div->divider >= divider)
+ break;
+ }
+
+ *real_clk = fsl_get_sys_freq() / prescaler / div->divider;
+ return div ? (int)div->fdr : -EINVAL;
+}
+
+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, &i2c->real_clk);
+ fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
+
+ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+ writeb((fdr >> 8) & 0xff, i2c->base + MPC_I2C_DFSRR);
+
+ if (ret >= 0)
+ dev_info(i2c->dev, "clock %d Hz (dfsrr=%d fdr=%d)\n",
+ i2c->real_clk, fdr >> 8, fdr & 0xff);
+}
+
+#else /* !CONFIG_FSL_SOC */
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_FSL_SOC */
+
+static void mpc_i2c_start(struct mpc_i2c *i2c)
+{
+ /* Clear arbitration */
+ writeb(0, i2c->base + MPC_I2C_SR);
+ /* Start with MEN */
+ writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_stop(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_write(struct mpc_i2c *i2c, int target,
+ const u8 *data, int length, int restart)
+{
+ int i, result;
+ unsigned timeout = i2c->adap.timeout;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Start as master */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target byte */
+ writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+ result = i2c_wait(i2c, timeout, 1);
+ if (result < 0)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ /* Write data byte */
+ writeb(data[i], i2c->base + MPC_I2C_DR);
+
+ result = i2c_wait(i2c, timeout, 1);
+ if (result < 0)
+ return result;
+ }
+
+ return 0;
+}
+
+static int mpc_read(struct mpc_i2c *i2c, int target,
+ u8 *data, int length, int restart)
+{
+ unsigned timeout = i2c->adap.timeout;
+ int i, result;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Switch to read - restart */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target address byte - this time with the read flag set */
+ writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+ result = i2c_wait(i2c, timeout, 1);
+ if (result < 0)
+ return result;
+
+ if (length) {
+ if (length == 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ else
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+ /* Dummy read */
+ readb(i2c->base + MPC_I2C_DR);
+ }
+
+ for (i = 0; i < length; i++) {
+ result = i2c_wait(i2c, timeout, 0);
+ if (result < 0)
+ return result;
+
+ /* Generate txack on next to last byte */
+ if (i == length - 2)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ /* Do not generate stop on last byte */
+ if (i == length - 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX);
+ data[i] = readb(i2c->base + MPC_I2C_DR);
+ }
+
+ return length;
+}
+
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int i;
+ int ret = 0;
+ unsigned long orig_jiffies = jiffies;
+ struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+ mpc_i2c_start(i2c);
+
+ /* Allow bus up to 1s to become not busy */
+ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+ if (signal_pending(current)) {
+ dev_dbg(i2c->dev, "Interrupted\n");
+ writeccr(i2c, 0);
+ return -EINTR;
+ }
+ if (time_after(jiffies, orig_jiffies + HZ)) {
+ u8 status = readb(i2c->base + MPC_I2C_SR);
+
+ dev_dbg(i2c->dev, "timeout\n");
+ if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+ writeb(status & ~CSR_MAL,
+ i2c->base + MPC_I2C_SR);
+ mpc_i2c_fixup(i2c);
+ }
+ return -EIO;
+ }
+ schedule();
+ }
+
+ for (i = 0; ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ dev_dbg(i2c->dev,
+ "Doing %s %d bytes to 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 =
+ mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ else
+ ret =
+ mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ }
+ mpc_i2c_stop(i2c);
+ return (ret < 0) ? ret : num;
+}
+
+static u32 mpc_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mpc_algo = {
+ .master_xfer = mpc_xfer,
+ .functionality = mpc_functionality,
+};
+
+static struct i2c_adapter mpc_ops = {
+ .owner = THIS_MODULE,
+ .name = "MPC adapter",
+ .algo = &mpc_algo,
+ .timeout = HZ,
+};
+
+static const struct of_device_id mpc_i2c_of_match[];
+static int __devinit fsl_i2c_probe(struct platform_device *op)
+{
+ const struct of_device_id *match;
+ struct mpc_i2c *i2c;
+ const u32 *prop;
+ u32 clock = MPC_I2C_CLOCK_LEGACY;
+ int result = 0;
+ int plen;
+
+ match = of_match_device(mpc_i2c_of_match, &op->dev);
+ if (!match)
+ return -EINVAL;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->dev = &op->dev; /* for debug and error output */
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->base = of_iomap(op->dev.of_node, 0);
+ if (!i2c->base) {
+ dev_err(i2c->dev, "failed to map controller\n");
+ result = -ENOMEM;
+ goto fail_map;
+ }
+
+ i2c->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ if (i2c->irq) { /* no i2c->irq implies polling */
+ result = request_irq(i2c->irq, mpc_i2c_isr,
+ IRQF_SHARED, "i2c-mpc", i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto fail_request;
+ }
+ }
+
+ if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
+ clock = MPC_I2C_CLOCK_PRESERVE;
+ } else {
+ prop = of_get_property(op->dev.of_node, "clock-frequency",
+ &plen);
+ if (prop && plen == sizeof(u32))
+ clock = *prop;
+ }
+
+ if (match->data) {
+ struct mpc_i2c_data *data = match->data;
+ data->setup(op->dev.of_node, i2c, clock, data->prescaler);
+ } else {
+ /* Backwards compatibility */
+ if (of_get_property(op->dev.of_node, "dfsrr", NULL))
+ mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0);
+ }
+
+ prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen);
+ if (prop && plen == sizeof(u32)) {
+ mpc_ops.timeout = *prop * HZ / 1000000;
+ if (mpc_ops.timeout < 5)
+ mpc_ops.timeout = 5;
+ }
+ dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
+
+ dev_set_drvdata(&op->dev, i2c);
+
+ i2c->adap = mpc_ops;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &op->dev;
+ i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
+
+ result = i2c_add_adapter(&i2c->adap);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to add adapter\n");
+ goto fail_add;
+ }
+ of_i2c_register_devices(&i2c->adap);
+
+ return result;
+
+ fail_add:
+ dev_set_drvdata(&op->dev, NULL);
+ free_irq(i2c->irq, i2c);
+ fail_request:
+ irq_dispose_mapping(i2c->irq);
+ iounmap(i2c->base);
+ fail_map:
+ kfree(i2c);
+ return result;
+};
+
+static int __devexit fsl_i2c_remove(struct platform_device *op)
+{
+ struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
+
+ i2c_del_adapter(&i2c->adap);
+ dev_set_drvdata(&op->dev, NULL);
+
+ if (i2c->irq)
+ free_irq(i2c->irq, i2c);
+
+ irq_dispose_mapping(i2c->irq);
+ iounmap(i2c->base);
+ kfree(i2c);
+ 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 = &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 platform_driver mpc_i2c_driver = {
+ .probe = fsl_i2c_probe,
+ .remove = __devexit_p(fsl_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .of_match_table = mpc_i2c_of_match,
+ },
+};
+
+static int __init fsl_i2c_init(void)
+{
+ return platform_driver_register(&mpc_i2c_driver);
+}
+
+static void __exit fsl_i2c_exit(void)
+{
+ platform_driver_unregister(&mpc_i2c_driver);
+}
+
+module_init(fsl_i2c_init);
+module_exit(fsl_i2c_exit);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
+ "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
new file mode 100644
index 00000000..a9941c65
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -0,0 +1,631 @@
+/*
+ * Driver for the i2c controller on the Marvell line of host bridges
+ * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mv643xx_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+/* Register defines */
+#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00
+#define MV64XXX_I2C_REG_DATA 0x04
+#define MV64XXX_I2C_REG_CONTROL 0x08
+#define MV64XXX_I2C_REG_STATUS 0x0c
+#define MV64XXX_I2C_REG_BAUD 0x0c
+#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10
+#define MV64XXX_I2C_REG_SOFT_RESET 0x1c
+
+#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004
+#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008
+#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010
+#define MV64XXX_I2C_REG_CONTROL_START 0x00000020
+#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040
+#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080
+
+/* Ctlr status values */
+#define MV64XXX_I2C_STATUS_BUS_ERR 0x00
+#define MV64XXX_I2C_STATUS_MAST_START 0x08
+#define MV64XXX_I2C_STATUS_MAST_REPEAT_START 0x10
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK 0x18
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20
+#define MV64XXX_I2C_STATUS_MAST_WR_ACK 0x28
+#define MV64XXX_I2C_STATUS_MAST_WR_NO_ACK 0x30
+#define MV64XXX_I2C_STATUS_MAST_LOST_ARB 0x38
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK 0x40
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48
+#define MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK 0x50
+#define MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8
+#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8
+
+/* Driver states */
+enum {
+ MV64XXX_I2C_STATE_INVALID,
+ MV64XXX_I2C_STATE_IDLE,
+ MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
+ MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA,
+};
+
+/* Driver actions */
+enum {
+ MV64XXX_I2C_ACTION_INVALID,
+ MV64XXX_I2C_ACTION_CONTINUE,
+ MV64XXX_I2C_ACTION_SEND_START,
+ MV64XXX_I2C_ACTION_SEND_RESTART,
+ MV64XXX_I2C_ACTION_SEND_ADDR_1,
+ MV64XXX_I2C_ACTION_SEND_ADDR_2,
+ MV64XXX_I2C_ACTION_SEND_DATA,
+ MV64XXX_I2C_ACTION_RCV_DATA,
+ MV64XXX_I2C_ACTION_RCV_DATA_STOP,
+ MV64XXX_I2C_ACTION_SEND_STOP,
+};
+
+struct mv64xxx_i2c_data {
+ int irq;
+ u32 state;
+ u32 action;
+ u32 aborting;
+ u32 cntl_bits;
+ void __iomem *reg_base;
+ u32 reg_base_p;
+ u32 reg_size;
+ u32 addr1;
+ u32 addr2;
+ u32 bytes_left;
+ u32 byte_posn;
+ u32 send_stop;
+ u32 block;
+ int rc;
+ u32 freq_m;
+ u32 freq_n;
+ wait_queue_head_t waitq;
+ spinlock_t lock;
+ struct i2c_msg *msg;
+ struct i2c_adapter adapter;
+};
+
+/*
+ *****************************************************************************
+ *
+ * Finite State Machine & Interrupt Routines
+ *
+ *****************************************************************************
+ */
+
+/* Reset hardware and initialize FSM */
+static void
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
+ writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
+ drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+ writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
+static void
+mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
+{
+ /*
+ * If state is idle, then this is likely the remnants of an old
+ * operation that driver has given up on or the user has killed.
+ * If so, issue the stop condition and go to idle.
+ */
+ if (drv_data->state == MV64XXX_I2C_STATE_IDLE) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ return;
+ }
+
+ /* The status from the ctlr [mostly] tells us what to do next */
+ switch (status) {
+ /* Start condition interrupt */
+ case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */
+ case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+ break;
+
+ /* Performing a write */
+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */
+ if (drv_data->msg->flags & I2C_M_TEN) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+ break;
+ }
+ /* FALLTHRU */
+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
+ case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
+ if ((drv_data->bytes_left == 0)
+ || (drv_data->aborting
+ && (drv_data->byte_posn != 0))) {
+ if (drv_data->send_stop) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ } else {
+ drv_data->action =
+ MV64XXX_I2C_ACTION_SEND_RESTART;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
+ }
+ } else {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+ drv_data->bytes_left--;
+ }
+ break;
+
+ /* Performing a read */
+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */
+ if (drv_data->msg->flags & I2C_M_TEN) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+ break;
+ }
+ /* FALLTHRU */
+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
+ if (drv_data->bytes_left == 0) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ break;
+ }
+ /* FALLTHRU */
+ case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
+ if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
+ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+ else {
+ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
+ drv_data->bytes_left--;
+ }
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+
+ if ((drv_data->bytes_left == 1) || drv_data->aborting)
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
+ break;
+
+ case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */
+ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ break;
+
+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */
+ case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */
+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */
+ /* Doesn't seem to be a device at other end */
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ drv_data->rc = -ENODEV;
+ break;
+
+ default:
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
+ "status: 0x%x, addr: 0x%x, flags: 0x%x\n",
+ drv_data->state, status, drv_data->msg->addr,
+ drv_data->msg->flags);
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ mv64xxx_i2c_hw_init(drv_data);
+ drv_data->rc = -EIO;
+ }
+}
+
+static void
+mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
+{
+ switch(drv_data->action) {
+ case MV64XXX_I2C_ACTION_SEND_RESTART:
+ drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->block = 0;
+ wake_up_interruptible(&drv_data->waitq);
+ break;
+
+ case MV64XXX_I2C_ACTION_CONTINUE:
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_START:
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_ADDR_1:
+ writel(drv_data->addr1,
+ drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_ADDR_2:
+ writel(drv_data->addr2,
+ drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_DATA:
+ writel(drv_data->msg->buf[drv_data->byte_posn++],
+ drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ break;
+
+ case MV64XXX_I2C_ACTION_RCV_DATA:
+ drv_data->msg->buf[drv_data->byte_posn++] =
+ readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ break;
+
+ case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
+ drv_data->msg->buf[drv_data->byte_posn++] =
+ readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->block = 0;
+ wake_up_interruptible(&drv_data->waitq);
+ break;
+
+ case MV64XXX_I2C_ACTION_INVALID:
+ default:
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx_i2c_do_action: Invalid action: %d\n",
+ drv_data->action);
+ drv_data->rc = -EIO;
+ /* FALLTHRU */
+ case MV64XXX_I2C_ACTION_SEND_STOP:
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->block = 0;
+ wake_up_interruptible(&drv_data->waitq);
+ break;
+ }
+}
+
+static irqreturn_t
+mv64xxx_i2c_intr(int irq, void *dev_id)
+{
+ struct mv64xxx_i2c_data *drv_data = dev_id;
+ unsigned long flags;
+ u32 status;
+ irqreturn_t rc = IRQ_NONE;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
+ MV64XXX_I2C_REG_CONTROL_IFLG) {
+ status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
+ mv64xxx_i2c_fsm(drv_data, status);
+ mv64xxx_i2c_do_action(drv_data);
+ rc = IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ * I2C Msg Execution Routines
+ *
+ *****************************************************************************
+ */
+static void
+mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
+ struct i2c_msg *msg)
+{
+ u32 dir = 0;
+
+ drv_data->msg = msg;
+ drv_data->byte_posn = 0;
+ drv_data->bytes_left = msg->len;
+ drv_data->aborting = 0;
+ drv_data->rc = 0;
+ drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
+ MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
+
+ if (msg->flags & I2C_M_RD)
+ 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;
+ } else {
+ drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir;
+ drv_data->addr2 = 0;
+ }
+}
+
+static void
+mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
+{
+ long time_left;
+ unsigned long flags;
+ char abort = 0;
+
+ time_left = wait_event_interruptible_timeout(drv_data->waitq,
+ !drv_data->block, drv_data->adapter.timeout);
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (!time_left) { /* Timed out */
+ drv_data->rc = -ETIMEDOUT;
+ abort = 1;
+ } else if (time_left < 0) { /* Interrupted/Error */
+ drv_data->rc = time_left; /* errno value */
+ abort = 1;
+ }
+
+ if (abort && drv_data->block) {
+ drv_data->aborting = 1;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ time_left = wait_event_timeout(drv_data->waitq,
+ !drv_data->block, drv_data->adapter.timeout);
+
+ if ((time_left <= 0) && drv_data->block) {
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx: I2C bus locked, block: %d, "
+ "time_left: %d\n", drv_data->block,
+ (int)time_left);
+ mv64xxx_i2c_hw_init(drv_data);
+ }
+ } else
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+static int
+mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
+ int is_first, int is_last)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ mv64xxx_i2c_prepare_for_io(drv_data, msg);
+
+ if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */
+ if (drv_data->msg->flags & I2C_M_RD) {
+ /* No action to do, wait for slave to send a byte */
+ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+ } else {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+ drv_data->bytes_left--;
+ }
+ } else {
+ if (is_first) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+ } else {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+ }
+ }
+
+ drv_data->send_stop = is_last;
+ drv_data->block = 1;
+ mv64xxx_i2c_do_action(drv_data);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ mv64xxx_i2c_wait_for_completion(drv_data);
+ return drv_data->rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ * I2C Core Support Routines (Interface to higher level I2C code)
+ *
+ *****************************************************************************
+ */
+static u32
+mv64xxx_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
+ int i, rc;
+
+ for (i = 0; i < num; i++) {
+ rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
+ i == 0, i + 1 == num);
+ if (rc < 0)
+ return rc;
+ }
+
+ return num;
+}
+
+static const struct i2c_algorithm mv64xxx_i2c_algo = {
+ .master_xfer = mv64xxx_i2c_xfer,
+ .functionality = mv64xxx_i2c_functionality,
+};
+
+/*
+ *****************************************************************************
+ *
+ * Driver Interface & Early Init Routines
+ *
+ *****************************************************************************
+ */
+static int __devinit
+mv64xxx_i2c_map_regs(struct platform_device *pd,
+ struct mv64xxx_i2c_data *drv_data)
+{
+ int size;
+ struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+ if (!r)
+ return -ENODEV;
+
+ size = resource_size(r);
+
+ if (!request_mem_region(r->start, size, drv_data->adapter.name))
+ return -EBUSY;
+
+ drv_data->reg_base = ioremap(r->start, size);
+ drv_data->reg_base_p = r->start;
+ drv_data->reg_size = size;
+
+ return 0;
+}
+
+static void
+mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
+{
+ if (drv_data->reg_base) {
+ iounmap(drv_data->reg_base);
+ release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
+ }
+
+ drv_data->reg_base = NULL;
+ drv_data->reg_base_p = 0;
+}
+
+static int __devinit
+mv64xxx_i2c_probe(struct platform_device *pd)
+{
+ struct mv64xxx_i2c_data *drv_data;
+ struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data;
+ int rc;
+
+ if ((pd->id != 0) || !pdata)
+ return -ENODEV;
+
+ drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ if (mv64xxx_i2c_map_regs(pd, drv_data)) {
+ rc = -ENODEV;
+ goto exit_kfree;
+ }
+
+ strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
+ sizeof(drv_data->adapter.name));
+
+ init_waitqueue_head(&drv_data->waitq);
+ spin_lock_init(&drv_data->lock);
+
+ drv_data->freq_m = pdata->freq_m;
+ drv_data->freq_n = pdata->freq_n;
+ drv_data->irq = platform_get_irq(pd, 0);
+ if (drv_data->irq < 0) {
+ rc = -ENXIO;
+ goto exit_unmap_regs;
+ }
+ drv_data->adapter.dev.parent = &pd->dev;
+ drv_data->adapter.algo = &mv64xxx_i2c_algo;
+ drv_data->adapter.owner = THIS_MODULE;
+ drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
+ drv_data->adapter.nr = pd->id;
+ platform_set_drvdata(pd, drv_data);
+ i2c_set_adapdata(&drv_data->adapter, drv_data);
+
+ mv64xxx_i2c_hw_init(drv_data);
+
+ if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
+ MV64XXX_I2C_CTLR_NAME, drv_data)) {
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx: Can't register intr handler irq: %d\n",
+ drv_data->irq);
+ rc = -EINVAL;
+ goto exit_unmap_regs;
+ } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
+ goto exit_free_irq;
+ }
+
+ return 0;
+
+ exit_free_irq:
+ free_irq(drv_data->irq, drv_data);
+ exit_unmap_regs:
+ mv64xxx_i2c_unmap_regs(drv_data);
+ exit_kfree:
+ kfree(drv_data);
+ return rc;
+}
+
+static int __devexit
+mv64xxx_i2c_remove(struct platform_device *dev)
+{
+ struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(dev);
+ int rc;
+
+ rc = i2c_del_adapter(&drv_data->adapter);
+ free_irq(drv_data->irq, drv_data);
+ mv64xxx_i2c_unmap_regs(drv_data);
+ kfree(drv_data);
+
+ return rc;
+}
+
+static struct platform_driver mv64xxx_i2c_driver = {
+ .probe = mv64xxx_i2c_probe,
+ .remove = __devexit_p(mv64xxx_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MV64XXX_I2C_CTLR_NAME,
+ },
+};
+
+static int __init
+mv64xxx_i2c_init(void)
+{
+ return platform_driver_register(&mv64xxx_i2c_driver);
+}
+
+static void __exit
+mv64xxx_i2c_exit(void)
+{
+ platform_driver_unregister(&mv64xxx_i2c_driver);
+}
+
+module_init(mv64xxx_i2c_init);
+module_exit(mv64xxx_i2c_exit);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
new file mode 100644
index 00000000..3d471d56
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -0,0 +1,419 @@
+/*
+ * Freescale MXS I2C bus driver
+ *
+ * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
+ *
+ * based on a (non-working) driver which was:
+ *
+ * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * TODO: add dma-support if platform-support for it is available
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+
+#include <mach/common.h>
+
+#define DRIVER_NAME "mxs-i2c"
+
+#define MXS_I2C_CTRL0 (0x00)
+#define MXS_I2C_CTRL0_SET (0x04)
+
+#define MXS_I2C_CTRL0_SFTRST 0x80000000
+#define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000
+#define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000
+#define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000
+#define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000
+#define MXS_I2C_CTRL0_MASTER_MODE 0x00020000
+#define MXS_I2C_CTRL0_DIRECTION 0x00010000
+#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF)
+
+#define MXS_I2C_CTRL1 (0x40)
+#define MXS_I2C_CTRL1_SET (0x44)
+#define MXS_I2C_CTRL1_CLR (0x48)
+
+#define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80
+#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40
+#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20
+#define MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x10
+#define MXS_I2C_CTRL1_EARLY_TERM_IRQ 0x08
+#define MXS_I2C_CTRL1_MASTER_LOSS_IRQ 0x04
+#define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02
+#define MXS_I2C_CTRL1_SLAVE_IRQ 0x01
+
+#define MXS_I2C_IRQ_MASK (MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \
+ MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \
+ MXS_I2C_CTRL1_EARLY_TERM_IRQ | \
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ | \
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \
+ MXS_I2C_CTRL1_SLAVE_IRQ)
+
+#define MXS_I2C_QUEUECTRL (0x60)
+#define MXS_I2C_QUEUECTRL_SET (0x64)
+#define MXS_I2C_QUEUECTRL_CLR (0x68)
+
+#define MXS_I2C_QUEUECTRL_QUEUE_RUN 0x20
+#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE 0x04
+
+#define MXS_I2C_QUEUESTAT (0x70)
+#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000
+#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F
+
+#define MXS_I2C_QUEUECMD (0x80)
+
+#define MXS_I2C_QUEUEDATA (0x90)
+
+#define MXS_I2C_DATA (0xa0)
+
+
+#define MXS_CMD_I2C_SELECT (MXS_I2C_CTRL0_RETAIN_CLOCK | \
+ MXS_I2C_CTRL0_PRE_SEND_START | \
+ MXS_I2C_CTRL0_MASTER_MODE | \
+ MXS_I2C_CTRL0_DIRECTION | \
+ MXS_I2C_CTRL0_XFER_COUNT(1))
+
+#define MXS_CMD_I2C_WRITE (MXS_I2C_CTRL0_PRE_SEND_START | \
+ MXS_I2C_CTRL0_MASTER_MODE | \
+ MXS_I2C_CTRL0_DIRECTION)
+
+#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
+ MXS_I2C_CTRL0_MASTER_MODE)
+
+/**
+ * struct mxs_i2c_dev - per device, private MXS-I2C data
+ *
+ * @dev: driver model device node
+ * @regs: IO registers pointer
+ * @cmd_complete: completion object for transaction wait
+ * @cmd_err: error code for last transaction
+ * @adapter: i2c subsystem adapter node
+ */
+struct mxs_i2c_dev {
+ struct device *dev;
+ void __iomem *regs;
+ struct completion cmd_complete;
+ u32 cmd_err;
+ struct i2c_adapter adapter;
+};
+
+/*
+ * TODO: check if calls to here are really needed. If not, we could get rid of
+ * mxs_reset_block and the mach-dependency. Needs an I2C analyzer, probably.
+ */
+static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
+{
+ mxs_reset_block(i2c->regs);
+ writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
+ writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+ i2c->regs + MXS_I2C_QUEUECTRL_SET);
+}
+
+static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
+ int flags)
+{
+ u32 data;
+
+ writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD);
+
+ data = (addr << 1) | I2C_SMBUS_READ;
+ writel(data, i2c->regs + MXS_I2C_DATA);
+
+ data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags;
+ writel(data, i2c->regs + MXS_I2C_QUEUECMD);
+}
+
+static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c,
+ u8 addr, u8 *buf, int len, int flags)
+{
+ u32 data;
+ int i, shifts_left;
+
+ data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
+ writel(data, i2c->regs + MXS_I2C_QUEUECMD);
+
+ /*
+ * We have to copy the slave address (u8) and buffer (arbitrary number
+ * of u8) into the data register (u32). To achieve that, the u8 are put
+ * into the MSBs of 'data' which is then shifted for the next u8. When
+ * appropriate, 'data' is written to MXS_I2C_DATA. So, the first u32
+ * looks like this:
+ *
+ * 3 2 1 0
+ * 10987654|32109876|54321098|76543210
+ * --------+--------+--------+--------
+ * buffer+2|buffer+1|buffer+0|slave_addr
+ */
+
+ data = ((addr << 1) | I2C_SMBUS_WRITE) << 24;
+
+ for (i = 0; i < len; i++) {
+ data >>= 8;
+ data |= buf[i] << 24;
+ if ((i & 3) == 2)
+ writel(data, i2c->regs + MXS_I2C_DATA);
+ }
+
+ /* Write out the remaining bytes if any */
+ shifts_left = 24 - (i & 3) * 8;
+ if (shifts_left)
+ writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA);
+}
+
+/*
+ * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the
+ * rd_threshold to 1). Couldn't get this to work, though.
+ */
+static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+ while (readl(i2c->regs + MXS_I2C_QUEUESTAT)
+ & MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ cond_resched();
+ }
+
+ return 0;
+}
+
+static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
+{
+ u32 data;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if ((i & 3) == 0) {
+ if (mxs_i2c_wait_for_data(i2c))
+ return -ETIMEDOUT;
+ data = readl(i2c->regs + MXS_I2C_QUEUEDATA);
+ }
+ buf[i] = data & 0xff;
+ data >>= 8;
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int stop)
+{
+ struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+ int ret;
+ int flags;
+
+ dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ init_completion(&i2c->cmd_complete);
+
+ flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
+ if (msg->flags & I2C_M_RD)
+ mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
+ else
+ mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
+ flags);
+
+ writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+ i2c->regs + MXS_I2C_QUEUECTRL_SET);
+
+ ret = wait_for_completion_timeout(&i2c->cmd_complete,
+ msecs_to_jiffies(1000));
+ if (ret == 0)
+ goto timeout;
+
+ if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+ ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
+ if (ret)
+ goto timeout;
+ }
+
+ if (i2c->cmd_err == -ENXIO)
+ mxs_i2c_reset(i2c);
+
+ dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err);
+
+ return i2c->cmd_err;
+
+timeout:
+ dev_dbg(i2c->dev, "Timeout!\n");
+ mxs_i2c_reset(i2c);
+ return -ETIMEDOUT;
+}
+
+static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < num; i++) {
+ err = mxs_i2c_xfer_msg(adap, &msgs[i], i == (num - 1));
+ if (err)
+ return err;
+ }
+
+ return num;
+}
+
+static u32 mxs_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
+{
+ struct mxs_i2c_dev *i2c = dev_id;
+ u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
+ bool is_last_cmd;
+
+ if (!stat)
+ return IRQ_NONE;
+
+ if (stat & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
+ i2c->cmd_err = -ENXIO;
+ else if (stat & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ | MXS_I2C_CTRL1_SLAVE_IRQ))
+ /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
+ i2c->cmd_err = -EIO;
+ else
+ i2c->cmd_err = 0;
+
+ is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+ MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+
+ if (is_last_cmd || i2c->cmd_err)
+ complete(&i2c->cmd_complete);
+
+ writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
+
+ return IRQ_HANDLED;
+}
+
+static const struct i2c_algorithm mxs_i2c_algo = {
+ .master_xfer = mxs_i2c_xfer,
+ .functionality = mxs_i2c_func,
+};
+
+static int __devinit mxs_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxs_i2c_dev *i2c;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ resource_size_t res_size;
+ int err, irq;
+
+ i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ res_size = resource_size(res);
+ if (!devm_request_mem_region(dev, res->start, res_size, res->name))
+ return -EBUSY;
+
+ i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
+ if (!i2c->regs)
+ return -EBUSY;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
+ if (err)
+ return err;
+
+ i2c->dev = dev;
+ platform_set_drvdata(pdev, i2c);
+
+ /* Do reset to enforce correct startup after pinmuxing */
+ mxs_i2c_reset(i2c);
+
+ adap = &i2c->adapter;
+ strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
+ adap->owner = THIS_MODULE;
+ adap->algo = &mxs_i2c_algo;
+ adap->dev.parent = dev;
+ adap->nr = pdev->id;
+ i2c_set_adapdata(adap, i2c);
+ err = i2c_add_numbered_adapter(adap);
+ if (err) {
+ dev_err(dev, "Failed to add adapter (%d)\n", err);
+ writel(MXS_I2C_CTRL0_SFTRST,
+ i2c->regs + MXS_I2C_CTRL0_SET);
+ return err;
+ }
+
+ return 0;
+}
+
+static int __devexit mxs_i2c_remove(struct platform_device *pdev)
+{
+ struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = i2c_del_adapter(&i2c->adapter);
+ if (ret)
+ return -EBUSY;
+
+ writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+ i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+ writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mxs_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(mxs_i2c_remove),
+};
+
+static int __init mxs_i2c_init(void)
+{
+ return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe);
+}
+subsys_initcall(mxs_i2c_init);
+
+static void __exit mxs_i2c_exit(void)
+{
+ platform_driver_unregister(&mxs_i2c_driver);
+}
+module_exit(mxs_i2c_exit);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("MXS I2C Bus Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c
new file mode 100644
index 00000000..29015eb9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nforce2-s4985.c
@@ -0,0 +1,257 @@
+/*
+ * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
+ *
+ * Copyright (C) 2008 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.
+ */
+
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4. We define one virtual
+ * adapter per CPU, which corresponds to one multiplexed channel:
+ * CPU0: virtual adapter 1, channel 1
+ * CPU1: virtual adapter 2, channel 2
+ * CPU2: virtual adapter 3, channel 3
+ * CPU3: virtual adapter 4, channel 4
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+extern struct i2c_adapter *nforce2_smbus;
+
+static struct i2c_adapter *s4985_adapter;
+static struct i2c_algorithm *s4985_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static DEFINE_MUTEX(nforce2_lock);
+
+static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ int error;
+
+ /* We exclude the multiplexed addresses */
+ if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+ || addr == 0x18)
+ return -ENXIO;
+
+ mutex_lock(&nforce2_lock);
+ error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+ mutex_unlock(&nforce2_lock);
+
+ return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+ channels when it is really needed. This greatly reduces the SMBus
+ overhead, but also assumes that nobody will be writing to the PCA9556
+ in our back. */
+static u8 last_channels;
+
+static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data,
+ u8 channels)
+{
+ int error;
+
+ /* We exclude the non-multiplexed addresses */
+ if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+ return -ENXIO;
+
+ mutex_lock(&nforce2_lock);
+ if (last_channels != channels) {
+ union i2c_smbus_data mplxdata;
+ mplxdata.byte = channels;
+
+ error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
+ I2C_SMBUS_WRITE, 0x01,
+ I2C_SMBUS_BYTE_DATA,
+ &mplxdata);
+ if (error)
+ goto UNLOCK;
+ last_channels = channels;
+ }
+ error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+
+UNLOCK:
+ mutex_unlock(&nforce2_lock);
+ return error;
+}
+
+static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU0: channel 1 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x02);
+}
+
+static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU1: channel 2 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x04);
+}
+
+static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU2: channel 3 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x08);
+}
+
+static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU3: channel 4 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x10);
+}
+
+static int __init nforce2_s4985_init(void)
+{
+ int i, error;
+ union i2c_smbus_data ioconfig;
+
+ if (!nforce2_smbus)
+ return -ENODEV;
+
+ /* Configure the PCA9556 multiplexer */
+ ioconfig.byte = 0x00; /* All I/O to output mode */
+ error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+ I2C_SMBUS_BYTE_DATA, &ioconfig);
+ if (error) {
+ dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
+ error = -EIO;
+ goto ERROR0;
+ }
+
+ /* Unregister physical bus */
+ error = i2c_del_adapter(nforce2_smbus);
+ if (error) {
+ dev_err(&nforce2_smbus->dev, "Physical bus removal failed\n");
+ goto ERROR0;
+ }
+
+ printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
+ /* Define the 5 virtual adapters and algorithms structures */
+ s4985_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!s4985_adapter) {
+ error = -ENOMEM;
+ goto ERROR1;
+ }
+ s4985_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL);
+ if (!s4985_algo) {
+ error = -ENOMEM;
+ goto ERROR2;
+ }
+
+ /* Fill in the new structures */
+ s4985_algo[0] = *(nforce2_smbus->algo);
+ s4985_algo[0].smbus_xfer = nforce2_access_virt0;
+ s4985_adapter[0] = *nforce2_smbus;
+ s4985_adapter[0].algo = s4985_algo;
+ s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
+ for (i = 1; i < 5; i++) {
+ s4985_algo[i] = *(nforce2_smbus->algo);
+ s4985_adapter[i] = *nforce2_smbus;
+ snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
+ "SMBus nForce2 adapter (CPU%d)", i - 1);
+ s4985_adapter[i].algo = s4985_algo + i;
+ s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
+ }
+ s4985_algo[1].smbus_xfer = nforce2_access_virt1;
+ s4985_algo[2].smbus_xfer = nforce2_access_virt2;
+ s4985_algo[3].smbus_xfer = nforce2_access_virt3;
+ s4985_algo[4].smbus_xfer = nforce2_access_virt4;
+
+ /* Register virtual adapters */
+ for (i = 0; i < 5; i++) {
+ error = i2c_add_adapter(s4985_adapter + i);
+ if (error) {
+ printk(KERN_ERR "i2c-nforce2-s4985: "
+ "Virtual adapter %d registration "
+ "failed, module not inserted\n", i);
+ for (i--; i >= 0; i--)
+ i2c_del_adapter(s4985_adapter + i);
+ goto ERROR3;
+ }
+ }
+
+ return 0;
+
+ERROR3:
+ kfree(s4985_algo);
+ s4985_algo = NULL;
+ERROR2:
+ kfree(s4985_adapter);
+ s4985_adapter = NULL;
+ERROR1:
+ /* Restore physical bus */
+ i2c_add_adapter(nforce2_smbus);
+ERROR0:
+ return error;
+}
+
+static void __exit nforce2_s4985_exit(void)
+{
+ if (s4985_adapter) {
+ int i;
+
+ for (i = 0; i < 5; i++)
+ i2c_del_adapter(s4985_adapter+i);
+ kfree(s4985_adapter);
+ s4985_adapter = NULL;
+ }
+ kfree(s4985_algo);
+ s4985_algo = NULL;
+
+ /* Restore physical bus */
+ if (i2c_add_adapter(nforce2_smbus))
+ printk(KERN_ERR "i2c-nforce2-s4985: "
+ "Physical bus restoration failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("S4985 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(nforce2_s4985_init);
+module_exit(nforce2_s4985_exit);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
new file mode 100644
index 00000000..4853b52a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -0,0 +1,468 @@
+/*
+ SMBus driver for nVidia nForce2 MCP
+
+ Added nForce3 Pro 150 Thomas Leibold <thomas@plx.com>,
+ Ported to 2.5 Patrick Dreker <patrick@dreker.de>,
+ Copyright (c) 2003 Hans-Frieder Vogt <hfvogt@arcor.de>,
+ Based on
+ SMBus 2.0 driver for AMD-8111 IO-Hub
+ Copyright (c) 2002 Vojtech Pavlik
+
+ 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.
+*/
+
+/*
+ SUPPORTED DEVICES PCI ID
+ nForce2 MCP 0064
+ nForce2 Ultra 400 MCP 0084
+ nForce3 Pro150 MCP 00D4
+ nForce3 250Gb MCP 00E4
+ nForce4 MCP 0052
+ nForce4 MCP-04 0034
+ nForce MCP51 0264
+ nForce MCP55 0368
+ nForce MCP61 03EB
+ nForce MCP65 0446
+ nForce MCP67 0542
+ nForce MCP73 07D8
+ nForce MCP78S 0752
+ nForce MCP79 0AA2
+
+ This driver supports the 2 SMBuses that are included in the MCP of the
+ nForce2/3/4/5xx chipsets.
+*/
+
+/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
+
+
+struct nforce2_smbus {
+ struct i2c_adapter adapter;
+ int base;
+ int size;
+ int blockops;
+ int can_abort;
+};
+
+
+/*
+ * nVidia nForce2 SMBus control register definitions
+ * (Newer incarnations use standard BARs 4 and 5 instead)
+ */
+#define NFORCE_PCI_SMB1 0x50
+#define NFORCE_PCI_SMB2 0x54
+
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+#define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */
+#define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */
+#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
+#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
+#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
+#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
+ bytes */
+#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to
+ check the status of
+ the abort command */
+#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */
+
+#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that
+ abort succeeded */
+#define NVIDIA_SMB_CTRL_ABORT 0x20
+#define NVIDIA_SMB_STS_DONE 0x80
+#define NVIDIA_SMB_STS_ALRM 0x40
+#define NVIDIA_SMB_STS_RES 0x20
+#define NVIDIA_SMB_STS_STATUS 0x1f
+
+#define NVIDIA_SMB_PRTCL_WRITE 0x00
+#define NVIDIA_SMB_PRTCL_READ 0x01
+#define NVIDIA_SMB_PRTCL_QUICK 0x02
+#define NVIDIA_SMB_PRTCL_BYTE 0x04
+#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
+#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
+#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
+#define NVIDIA_SMB_PRTCL_PEC 0x80
+
+/* Misc definitions */
+#define MAX_TIMEOUT 100
+
+/* We disable the second SMBus channel on these boards */
+static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = {
+ {
+ .ident = "DFI Lanparty NF4 Expert",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"),
+ DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"),
+ },
+ },
+ { }
+};
+
+static struct pci_driver nforce2_driver;
+
+/* For multiplexing support, we need a global reference to the 1st
+ SMBus channel */
+#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE
+struct i2c_adapter *nforce2_smbus;
+EXPORT_SYMBOL_GPL(nforce2_smbus);
+
+static void nforce2_set_reference(struct i2c_adapter *adap)
+{
+ nforce2_smbus = adap;
+}
+#else
+static inline void nforce2_set_reference(struct i2c_adapter *adap) { }
+#endif
+
+static void nforce2_abort(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ dev_dbg(&adap->dev, "Aborting current transaction\n");
+
+ outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
+ } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
+ (timeout++ < MAX_TIMEOUT));
+ if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
+ dev_err(&adap->dev, "Can't reset the smbus\n");
+ outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
+}
+
+static int nforce2_check_status(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STS);
+ } while ((!temp) && (timeout++ < MAX_TIMEOUT));
+
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ if (smbus->can_abort)
+ nforce2_abort(adap);
+ return -ETIMEDOUT;
+ }
+ if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+ dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Return negative errno on error */
+static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ unsigned char protocol, pec;
+ u8 len;
+ int i, status;
+
+ protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
+ NVIDIA_SMB_PRTCL_WRITE;
+ pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
+
+ switch (size) {
+
+ case I2C_SMBUS_QUICK:
+ protocol |= NVIDIA_SMB_PRTCL_QUICK;
+ read_write = I2C_SMBUS_WRITE;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, NVIDIA_SMB_CMD);
+ protocol |= NVIDIA_SMB_PRTCL_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, NVIDIA_SMB_DATA);
+ protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word, NVIDIA_SMB_DATA);
+ outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
+ }
+ protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev,
+ "Transaction failed "
+ "(requested block size: %d)\n",
+ len);
+ return -EINVAL;
+ }
+ outb_p(len, NVIDIA_SMB_BCNT);
+ for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
+ outb_p(data->block[i + 1],
+ NVIDIA_SMB_DATA+i);
+ }
+ protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
+ break;
+
+ default:
+ dev_err(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
+ outb_p(protocol, NVIDIA_SMB_PRTCL);
+
+ status = nforce2_check_status(adap);
+ if (status)
+ return status;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = inb_p(NVIDIA_SMB_DATA);
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ len = inb_p(NVIDIA_SMB_BCNT);
+ if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev, "Transaction failed "
+ "(received block size: 0x%02x)\n",
+ len);
+ return -EPROTO;
+ }
+ for (i = 0; i < len; i++)
+ data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
+ data->block[0] = len;
+ break;
+ }
+
+ return 0;
+}
+
+
+static u32 nforce2_func(struct i2c_adapter *adapter)
+{
+ /* other functionality might be possible, but is not tested */
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PEC |
+ (((struct nforce2_smbus*)adapter->algo_data)->blockops ?
+ I2C_FUNC_SMBUS_BLOCK_DATA : 0);
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = nforce2_access,
+ .functionality = nforce2_func,
+};
+
+
+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) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE (pci, nforce2_ids);
+
+
+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
+ int alt_reg, struct nforce2_smbus *smbus, const char *name)
+{
+ int error;
+
+ smbus->base = pci_resource_start(dev, bar);
+ if (smbus->base) {
+ smbus->size = pci_resource_len(dev, bar);
+ } else {
+ /* Older incarnations of the device used non-standard BARs */
+ u16 iobase;
+
+ if (pci_read_config_word(dev, alt_reg, &iobase)
+ != PCIBIOS_SUCCESSFUL) {
+ dev_err(&dev->dev, "Error reading PCI config for %s\n",
+ name);
+ return -EIO;
+ }
+
+ smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
+ smbus->size = 64;
+ }
+
+ error = acpi_check_region(smbus->base, smbus->size,
+ nforce2_driver.name);
+ if (error)
+ return error;
+
+ if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
+ dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
+ smbus->base, smbus->base+smbus->size-1, name);
+ return -EBUSY;
+ }
+ smbus->adapter.owner = THIS_MODULE;
+ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+ smbus->adapter.dev.parent = &dev->dev;
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+ "SMBus nForce2 adapter at %04x", smbus->base);
+
+ error = i2c_add_adapter(&smbus->adapter);
+ if (error) {
+ dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");
+ release_region(smbus->base, smbus->size);
+ return error;
+ }
+ dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base);
+ return 0;
+}
+
+
+static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct nforce2_smbus *smbuses;
+ int res1, res2;
+
+ /* we support 2 SMBus adapters */
+ if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL)))
+ return -ENOMEM;
+ pci_set_drvdata(dev, smbuses);
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
+ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
+ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
+ smbuses[0].blockops = 1;
+ smbuses[1].blockops = 1;
+ smbuses[0].can_abort = 1;
+ smbuses[1].can_abort = 1;
+ }
+
+ /* SMBus adapter 1 */
+ res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+ if (res1 < 0)
+ smbuses[0].base = 0; /* to have a check value */
+
+ /* SMBus adapter 2 */
+ if (dmi_check_system(nforce2_dmi_blacklist2)) {
+ dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n");
+ res2 = -EPERM;
+ smbuses[1].base = 0;
+ } else {
+ res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1],
+ "SMB2");
+ if (res2 < 0)
+ smbuses[1].base = 0; /* to have a check value */
+ }
+
+ if ((res1 < 0) && (res2 < 0)) {
+ /* we did not find even one of the SMBuses, so we give up */
+ kfree(smbuses);
+ return -ENODEV;
+ }
+
+ nforce2_set_reference(&smbuses[0].adapter);
+ return 0;
+}
+
+
+static void __devexit nforce2_remove(struct pci_dev *dev)
+{
+ struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
+
+ nforce2_set_reference(NULL);
+ if (smbuses[0].base) {
+ i2c_del_adapter(&smbuses[0].adapter);
+ release_region(smbuses[0].base, smbuses[0].size);
+ }
+ if (smbuses[1].base) {
+ i2c_del_adapter(&smbuses[1].adapter);
+ release_region(smbuses[1].base, smbuses[1].size);
+ }
+ kfree(smbuses);
+}
+
+static struct pci_driver nforce2_driver = {
+ .name = "nForce2_smbus",
+ .id_table = nforce2_ids,
+ .probe = nforce2_probe,
+ .remove = __devexit_p(nforce2_remove),
+};
+
+static int __init nforce2_init(void)
+{
+ return pci_register_driver(&nforce2_driver);
+}
+
+static void __exit nforce2_exit(void)
+{
+ pci_unregister_driver(&nforce2_driver);
+}
+
+module_init(nforce2_init);
+module_exit(nforce2_exit);
+
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
new file mode 100644
index 00000000..0c731ca6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ * 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/slab.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.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
+};
+
+/**
+ * struct i2c_nmk_client - client specific data
+ * @slave_adr: 7-bit slave address
+ * @count: no. bytes to be transferred
+ * @buffer: client data buffer
+ * @xfer_bytes: bytes transferred 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
+ * @busy: Busy doing transfer
+ */
+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;
+ struct regulator *regulator;
+ bool busy;
+};
+
+/* 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 + dev->adap.timeout;
+
+ 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)
+ goto exit;
+
+ /* 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;
+
+exit:
+ return stat;
+}
+
+/* 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 respectively 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 (up to 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, dev->adap.timeout);
+
+ 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) {
+ /* Controller timed out */
+ dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+ dev->cli.slave_adr);
+ status = -ETIMEDOUT;
+ }
+ return status;
+}
+
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+ int count;
+
+ for (count = (no_bytes - 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++;
+ }
+
+}
+
+/**
+ * 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_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+ /* Fill the TX FIFO with transmit data */
+ fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+ if (dev->cli.count != 0)
+ irq_mask |= I2C_IT_TXFNE;
+
+ /*
+ * 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, dev->adap.timeout);
+
+ 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) {
+ /* Controller timed out */
+ dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+ dev->cli.slave_adr);
+ status = -ETIMEDOUT;
+ }
+
+ return status;
+}
+
+/**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+ int status;
+
+ if (flags & I2C_M_RD) {
+ /* 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)) {
+ u32 i2c_sr;
+ u32 cause;
+
+ i2c_sr = readl(dev->virtbase + I2C_SR);
+ /*
+ * Check if the controller I2C operation status
+ * is set to ABORT(11b).
+ */
+ if (((i2c_sr >> 2) & 0x3) == 0x3) {
+ /* get the abort cause */
+ cause = (i2c_sr >> 4) & 0x7;
+ dev_err(&dev->pdev->dev, "%s\n", cause
+ >= ARRAY_SIZE(abort_causes) ?
+ "unknown reason" :
+ abort_causes[cause]);
+ }
+
+ (void) init_hw(dev);
+
+ status = status ? status : dev->result;
+ }
+
+ 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;
+ struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+ int j;
+
+ dev->busy = true;
+
+ if (dev->regulator)
+ regulator_enable(dev->regulator);
+ pm_runtime_get_sync(&dev->pdev->dev);
+
+ clk_enable(dev->clk);
+
+ status = init_hw(dev);
+ if (status)
+ goto out;
+
+ /* Attempt three times to send the message queue */
+ for (j = 0; j < 3; j++) {
+ /* 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");
+
+ status = -EINVAL;
+ goto out;
+ }
+ 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;
+
+ status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+ if (status != 0)
+ break;
+ }
+ if (status == 0)
+ break;
+ }
+
+out:
+ clk_disable(dev->clk);
+ pm_runtime_put_sync(&dev->pdev->dev);
+ if (dev->regulator)
+ regulator_disable(dev->regulator);
+
+ dev->busy = false;
+
+ /* return the no. messages processed */
+ if (status)
+ return status;
+ else
+ return num_msgs;
+}
+
+/**
+ * disable_interrupts() - disable the interrupts
+ * @dev: private data of controller
+ * @irq: interrupt number
+ */
+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 {
+ fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
+ /*
+ * 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++;
+ }
+ }
+
+ disable_all_interrupts(dev);
+ clear_all_interrupts(dev);
+
+ if (dev->cli.count) {
+ dev->result = -EIO;
+ 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 = -EIO;
+ (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 = -EIO;
+ /* 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 = -EIO;
+ (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;
+}
+
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+
+ if (nmk_i2c->busy)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int nmk_i2c_resume(struct device *dev)
+{
+ return 0;
+}
+#else
+#define nmk_i2c_suspend NULL
+#define nmk_i2c_resume NULL
+#endif
+
+/*
+ * We use noirq so that we suspend late and resume before the wakeup interrupt
+ * to ensure that we do the !pm_runtime_suspended() check in resume before
+ * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
+ */
+static const struct dev_pm_ops nmk_i2c_pm = {
+ .suspend_noirq = nmk_i2c_suspend,
+ .resume_noirq = nmk_i2c_resume,
+};
+
+static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+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->busy = false;
+ 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->regulator = regulator_get(&pdev->dev, "v-i2c");
+ if (IS_ERR(dev->regulator)) {
+ dev_warn(&pdev->dev, "could not get i2c regulator\n");
+ dev->regulator = NULL;
+ }
+
+ pm_suspend_ignore_children(&pdev->dev, true);
+ pm_runtime_enable(&pdev->dev);
+
+ 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;
+ }
+
+ 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;
+ adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+ msecs_to_jiffies(20000);
+ snprintf(adap->name, sizeof(adap->name),
+ "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
+
+ /* 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);
+
+ dev_info(&pdev->dev, "initialize %s on virtual "
+ "base %p\n", adap->name, 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_add_adap:
+ clk_put(dev->clk);
+ err_no_clk:
+ if (dev->regulator)
+ regulator_put(dev->regulator);
+ pm_runtime_disable(&pdev->dev);
+ 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 resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 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);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ clk_put(dev->clk);
+ if (dev->regulator)
+ regulator_put(dev->regulator);
+ pm_runtime_disable(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct platform_driver nmk_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .pm = &nmk_i2c_pm,
+ },
+ .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-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c
new file mode 100644
index 00000000..72434263
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nuc900.c
@@ -0,0 +1,708 @@
+/*
+ * linux/drivers/i2c/busses/i2c-nuc900.c
+ *
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * This driver based on S3C2410 I2C driver of Ben Dooks <ben-Y5A6D6n0/KfQXOPxS62xeg@public.gmane.org>.
+ * Written by Wan ZongShun <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.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;version 2 of the License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <mach/mfp.h>
+#include <mach/i2c.h>
+
+/* nuc900 i2c registers offset */
+
+#define CSR 0x00
+#define DIVIDER 0x04
+#define CMDR 0x08
+#define SWR 0x0C
+#define RXR 0x10
+#define TXR 0x14
+
+/* nuc900 i2c CSR register bits */
+
+#define IRQEN 0x003
+#define I2CBUSY 0x400
+#define I2CSTART 0x018
+#define IRQFLAG 0x004
+#define ARBIT_LOST 0x200
+#define SLAVE_ACK 0x800
+
+/* nuc900 i2c CMDR register bits */
+
+#define I2C_CMD_START 0x10
+#define I2C_CMD_STOP 0x08
+#define I2C_CMD_READ 0x04
+#define I2C_CMD_WRITE 0x02
+#define I2C_CMD_NACK 0x01
+
+/* i2c controller state */
+
+enum nuc900_i2c_state {
+ STATE_IDLE,
+ STATE_START,
+ STATE_READ,
+ STATE_WRITE,
+ STATE_STOP
+};
+
+/* i2c controller private data */
+
+struct nuc900_i2c {
+ spinlock_t lock;
+ wait_queue_head_t wait;
+
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int msg_idx;
+ unsigned int msg_ptr;
+ unsigned int irq;
+
+ enum nuc900_i2c_state state;
+
+ void __iomem *regs;
+ struct clk *clk;
+ struct device *dev;
+ struct resource *ioarea;
+ struct i2c_adapter adap;
+};
+
+/* nuc900_i2c_master_complete
+ *
+ * complete the message and wake up the caller, using the given return code,
+ * or zero to mean ok.
+*/
+
+static inline void nuc900_i2c_master_complete(struct nuc900_i2c *i2c, int ret)
+{
+ dev_dbg(i2c->dev, "master_complete %d\n", ret);
+
+ i2c->msg_ptr = 0;
+ i2c->msg = NULL;
+ i2c->msg_idx++;
+ i2c->msg_num = 0;
+ if (ret)
+ i2c->msg_idx = ret;
+
+ wake_up(&i2c->wait);
+}
+
+/* irq enable/disable functions */
+
+static inline void nuc900_i2c_disable_irq(struct nuc900_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + CSR);
+ writel(tmp & ~IRQEN, i2c->regs + CSR);
+}
+
+static inline void nuc900_i2c_enable_irq(struct nuc900_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + CSR);
+ writel(tmp | IRQEN, i2c->regs + CSR);
+}
+
+
+/* nuc900_i2c_message_start
+ *
+ * put the start of a message onto the bus
+*/
+
+static void nuc900_i2c_message_start(struct nuc900_i2c *i2c,
+ struct i2c_msg *msg)
+{
+ unsigned int addr = (msg->addr & 0x7f) << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 0x1;
+ writel(addr & 0xff, i2c->regs + TXR);
+ writel(I2C_CMD_START | I2C_CMD_WRITE, i2c->regs + CMDR);
+}
+
+static inline void nuc900_i2c_stop(struct nuc900_i2c *i2c, int ret)
+{
+
+ dev_dbg(i2c->dev, "STOP\n");
+
+ /* stop the transfer */
+ i2c->state = STATE_STOP;
+ writel(I2C_CMD_STOP, i2c->regs + CMDR);
+
+ nuc900_i2c_master_complete(i2c, ret);
+ nuc900_i2c_disable_irq(i2c);
+}
+
+/* helper functions to determine the current state in the set of
+ * messages we are sending
+*/
+
+/* is_lastmsg()
+ *
+ * returns TRUE if the current message is the last in the set
+*/
+
+static inline int is_lastmsg(struct nuc900_i2c *i2c)
+{
+ return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+/* is_msglast
+ *
+ * returns TRUE if we this is the last byte in the current message
+*/
+
+static inline int is_msglast(struct nuc900_i2c *i2c)
+{
+ return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/* is_msgend
+ *
+ * returns TRUE if we reached the end of the current message
+*/
+
+static inline int is_msgend(struct nuc900_i2c *i2c)
+{
+ return i2c->msg_ptr >= i2c->msg->len;
+}
+
+/* i2c_nuc900_irq_nextbyte
+ *
+ * process an interrupt and work out what to do
+ */
+
+static void i2c_nuc900_irq_nextbyte(struct nuc900_i2c *i2c,
+ unsigned long iicstat)
+{
+ unsigned char byte;
+
+ switch (i2c->state) {
+
+ case STATE_IDLE:
+ dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
+ break;
+
+ case STATE_STOP:
+ dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
+ nuc900_i2c_disable_irq(i2c);
+ break;
+
+ case STATE_START:
+ /* last thing we did was send a start condition on the
+ * bus, or started a new i2c message
+ */
+
+ if (iicstat & SLAVE_ACK &&
+ !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ /* ack was not received... */
+
+ dev_dbg(i2c->dev, "ack was not received\n");
+ nuc900_i2c_stop(i2c, -ENXIO);
+ break;
+ }
+
+ if (i2c->msg->flags & I2C_M_RD)
+ i2c->state = STATE_READ;
+ else
+ i2c->state = STATE_WRITE;
+
+ /* terminate the transfer if there is nothing to do
+ * as this is used by the i2c probe to find devices.
+ */
+
+ if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+ nuc900_i2c_stop(i2c, 0);
+ break;
+ }
+
+ if (i2c->state == STATE_READ)
+ goto prepare_read;
+
+ /* fall through to the write state, as we will need to
+ * send a byte as well
+ */
+
+ case STATE_WRITE:
+ /* we are writing data to the device... check for the
+ * end of the message, and if so, work out what to do
+ */
+
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ if (iicstat & SLAVE_ACK) {
+ dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+ nuc900_i2c_stop(i2c, -ECONNREFUSED);
+ break;
+ }
+ }
+
+retry_write:
+
+ if (!is_msgend(i2c)) {
+ byte = i2c->msg->buf[i2c->msg_ptr++];
+ writeb(byte, i2c->regs + TXR);
+ writel(I2C_CMD_WRITE, i2c->regs + CMDR);
+
+ } else if (!is_lastmsg(i2c)) {
+ /* we need to go to the next i2c message */
+
+ dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+
+ /* check to see if we need to do another message */
+ if (i2c->msg->flags & I2C_M_NOSTART) {
+
+ if (i2c->msg->flags & I2C_M_RD) {
+ /* cannot do this, the controller
+ * forces us to send a new START
+ * when we change direction
+ */
+
+ nuc900_i2c_stop(i2c, -EINVAL);
+ }
+
+ goto retry_write;
+ } else {
+ /* send the new start */
+ nuc900_i2c_message_start(i2c, i2c->msg);
+ i2c->state = STATE_START;
+ }
+
+ } else {
+ /* send stop */
+
+ nuc900_i2c_stop(i2c, 0);
+ }
+ break;
+
+ case STATE_READ:
+ /* we have a byte of data in the data register, do
+ * something with it, and then work out wether we are
+ * going to do any more read/write
+ */
+
+ byte = readb(i2c->regs + RXR);
+ i2c->msg->buf[i2c->msg_ptr++] = byte;
+
+prepare_read:
+ if (is_msglast(i2c)) {
+ /* last byte of buffer */
+
+ if (is_lastmsg(i2c))
+ writel(I2C_CMD_READ | I2C_CMD_NACK,
+ i2c->regs + CMDR);
+
+ } else if (is_msgend(i2c)) {
+ /* ok, we've read the entire buffer, see if there
+ * is anything else we need to do
+ */
+
+ if (is_lastmsg(i2c)) {
+ /* last message, send stop and complete */
+ dev_dbg(i2c->dev, "READ: Send Stop\n");
+
+ nuc900_i2c_stop(i2c, 0);
+ } else {
+ /* go to the next transfer */
+ dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+
+ writel(I2C_CMD_READ, i2c->regs + CMDR);
+ }
+
+ } else {
+ writel(I2C_CMD_READ, i2c->regs + CMDR);
+ }
+
+ break;
+ }
+}
+
+/* nuc900_i2c_irq
+ *
+ * top level IRQ servicing routine
+*/
+
+static irqreturn_t nuc900_i2c_irq(int irqno, void *dev_id)
+{
+ struct nuc900_i2c *i2c = dev_id;
+ unsigned long status;
+
+ status = readl(i2c->regs + CSR);
+ writel(status | IRQFLAG, i2c->regs + CSR);
+
+ if (status & ARBIT_LOST) {
+ /* deal with arbitration loss */
+ dev_err(i2c->dev, "deal with arbitration loss\n");
+ goto out;
+ }
+
+ if (i2c->state == STATE_IDLE) {
+ dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
+ goto out;
+ }
+
+ /* pretty much this leaves us with the fact that we've
+ * transmitted or received whatever byte we last sent
+ */
+
+ i2c_nuc900_irq_nextbyte(i2c, status);
+
+ out:
+ return IRQ_HANDLED;
+}
+
+
+/* nuc900_i2c_set_master
+ *
+ * get the i2c bus for a master transaction
+*/
+
+static int nuc900_i2c_set_master(struct nuc900_i2c *i2c)
+{
+ int timeout = 400;
+
+ while (timeout-- > 0) {
+ if (((readl(i2c->regs + SWR) & I2CSTART) == I2CSTART) &&
+ ((readl(i2c->regs + CSR) & I2CBUSY) == 0)) {
+ return 0;
+ }
+
+ msleep(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/* nuc900_i2c_doxfer
+ *
+ * this starts an i2c transfer
+*/
+
+static int nuc900_i2c_doxfer(struct nuc900_i2c *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ unsigned long iicstat, timeout;
+ int spins = 20;
+ int ret;
+
+ ret = nuc900_i2c_set_master(i2c);
+ if (ret != 0) {
+ dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ spin_lock_irq(&i2c->lock);
+
+ i2c->msg = msgs;
+ i2c->msg_num = num;
+ i2c->msg_ptr = 0;
+ i2c->msg_idx = 0;
+ i2c->state = STATE_START;
+
+ nuc900_i2c_message_start(i2c, msgs);
+ spin_unlock_irq(&i2c->lock);
+
+ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+ ret = i2c->msg_idx;
+
+ /* having these next two as dev_err() makes life very
+ * noisy when doing an i2cdetect
+ */
+
+ if (timeout == 0)
+ dev_dbg(i2c->dev, "timeout\n");
+ else if (ret != num)
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+ /* ensure the stop has been through the bus */
+
+ dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+ /* first, try busy waiting briefly */
+ do {
+ iicstat = readl(i2c->regs + CSR);
+ } while ((iicstat & I2CBUSY) && --spins);
+
+ /* if that timed out sleep */
+ if (!spins) {
+ msleep(1);
+ iicstat = readl(i2c->regs + CSR);
+ }
+
+ if (iicstat & I2CBUSY)
+ dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+
+ out:
+ return ret;
+}
+
+/* nuc900_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+*/
+
+static int nuc900_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct nuc900_i2c *i2c = (struct nuc900_i2c *)adap->algo_data;
+ int retry;
+ int ret;
+
+ nuc900_i2c_enable_irq(i2c);
+
+ for (retry = 0; retry < adap->retries; retry++) {
+
+ ret = nuc900_i2c_doxfer(i2c, msgs, num);
+
+ if (ret != -EAGAIN)
+ return ret;
+
+ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+ udelay(100);
+ }
+
+ return -EREMOTEIO;
+}
+
+/* declare our i2c functionality */
+static u32 nuc900_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* i2c bus registration info */
+
+static const struct i2c_algorithm nuc900_i2c_algorithm = {
+ .master_xfer = nuc900_i2c_xfer,
+ .functionality = nuc900_i2c_func,
+};
+
+/* nuc900_i2c_probe
+ *
+ * called by the bus driver when a suitable device is found
+*/
+
+static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
+{
+ struct nuc900_i2c *i2c;
+ struct nuc900_platform_i2c *pdata;
+ struct resource *res;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ i2c = kzalloc(sizeof(struct nuc900_i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ strlcpy(i2c->adap.name, "nuc900-i2c0", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &nuc900_i2c_algorithm;
+ i2c->adap.retries = 2;
+ i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ /* find the clock and enable it */
+
+ i2c->dev = &pdev->dev;
+ i2c->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ ret = -ENOENT;
+ goto err_noclk;
+ }
+
+ dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
+ clk_enable(i2c->clk);
+
+ /* map the registers */
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err_clk;
+ }
+
+ i2c->ioarea = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+
+ if (i2c->ioarea == NULL) {
+ dev_err(&pdev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err_clk;
+ }
+
+ i2c->regs = ioremap(res->start, resource_size(res));
+
+ if (i2c->regs == NULL) {
+ dev_err(&pdev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_ioarea;
+ }
+
+ dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+ i2c->regs, i2c->ioarea, res);
+
+ /* setup info block for the i2c core */
+
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &pdev->dev;
+
+ mfp_set_groupg(&pdev->dev);
+
+ clk_get_rate(i2c->clk);
+
+ ret = (i2c->clk.apbfreq)/(pdata->bus_freq * 5) - 1;
+ writel(ret & 0xffff, i2c->regs + DIVIDER);
+
+ /* find the IRQ for this unit (note, this relies on the init call to
+ * ensure no current IRQs pending
+ */
+
+ i2c->irq = ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ goto err_iomap;
+ }
+
+ ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_DISABLED | IRQF_SHARED,
+ dev_name(&pdev->dev), i2c);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ goto err_iomap;
+ }
+
+ /* Note, previous versions of the driver used i2c_add_adapter()
+ * to add the bus at any number. We now pass the bus number via
+ * the platform data, so if unset it will now default to always
+ * being bus 0.
+ */
+
+ i2c->adap.nr = pdata->bus_num;
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+ goto err_irq;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ dev_info(&pdev->dev, "%s: NUC900 I2C adapter\n",
+ dev_name(&i2c->adap.dev));
+ return 0;
+
+ err_irq:
+ free_irq(i2c->irq, i2c);
+
+ err_iomap:
+ iounmap(i2c->regs);
+
+ err_ioarea:
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+
+ err_clk:
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ err_noclk:
+ kfree(i2c);
+ return ret;
+}
+
+/* nuc900_i2c_remove
+ *
+ * called when device is removed from the bus
+*/
+
+static int __devexit nuc900_i2c_remove(struct platform_device *pdev)
+{
+ struct nuc900_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ free_irq(i2c->irq, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->regs);
+
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+ kfree(i2c);
+
+ return 0;
+}
+
+static struct platform_driver nuc900_i2c_driver = {
+ .probe = nuc900_i2c_probe,
+ .remove = __devexit_p(nuc900_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "nuc900-i2c0",
+ },
+};
+
+static int __init i2c_adap_nuc900_init(void)
+{
+ return platform_driver_register(&nuc900_i2c_driver);
+}
+
+static void __exit i2c_adap_nuc900_exit(void)
+{
+ platform_driver_unregister(&nuc900_i2c_driver);
+}
+subsys_initcall(i2c_adap_nuc900_init);
+module_exit(i2c_adap_nuc900_exit);
+
+MODULE_DESCRIPTION("NUC900 I2C Bus driver");
+MODULE_AUTHOR("Wan ZongShun, <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-i2c0");
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
new file mode 100644
index 00000000..1b46a9d9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -0,0 +1,427 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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.
+ */
+
+/*
+ * Device tree configuration:
+ *
+ * Required properties:
+ * - compatible : "opencores,i2c-ocores"
+ * - reg : bus address start and address range size of device
+ * - interrupts : interrupt number
+ * - regstep : size of device registers in bytes
+ * - clock-frequency : frequency of bus clock in Hz
+ *
+ * Example:
+ *
+ * i2c0: ocores@a0000000 {
+ * compatible = "opencores,i2c-ocores";
+ * reg = <0xa0000000 0x8>;
+ * interrupts = <10>;
+ *
+ * regstep = <1>;
+ * clock-frequency = <20000000>;
+ *
+ * -- Devices connected on this I2C bus get
+ * -- defined here; address- and size-cells
+ * -- apply to these child devices
+ *
+ * #address-cells = <1>;
+ * #size-cells = <0>;
+ *
+ * dummy@60 {
+ * compatible = "dummy";
+ * reg = <60>;
+ * };
+ * };
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-ocores.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+struct ocores_i2c {
+ void __iomem *base;
+ int regstep;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+ int clock_khz;
+};
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4 /* write only */
+#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
+
+#define OCI2C_CTRL_IEN 0x40
+#define OCI2C_CTRL_EN 0x80
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_IF 0x01
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_NACK 0x80
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg * i2c->regstep);
+}
+
+static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg * i2c->regstep);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up(&i2c->wait);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
+ i2c->state =
+ (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ } else
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+ /* end of msg? */
+ if (i2c->pos == msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) { /* end? */
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ u8 addr = (msg->addr << 1);
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ } else
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ } else {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ } else {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id)
+{
+ struct ocores_i2c *i2c = dev_id;
+
+ ocores_process(i2c);
+
+ return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA,
+ (i2c->msg->addr << 1) |
+ ((i2c->msg->flags & I2C_M_RD) ? 1:0));
+
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ))
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+ else
+ return -ETIMEDOUT;
+}
+
+static void ocores_init(struct ocores_i2c *i2c)
+{
+ int prescale;
+ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ prescale = (i2c->clock_khz / (5*100)) - 1;
+ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+};
+
+static struct i2c_adapter ocores_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ocores",
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &ocores_algorithm,
+};
+
+#ifdef CONFIG_OF
+static int ocores_i2c_of_probe(struct platform_device* pdev,
+ struct ocores_i2c* i2c)
+{
+ const __be32* val;
+
+ val = of_get_property(pdev->dev.of_node, "regstep", NULL);
+ if (!val) {
+ dev_err(&pdev->dev, "Missing required parameter 'regstep'");
+ return -ENODEV;
+ }
+ i2c->regstep = be32_to_cpup(val);
+
+ val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
+ if (!val) {
+ dev_err(&pdev->dev,
+ "Missing required parameter 'clock-frequency'");
+ return -ENODEV;
+ }
+ i2c->clock_khz = be32_to_cpup(val) / 1000;
+
+ return 0;
+}
+#else
+#define ocores_i2c_of_probe(pdev,i2c) -ENODEV
+#endif
+
+static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+{
+ struct ocores_i2c *i2c;
+ struct ocores_i2c_platform_data *pdata;
+ struct resource *res, *res2;
+ int ret;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ return -EBUSY;
+ }
+
+ i2c->base = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!i2c->base) {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ return -EIO;
+ }
+
+ pdata = pdev->dev.platform_data;
+ if (pdata) {
+ i2c->regstep = pdata->regstep;
+ i2c->clock_khz = pdata->clock_khz;
+ } else {
+ ret = ocores_i2c_of_probe(pdev, i2c);
+ if (ret)
+ return ret;
+ }
+
+ ocores_init(i2c);
+
+ init_waitqueue_head(&i2c->wait);
+ ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0,
+ pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ return ret;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = ocores_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ return ret;
+ }
+
+ /* add in known devices to the bus */
+ if (pdata) {
+ for (i = 0; i < pdata->num_devices; i++)
+ i2c_new_device(&i2c->adap, pdata->devices + i);
+ }
+
+ return 0;
+}
+
+static int __devexit ocores_i2c_remove(struct platform_device* pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+
+ /* disable i2c logic */
+ oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
+ & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ return 0;
+}
+
+static int ocores_i2c_resume(struct platform_device *pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+
+ ocores_init(i2c);
+
+ return 0;
+}
+#else
+#define ocores_i2c_suspend NULL
+#define ocores_i2c_resume NULL
+#endif
+
+static struct of_device_id ocores_i2c_match[] = {
+ { .compatible = "opencores,i2c-ocores", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ocores_i2c_match);
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:ocores-i2c");
+
+static struct platform_driver ocores_i2c_driver = {
+ .probe = ocores_i2c_probe,
+ .remove = __devexit_p(ocores_i2c_remove),
+ .suspend = ocores_i2c_suspend,
+ .resume = ocores_i2c_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ocores-i2c",
+ .of_match_table = ocores_i2c_match,
+ },
+};
+
+static int __init ocores_i2c_init(void)
+{
+ return platform_driver_register(&ocores_i2c_driver);
+}
+
+static void __exit ocores_i2c_exit(void)
+{
+ platform_driver_unregister(&ocores_i2c_driver);
+}
+
+module_init(ocores_i2c_init);
+module_exit(ocores_i2c_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
new file mode 100644
index 00000000..56dbe54e
--- /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__);
+ return -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 __devinit 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 __devinit 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
new file mode 100644
index 00000000..137e1a3b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -0,0 +1,1197 @@
+/*
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ * Tony Lindgren <tony@atomide.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * Juha Yrjölä <juha.yrjola@solidboot.com>
+ * Syed Khasim <x0khasim@ti.com>
+ * Nishant Menon <nm@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/i2c-omap.h>
+#include <linux/pm_runtime.h>
+
+/* I2C controller revisions */
+#define OMAP_I2C_REV_2 0x20
+
+/* I2C controller revisions present on specific hardware */
+#define OMAP_I2C_REV_ON_2430 0x36
+#define OMAP_I2C_REV_ON_3430 0x3C
+#define OMAP_I2C_REV_ON_4430 0x40
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
+enum {
+ OMAP_I2C_REV_REG = 0,
+ OMAP_I2C_IE_REG,
+ OMAP_I2C_STAT_REG,
+ OMAP_I2C_IV_REG,
+ OMAP_I2C_WE_REG,
+ OMAP_I2C_SYSS_REG,
+ OMAP_I2C_BUF_REG,
+ OMAP_I2C_CNT_REG,
+ OMAP_I2C_DATA_REG,
+ OMAP_I2C_SYSC_REG,
+ OMAP_I2C_CON_REG,
+ OMAP_I2C_OA_REG,
+ OMAP_I2C_SA_REG,
+ OMAP_I2C_PSC_REG,
+ OMAP_I2C_SCLL_REG,
+ OMAP_I2C_SCLH_REG,
+ OMAP_I2C_SYSTEST_REG,
+ OMAP_I2C_BUFSTAT_REG,
+ OMAP_I2C_REVNB_LO,
+ OMAP_I2C_REVNB_HI,
+ OMAP_I2C_IRQSTATUS_RAW,
+ OMAP_I2C_IRQENABLE_SET,
+ OMAP_I2C_IRQENABLE_CLR,
+};
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
+#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C WE wakeup enable register */
+#define OMAP_I2C_WE_XDR_WE (1 << 14) /* TX drain wakup */
+#define OMAP_I2C_WE_RDR_WE (1 << 13) /* RX drain wakeup */
+#define OMAP_I2C_WE_AAS_WE (1 << 9) /* Address as slave wakeup*/
+#define OMAP_I2C_WE_BF_WE (1 << 8) /* Bus free wakeup */
+#define OMAP_I2C_WE_STC_WE (1 << 6) /* Start condition wakeup */
+#define OMAP_I2C_WE_GC_WE (1 << 5) /* General call wakeup */
+#define OMAP_I2C_WE_DRDY_WE (1 << 3) /* TX/RX data ready wakeup */
+#define OMAP_I2C_WE_ARDY_WE (1 << 2) /* Reg access ready wakeup */
+#define OMAP_I2C_WE_NACK_WE (1 << 1) /* No acknowledgment wakeup */
+#define OMAP_I2C_WE_AL_WE (1 << 0) /* Arbitration lost wakeup */
+
+#define OMAP_I2C_WE_ALL (OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \
+ OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \
+ OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \
+ OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \
+ OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE)
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL 8
+#define OMAP_I2C_SCLH_HSSCLH 8
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+#endif
+
+/* OCP_SYSSTATUS bit definitions */
+#define SYSS_RESETDONE_MASK (1 << 0)
+
+/* OCP_SYSCONFIG bit definitions */
+#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8)
+#define SYSC_SIDLEMODE_MASK (0x3 << 3)
+#define SYSC_ENAWAKEUP_MASK (1 << 2)
+#define SYSC_SOFTRESET_MASK (1 << 1)
+#define SYSC_AUTOIDLE_MASK (1 << 0)
+
+#define SYSC_IDLEMODE_SMART 0x2
+#define SYSC_CLOCKACTIVITY_FCLK 0x2
+
+/* Errata definitions */
+#define I2C_OMAP_ERRATA_I207 (1 << 0)
+#define I2C_OMAP3_1P153 (1 << 1)
+
+struct omap_i2c_dev {
+ struct device *dev;
+ void __iomem *base; /* virtual */
+ int irq;
+ int reg_shift; /* bit shift for I2C register addresses */
+ struct completion cmd_complete;
+ struct resource *ioarea;
+ u32 latency; /* maximum mpu wkup latency */
+ void (*set_mpu_wkup_lat)(struct device *dev,
+ long latency);
+ u32 speed; /* Speed of bus in Khz */
+ u16 cmd_err;
+ u8 *buf;
+ u8 *regs;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ u8 fifo_size; /* use as flag and value
+ * fifo_size==0 implies no fifo
+ * if set, should be trsh+1
+ */
+ u8 rev;
+ 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;
+ u16 errata;
+};
+
+const static u8 reg_map[] = {
+ [OMAP_I2C_REV_REG] = 0x00,
+ [OMAP_I2C_IE_REG] = 0x01,
+ [OMAP_I2C_STAT_REG] = 0x02,
+ [OMAP_I2C_IV_REG] = 0x03,
+ [OMAP_I2C_WE_REG] = 0x03,
+ [OMAP_I2C_SYSS_REG] = 0x04,
+ [OMAP_I2C_BUF_REG] = 0x05,
+ [OMAP_I2C_CNT_REG] = 0x06,
+ [OMAP_I2C_DATA_REG] = 0x07,
+ [OMAP_I2C_SYSC_REG] = 0x08,
+ [OMAP_I2C_CON_REG] = 0x09,
+ [OMAP_I2C_OA_REG] = 0x0a,
+ [OMAP_I2C_SA_REG] = 0x0b,
+ [OMAP_I2C_PSC_REG] = 0x0c,
+ [OMAP_I2C_SCLL_REG] = 0x0d,
+ [OMAP_I2C_SCLH_REG] = 0x0e,
+ [OMAP_I2C_SYSTEST_REG] = 0x0f,
+ [OMAP_I2C_BUFSTAT_REG] = 0x10,
+};
+
+const static u8 omap4_reg_map[] = {
+ [OMAP_I2C_REV_REG] = 0x04,
+ [OMAP_I2C_IE_REG] = 0x2c,
+ [OMAP_I2C_STAT_REG] = 0x28,
+ [OMAP_I2C_IV_REG] = 0x34,
+ [OMAP_I2C_WE_REG] = 0x34,
+ [OMAP_I2C_SYSS_REG] = 0x90,
+ [OMAP_I2C_BUF_REG] = 0x94,
+ [OMAP_I2C_CNT_REG] = 0x98,
+ [OMAP_I2C_DATA_REG] = 0x9c,
+ [OMAP_I2C_SYSC_REG] = 0x10,
+ [OMAP_I2C_CON_REG] = 0xa4,
+ [OMAP_I2C_OA_REG] = 0xa8,
+ [OMAP_I2C_SA_REG] = 0xac,
+ [OMAP_I2C_PSC_REG] = 0xb0,
+ [OMAP_I2C_SCLL_REG] = 0xb4,
+ [OMAP_I2C_SCLH_REG] = 0xb8,
+ [OMAP_I2C_SYSTEST_REG] = 0xbC,
+ [OMAP_I2C_BUFSTAT_REG] = 0xc0,
+ [OMAP_I2C_REVNB_LO] = 0x00,
+ [OMAP_I2C_REVNB_HI] = 0x04,
+ [OMAP_I2C_IRQSTATUS_RAW] = 0x24,
+ [OMAP_I2C_IRQENABLE_SET] = 0x2c,
+ [OMAP_I2C_IRQENABLE_CLR] = 0x30,
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base +
+ (i2c_dev->regs[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 +
+ (i2c_dev->regs[reg] << i2c_dev->reg_shift));
+}
+
+static void omap_i2c_unidle(struct omap_i2c_dev *dev)
+{
+ struct platform_device *pdev;
+ struct omap_i2c_bus_platform_data *pdata;
+
+ WARN_ON(!dev->idle);
+
+ pdev = to_platform_device(dev->dev);
+ pdata = pdev->dev.platform_data;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ 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);
+}
+
+static void omap_i2c_idle(struct omap_i2c_dev *dev)
+{
+ struct platform_device *pdev;
+ struct omap_i2c_bus_platform_data *pdata;
+ u16 iv;
+
+ WARN_ON(dev->idle);
+
+ pdev = to_platform_device(dev->dev);
+ pdata = pdev->dev.platform_data;
+
+ dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ if (dev->rev >= OMAP_I2C_REV_ON_4430)
+ omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
+ else
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+
+ if (dev->rev < OMAP_I2C_REV_2) {
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
+ } else {
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
+
+ /* Flush posted write before the dev->idle store occurs */
+ omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ }
+ dev->idle = 1;
+
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+ 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;
+ struct clk *fclk;
+
+ 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. */
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+ SYSS_RESETDONE_MASK)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting "
+ "for controller reset\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ /* SYSC register is cleared by the reset; rewrite it */
+ if (dev->rev == OMAP_I2C_REV_ON_2430) {
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
+ SYSC_AUTOIDLE_MASK);
+
+ } else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
+ dev->syscstate = SYSC_AUTOIDLE_MASK;
+ dev->syscstate |= SYSC_ENAWAKEUP_MASK;
+ dev->syscstate |= (SYSC_IDLEMODE_SMART <<
+ __ffs(SYSC_SIDLEMODE_MASK));
+ dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK <<
+ __ffs(SYSC_CLOCKACTIVITY_MASK));
+
+ 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.
+ */
+ 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);
+
+ if (cpu_class_is_omap1()) {
+ /*
+ * The I2C functional clock is the armxor_ck, so there's
+ * no need to get "armxor_ck" separately. Now, if OMAP2420
+ * always returns 12MHz for the functional clock, we can
+ * do this bit unconditionally.
+ */
+ fclk = clk_get(dev->dev, "fck");
+ fclk_rate = clk_get_rate(fclk);
+ clk_put(fclk);
+
+ /* TRM for 5912 says the I2C clock must be prescaled to be
+ * between 7 - 12 MHz. The XOR input clock is typically
+ * 12, 13 or 19.2 MHz. So we should have code that produces:
+ *
+ * XOR MHz Divider Prescaler
+ * 12 1 0
+ * 13 2 1
+ * 19.2 2 1
+ */
+ if (fclk_rate > 12000000)
+ psc = fclk_rate / 12000000;
+ }
+
+ if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
+
+ /*
+ * HSI2C controller internal clk rate should be 19.2 Mhz for
+ * HS and for all modes on 2430. On 34xx we can use lower rate
+ * to get longer filter period for better noise suppression.
+ * The filter is iclk (fclk for HS) period.
+ */
+ if (dev->speed > 400 || cpu_is_omap2430())
+ internal_clk = 19200;
+ else if (dev->speed > 100)
+ internal_clk = 9600;
+ else
+ internal_clk = 4000;
+ fclk = clk_get(dev->dev, "fck");
+ fclk_rate = clk_get_rate(fclk) / 1000;
+ clk_put(fclk);
+
+ /* Compute prescaler divisor */
+ psc = fclk_rate / internal_clk;
+ psc = psc - 1;
+
+ /* If configured for High Speed */
+ if (dev->speed > 400) {
+ unsigned long scl;
+
+ /* For first phase of HS mode */
+ scl = internal_clk / 400;
+ fsscll = scl - (scl / 3) - 7;
+ fssclh = (scl / 3) - 5;
+
+ /* For second phase of HS mode */
+ scl = fclk_rate / dev->speed;
+ hsscll = scl - (scl / 3) - 7;
+ hssclh = (scl / 3) - 5;
+ } else if (dev->speed > 100) {
+ unsigned long scl;
+
+ /* Fast mode */
+ scl = internal_clk / dev->speed;
+ fsscll = scl - (scl / 3) - 7;
+ fssclh = (scl / 3) - 5;
+ } else {
+ /* Standard mode */
+ fsscll = internal_clk / (dev->speed * 2) - 7;
+ fssclh = internal_clk / (dev->speed * 2) - 5;
+ }
+ scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+ sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+ } else {
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+ scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+ sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+ }
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+ /* SCL low and high time values */
+ 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. 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);
+
+ dev->errata = 0;
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx())
+ dev->errata |= I2C_OMAP_ERRATA_I207;
+
+ /* Enable interrupts */
+ 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_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;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int r;
+ u16 w;
+
+ dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+ /* Clear the FIFO Buffers */
+ w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+ w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+ /* High speed configuration */
+ if (dev->speed > 400)
+ w |= OMAP_I2C_CON_OPMODE_HS;
+
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+
+ if (!dev->b_hw && stop)
+ w |= OMAP_I2C_CON_STP;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ /*
+ * Don't write stt and stp together on some hardware.
+ */
+ if (dev->b_hw && stop) {
+ unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
+ u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ while (con & OMAP_I2C_CON_STT) {
+ con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+
+ /* Let the user know if i2c is in a bad state */
+ if (time_after(jiffies, delay)) {
+ dev_err(dev->dev, "controller timed out "
+ "waiting for start condition to finish\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ w |= OMAP_I2C_CON_STP;
+ w &= ~OMAP_I2C_CON_STT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+
+ /*
+ * REVISIT: We should abort the transfer on signals, but the bus goes
+ * into arbitration and we're currently unable to recover from it.
+ */
+ r = wait_for_completion_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ omap_i2c_init(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (likely(!dev->cmd_err))
+ return 0;
+
+ /* We have an error */
+ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+ OMAP_I2C_STAT_XUDF)) {
+ omap_i2c_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int r;
+
+ omap_i2c_unidle(dev);
+
+ r = omap_i2c_wait_for_bb(dev);
+ if (r < 0)
+ goto out;
+
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+
+ for (i = 0; i < num; i++) {
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, -1);
+
+ if (r == 0)
+ r = num;
+
+ omap_i2c_wait_for_bb(dev);
+out:
+ omap_i2c_idle(dev);
+ return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
+{
+ dev->cmd_err |= err;
+ complete(&dev->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
+{
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+}
+
+static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
+{
+ /*
+ * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
+ * Not applicable for OMAP4.
+ * Under certain rare conditions, RDR could be set again
+ * when the bus is busy, then ignore the interrupt and
+ * clear the interrupt.
+ */
+ if (stat & OMAP_I2C_STAT_RDR) {
+ /* Step 1: If RDR is set, clear it */
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+
+ /* Step 2: */
+ if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
+ & OMAP_I2C_STAT_BB)) {
+
+ /* Step 3: */
+ if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
+ & OMAP_I2C_STAT_RDR) {
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+ dev_dbg(dev->dev, "RDR when bus is busy.\n");
+ }
+
+ }
+ }
+}
+
+/* rev1 devices are apparently only on some 15xx */
+#ifdef CONFIG_ARCH_OMAP15XX
+
+static irqreturn_t
+omap_i2c_rev1_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 iv, w;
+
+ if (dev->idle)
+ return IRQ_NONE;
+
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x00: /* None */
+ break;
+ case 0x01: /* Arbitration lost */
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ break;
+ case 0x03: /* Register access ready */
+ omap_i2c_complete_cmd(dev, 0);
+ break;
+ case 0x04: /* Receive data ready */
+ if (dev->buf_len) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+ break;
+ case 0x05: /* Transmit data ready */
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+ break;
+ default:
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+#else
+#define omap_i2c_rev1_isr NULL
+#endif
+
+/*
+ * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
+ * data to DATA_REG. Otherwise some data bytes can be lost while transferring
+ * them from the memory to the I2C interface.
+ */
+static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
+{
+ unsigned long timeout = 10000;
+
+ while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
+ if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
+ OMAP_I2C_STAT_XDR));
+ *err |= OMAP_I2C_STAT_XUDF;
+ return -ETIMEDOUT;
+ }
+
+ cpu_relax();
+ *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ }
+
+ if (!timeout) {
+ dev_err(dev->dev, "timeout waiting on XUDF bit\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+static irqreturn_t
+omap_i2c_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 bits;
+ u16 stat, w;
+ int err, count = 0;
+
+ if (dev->idle)
+ return IRQ_NONE;
+
+ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+ dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ err = 0;
+complete:
+ /*
+ * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
+ * acked after the data operation is complete.
+ * Ref: TRM SWPU114Q Figure 18-31
+ */
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+ ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+
+ if (stat & OMAP_I2C_STAT_NACK) {
+ err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
+ }
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ err |= OMAP_I2C_STAT_AL;
+ }
+ /*
+ * ProDB0017052: Clear ARDY bit twice
+ */
+ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+ OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, stat &
+ (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
+ OMAP_I2C_STAT_ARDY));
+ omap_i2c_complete_cmd(dev, err);
+ return IRQ_HANDLED;
+ }
+ if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+ u8 num_bytes = 1;
+
+ if (dev->errata & I2C_OMAP_ERRATA_I207)
+ i2c_omap_errata_i207(dev, stat);
+
+ if (dev->fifo_size) {
+ if (stat & OMAP_I2C_STAT_RRDY)
+ num_bytes = dev->fifo_size;
+ else /* read RXSTAT on RDR interrupt */
+ num_bytes = (omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG)
+ >> 8) & 0x3F;
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ if (dev->buf_len) {
+ *dev->buf++ = w;
+ dev->buf_len--;
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (cpu_class_is_omap1() ||
+ cpu_is_omap2420()) {
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_RRDY)
+ dev_err(dev->dev,
+ "RRDY IRQ while no data"
+ " requested\n");
+ if (stat & OMAP_I2C_STAT_RDR)
+ dev_err(dev->dev,
+ "RDR IRQ while no data"
+ " requested\n");
+ break;
+ }
+ }
+ omap_i2c_ack_stat(dev,
+ stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+ continue;
+ }
+ if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ if (stat & OMAP_I2C_STAT_XRDY)
+ num_bytes = dev->fifo_size;
+ else /* read TXSTAT on XDR interrupt */
+ num_bytes = omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG)
+ & 0x3F;
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = 0;
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (cpu_class_is_omap1() ||
+ cpu_is_omap2420()) {
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_XRDY)
+ dev_err(dev->dev,
+ "XRDY IRQ while no "
+ "data to send\n");
+ if (stat & OMAP_I2C_STAT_XDR)
+ dev_err(dev->dev,
+ "XDR IRQ while no "
+ "data to send\n");
+ break;
+ }
+
+ if ((dev->errata & I2C_OMAP3_1P153) &&
+ errata_omap3_1p153(dev, &stat, &err))
+ goto complete;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ }
+ omap_i2c_ack_stat(dev,
+ stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err(dev->dev, "Receive overrun\n");
+ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ }
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err(dev->dev, "Transmit underflow\n");
+ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static int __devinit
+omap_i2c_probe(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+ irq_handler_t isr;
+ int r;
+ u32 speed = 0;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, resource_size(mem),
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ if (pdata != NULL) {
+ speed = pdata->clkrate;
+ dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
+ } else {
+ speed = 100; /* Default speed */
+ dev->set_mpu_wkup_lat = NULL;
+ }
+
+ dev->speed = speed;
+ dev->idle = 1;
+ dev->dev = &pdev->dev;
+ dev->irq = irq->start;
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (!dev->base) {
+ r = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ if (cpu_is_omap7xx())
+ dev->reg_shift = 1;
+ else if (cpu_is_omap44xx())
+ dev->reg_shift = 0;
+ else
+ dev->reg_shift = 2;
+
+ if (cpu_is_omap44xx())
+ dev->regs = (u8 *) omap4_reg_map;
+ else
+ dev->regs = (u8 *) reg_map;
+
+ pm_runtime_enable(&pdev->dev);
+ omap_i2c_unidle(dev);
+
+ dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+
+ if (dev->rev <= OMAP_I2C_REV_ON_3430)
+ dev->errata |= I2C_OMAP3_1P153;
+
+ if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
+ u16 s;
+
+ /* Set up the fifo size - Get total size */
+ s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
+ dev->fifo_size = 0x8 << s;
+
+ /*
+ * Set up notification threshold as half the total available
+ * size. This is to ensure that we can handle the status on int
+ * call back latencies.
+ */
+ if (dev->rev >= OMAP_I2C_REV_ON_4430) {
+ dev->fifo_size = 0;
+ dev->b_hw = 0; /* Disable hardware fixes */
+ } else {
+ dev->fifo_size = (dev->fifo_size / 2);
+ dev->b_hw = 1; /* Enable hardware fixes */
+ }
+ /* calculate wakeup latency constraint for MPU */
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->latency = (1000000 * dev->fifo_size) /
+ (1000 * speed / 8);
+ }
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_init(dev);
+
+ isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr;
+ r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+
+ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
+ pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
+ omap_i2c_idle(dev);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(dev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ omap_i2c_idle(dev);
+ iounmap(dev->base);
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return r;
+}
+
+static int
+omap_i2c_remove(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_irq(dev->irq, dev);
+ i2c_del_adapter(&dev->adapter);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ iounmap(dev->base);
+ kfree(dev);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+}
+
+#ifdef CONFIG_SUSPEND
+static int omap_i2c_suspend(struct device *dev)
+{
+ if (!pm_runtime_suspended(dev))
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
+ dev->bus->pm->runtime_suspend(dev);
+
+ return 0;
+}
+
+static int omap_i2c_resume(struct device *dev)
+{
+ if (!pm_runtime_suspended(dev))
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
+ dev->bus->pm->runtime_resume(dev);
+
+ return 0;
+}
+
+static struct dev_pm_ops omap_i2c_pm_ops = {
+ .suspend = omap_i2c_suspend,
+ .resume = omap_i2c_resume,
+};
+#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
+#else
+#define OMAP_I2C_PM_OPS NULL
+#endif
+
+static struct platform_driver omap_i2c_driver = {
+ .probe = omap_i2c_probe,
+ .remove = omap_i2c_remove,
+ .driver = {
+ .name = "omap_i2c",
+ .owner = THIS_MODULE,
+ .pm = OMAP_I2C_PM_OPS,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+ return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap_i2c");
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
new file mode 100644
index 00000000..4b95f7a6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -0,0 +1,281 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport-light.c I2C bus over parallel port *
+ * ------------------------------------------------------------------------ *
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+
+ Based on older i2c-velleman.c driver
+ Copyright (C) 1995-2000 Simon G. Vogl
+ With some changes from:
+ Frodo Looijaard <frodol@dds.nl>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ 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/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 <linux/io.h>
+#include "i2c-parport.h"
+
+#define DEFAULT_BASE 0x378
+#define DRVNAME "i2c-parport-light"
+
+static struct platform_device *pdev;
+
+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)
+{
+ outb(d, base+p);
+}
+
+static inline unsigned char port_read(unsigned char p)
+{
+ return inb(base+p);
+}
+
+/* ----- Unified line operation functions --------------------------------- */
+
+static inline void line_set(int state, const struct lineop *op)
+{
+ u8 oldval = port_read(op->port);
+
+ /* Touch only the bit(s) needed */
+ if ((op->inverted && !state) || (!op->inverted && state))
+ port_write(op->port, oldval | op->val);
+ else
+ port_write(op->port, oldval & ~op->val);
+}
+
+static inline int line_get(const struct lineop *op)
+{
+ u8 oldval = port_read(op->port);
+
+ return ((op->inverted && (oldval & op->val) != op->val)
+ || (!op->inverted && (oldval & op->val) == op->val));
+}
+
+/* ----- I2C algorithm call-back functions and structures ----------------- */
+
+static void parport_setscl(void *data, int state)
+{
+ line_set(state, &adapter_parm[type].setscl);
+}
+
+static void parport_setsda(void *data, int state)
+{
+ line_set(state, &adapter_parm[type].setsda);
+}
+
+static int parport_getscl(void *data)
+{
+ return line_get(&adapter_parm[type].getscl);
+}
+
+static int parport_getsda(void *data)
+{
+ return line_get(&adapter_parm[type].getsda);
+}
+
+/* Encapsulate the functions above in the correct structure
+ Note that getscl will be set to NULL by the attaching code for adapters
+ that cannot read SCL back */
+static struct i2c_algo_bit_data parport_algo_data = {
+ .setsda = parport_setsda,
+ .setscl = parport_setscl,
+ .getsda = parport_getsda,
+ .getscl = parport_getscl,
+ .udelay = 50,
+ .timeout = HZ,
+};
+
+/* ----- Driver registration ---------------------------------------------- */
+
+static struct i2c_adapter parport_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON,
+ .algo_data = &parport_algo_data,
+ .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 = PORT_CTRL,
+};
+
+static int __devinit i2c_parport_probe(struct platform_device *pdev)
+{
+ int err;
+
+ /* Reset hardware to a sane state (SCL and SDA high) */
+ parport_setsda(NULL, 1);
+ parport_setscl(NULL, 1);
+ /* Other init if needed (power on...) */
+ 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) {
+ dev_err(&pdev->dev, "Unable to register with I2C\n");
+ 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...) */
+ if (adapter_parm[type].init.val)
+ line_set(0, &adapter_parm[type].init);
+
+ return 0;
+}
+
+static struct platform_driver i2c_parport_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = i2c_parport_probe,
+ .remove = __devexit_p(i2c_parport_remove),
+};
+
+static int __init i2c_parport_device_add(u16 address)
+{
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, -1);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
+static int __init i2c_parport_init(void)
+{
+ int err;
+
+ if (type < 0) {
+ printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
+ return -ENODEV;
+ }
+
+ if (type >= ARRAY_SIZE(adapter_parm)) {
+ printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
+ return -ENODEV;
+ }
+
+ if (base == 0) {
+ pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
+ base = DEFAULT_BASE;
+ }
+
+ 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;
+
+ /* Sets global pdev as a side effect */
+ err = i2c_parport_device_add(base);
+ if (err)
+ goto exit_release;
+
+ err = platform_driver_register(&i2c_parport_driver);
+ if (err)
+ goto exit_device;
+
+ return 0;
+
+exit_device:
+ platform_device_unregister(pdev);
+exit_release:
+ release_region(base, 3);
+ return err;
+}
+
+static void __exit i2c_parport_exit(void)
+{
+ platform_driver_unregister(&i2c_parport_driver);
+ platform_device_unregister(pdev);
+ release_region(base, 3);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("I2C bus over parallel port (light)");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_parport_init);
+module_exit(i2c_parport_exit);
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
new file mode 100644
index 00000000..24565687
--- /dev/null
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -0,0 +1,306 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport.c I2C bus over parallel port *
+ * ------------------------------------------------------------------------ *
+ Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
+
+ Based on older i2c-philips-par.c driver
+ Copyright (C) 1995-2000 Simon G. Vogl
+ With some changes from:
+ Frodo Looijaard <frodol@dds.nl>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ 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/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 <linux/list.h>
+#include <linux/mutex.h>
+#include "i2c-parport.h"
+
+/* ----- Device list ------------------------------------------------------ */
+
+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 list_head node;
+};
+
+static LIST_HEAD(adapter_list);
+static DEFINE_MUTEX(adapter_list_lock);
+
+/* ----- Low-level parallel port access ----------------------------------- */
+
+static void port_write_data(struct parport *p, unsigned char d)
+{
+ parport_write_data(p, d);
+}
+
+static void port_write_control(struct parport *p, unsigned char d)
+{
+ parport_write_control(p, d);
+}
+
+static unsigned char port_read_data(struct parport *p)
+{
+ return parport_read_data(p);
+}
+
+static unsigned char port_read_status(struct parport *p)
+{
+ return parport_read_status(p);
+}
+
+static unsigned char port_read_control(struct parport *p)
+{
+ return parport_read_control(p);
+}
+
+static void (* const port_write[])(struct parport *, unsigned char) = {
+ port_write_data,
+ NULL,
+ port_write_control,
+};
+
+static unsigned char (* const port_read[])(struct parport *) = {
+ port_read_data,
+ port_read_status,
+ port_read_control,
+};
+
+/* ----- Unified line operation functions --------------------------------- */
+
+static inline void line_set(struct parport *data, int state,
+ const struct lineop *op)
+{
+ u8 oldval = port_read[op->port](data);
+
+ /* Touch only the bit(s) needed */
+ if ((op->inverted && !state) || (!op->inverted && state))
+ port_write[op->port](data, oldval | op->val);
+ else
+ port_write[op->port](data, oldval & ~op->val);
+}
+
+static inline int line_get(struct parport *data,
+ const struct lineop *op)
+{
+ u8 oldval = port_read[op->port](data);
+
+ return ((op->inverted && (oldval & op->val) != op->val)
+ || (!op->inverted && (oldval & op->val) == op->val));
+}
+
+/* ----- I2C algorithm call-back functions and structures ----------------- */
+
+static void parport_setscl(void *data, int state)
+{
+ line_set((struct parport *) data, state, &adapter_parm[type].setscl);
+}
+
+static void parport_setsda(void *data, int state)
+{
+ line_set((struct parport *) data, state, &adapter_parm[type].setsda);
+}
+
+static int parport_getscl(void *data)
+{
+ return line_get((struct parport *) data, &adapter_parm[type].getscl);
+}
+
+static int parport_getsda(void *data)
+{
+ return line_get((struct parport *) data, &adapter_parm[type].getsda);
+}
+
+/* Encapsulate the functions above in the correct structure.
+ Note that this is only a template, from which the real structures are
+ copied. The attaching code will set getscl to NULL for adapters that
+ cannot read SCL back, and will also make the data field point to
+ the parallel port structure. */
+static const struct i2c_algo_bit_data parport_algo_data = {
+ .setsda = parport_setsda,
+ .setscl = parport_setscl,
+ .getsda = parport_getsda,
+ .getscl = parport_getscl,
+ .udelay = 10, /* ~50 kbps */
+ .timeout = HZ,
+};
+
+/* ----- 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;
+
+ adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
+ if (adapter == NULL) {
+ printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
+ return;
+ }
+
+ pr_debug("i2c-parport: attaching to %s\n", port->name);
+ parport_disable_irq(port);
+ adapter->pdev = parport_register_device(port, "i2c-parport",
+ NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
+ if (!adapter->pdev) {
+ printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
+ goto err_free;
+ }
+
+ /* Fill the rest of the structure */
+ adapter->adapter.owner = THIS_MODULE;
+ adapter->adapter.class = I2C_CLASS_HWMON;
+ strlcpy(adapter->adapter.name, "Parallel port adapter",
+ sizeof(adapter->adapter.name));
+ adapter->algo_data = parport_algo_data;
+ /* Slow down if we can't sense SCL */
+ if (!adapter_parm[type].getscl.val) {
+ adapter->algo_data.getscl = NULL;
+ adapter->algo_data.udelay = 50; /* ~10 kbps */
+ }
+ adapter->algo_data.data = port;
+ adapter->adapter.algo_data = &adapter->algo_data;
+ adapter->adapter.dev.parent = port->physport->dev;
+
+ if (parport_claim_or_block(adapter->pdev) < 0) {
+ printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
+ goto err_unregister;
+ }
+
+ /* Reset hardware to a sane state (SCL and SDA high) */
+ parport_setsda(port, 1);
+ parport_setscl(port, 1);
+ /* Other init if needed (power on...) */
+ 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 err_unregister;
+ }
+
+ /* 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 */
+ mutex_lock(&adapter_list_lock);
+ list_add_tail(&adapter->node, &adapter_list);
+ mutex_unlock(&adapter_list_lock);
+ return;
+
+ err_unregister:
+ parport_release(adapter->pdev);
+ parport_unregister_device(adapter->pdev);
+ err_free:
+ kfree(adapter);
+}
+
+static void i2c_parport_detach(struct parport *port)
+{
+ struct i2c_par *adapter, *_n;
+
+ /* Walk the list */
+ mutex_lock(&adapter_list_lock);
+ list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
+ 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...) */
+ if (adapter_parm[type].init.val)
+ line_set(port, 0, &adapter_parm[type].init);
+
+ parport_release(adapter->pdev);
+ parport_unregister_device(adapter->pdev);
+ list_del(&adapter->node);
+ kfree(adapter);
+ }
+ }
+ mutex_unlock(&adapter_list_lock);
+}
+
+static struct parport_driver i2c_parport_driver = {
+ .name = "i2c-parport",
+ .attach = i2c_parport_attach,
+ .detach = i2c_parport_detach,
+};
+
+/* ----- Module loading, unloading and information ------------------------ */
+
+static int __init i2c_parport_init(void)
+{
+ if (type < 0) {
+ printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
+ return -ENODEV;
+ }
+
+ if (type >= ARRAY_SIZE(adapter_parm)) {
+ printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+ return -ENODEV;
+ }
+
+ return parport_register_driver(&i2c_parport_driver);
+}
+
+static void __exit i2c_parport_exit(void)
+{
+ parport_unregister_driver(&i2c_parport_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("I2C bus over parallel port");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_parport_init);
+module_exit(i2c_parport_exit);
diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h
new file mode 100644
index 00000000..3fe65230
--- /dev/null
+++ b/drivers/i2c/busses/i2c-parport.h
@@ -0,0 +1,110 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport.h I2C bus over parallel port *
+ * ------------------------------------------------------------------------ *
+ 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
+ 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.
+ * ------------------------------------------------------------------------ */
+
+#define PORT_DATA 0
+#define PORT_STAT 1
+#define PORT_CTRL 2
+
+struct lineop {
+ u8 val;
+ u8 port;
+ u8 inverted;
+};
+
+struct adapter_parm {
+ struct lineop setsda;
+ struct lineop setscl;
+ struct lineop getsda;
+ struct lineop getscl;
+ struct lineop init;
+ unsigned int smbus_alert:1;
+};
+
+static const struct adapter_parm adapter_parm[] = {
+ /* type 0: Philips adapter */
+ {
+ .setsda = { 0x80, PORT_DATA, 1 },
+ .setscl = { 0x08, PORT_CTRL, 0 },
+ .getsda = { 0x80, PORT_STAT, 0 },
+ .getscl = { 0x08, PORT_STAT, 0 },
+ },
+ /* type 1: home brew teletext adapter */
+ {
+ .setsda = { 0x02, PORT_DATA, 0 },
+ .setscl = { 0x01, PORT_DATA, 0 },
+ .getsda = { 0x80, PORT_STAT, 1 },
+ },
+ /* type 2: Velleman K8000 adapter */
+ {
+ .setsda = { 0x02, PORT_CTRL, 1 },
+ .setscl = { 0x08, PORT_CTRL, 1 },
+ .getsda = { 0x10, PORT_STAT, 0 },
+ },
+ /* type 3: ELV adapter */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x40, PORT_STAT, 1 },
+ .getscl = { 0x08, PORT_STAT, 1 },
+ },
+ /* type 4: ADM1032 evaluation board */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x10, PORT_STAT, 1 },
+ .init = { 0xf0, PORT_DATA, 0 },
+ .smbus_alert = 1,
+ },
+ /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x10, PORT_STAT, 1 },
+ },
+ /* type 6: Barco LPT->DVI (K5800236) adapter */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x20, PORT_STAT, 0 },
+ .getscl = { 0x40, PORT_STAT, 0 },
+ .init = { 0xfc, PORT_DATA, 0 },
+ },
+ /* type 7: One For All JP1 parallel port adapter */
+ {
+ .setsda = { 0x01, PORT_DATA, 0 },
+ .setscl = { 0x02, PORT_DATA, 0 },
+ .getsda = { 0x80, PORT_STAT, 1 },
+ .init = { 0x04, PORT_DATA, 1 },
+ },
+};
+
+static int type = -1;
+module_param(type, int, 0);
+MODULE_PARM_DESC(type,
+ "Type of adapter:\n"
+ " 0 = Philips adapter\n"
+ " 1 = home brew teletext adapter\n"
+ " 2 = Velleman K8000 adapter\n"
+ " 3 = ELV adapter\n"
+ " 4 = ADM1032 evaluation board\n"
+ " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
+ " 6 = Barco LPT->DVI (K5800236) adapter\n"
+ " 7 = One For All JP1 parallel port adapter\n"
+);
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
new file mode 100644
index 00000000..837b8c1a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * SMBus host driver for PA Semi PWRficient
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+static struct pci_driver pasemi_smb_driver;
+
+struct pasemi_smbus {
+ struct pci_dev *dev;
+ struct i2c_adapter adapter;
+ unsigned long base;
+ int size;
+};
+
+/* Register offsets */
+#define REG_MTXFIFO 0x00
+#define REG_MRXFIFO 0x04
+#define REG_SMSTA 0x14
+#define REG_CTL 0x1c
+
+/* Register defs */
+#define MTXFIFO_READ 0x00000400
+#define MTXFIFO_STOP 0x00000200
+#define MTXFIFO_START 0x00000100
+#define MTXFIFO_DATA_M 0x000000ff
+
+#define MRXFIFO_EMPTY 0x00000100
+#define MRXFIFO_DATA_M 0x000000ff
+
+#define SMSTA_XEN 0x08000000
+#define SMSTA_MTN 0x00200000
+
+#define CTL_MRR 0x00000400
+#define CTL_MTR 0x00000200
+#define CTL_CLK_M 0x000000ff
+
+#define CLK_100K_DIV 84
+#define CLK_400K_DIV 21
+
+static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
+{
+ dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n",
+ smbus->base + reg, val);
+ outl(val, smbus->base + reg);
+}
+
+static inline int reg_read(struct pasemi_smbus *smbus, int reg)
+{
+ int ret;
+ ret = inl(smbus->base + reg);
+ dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n",
+ smbus->base + reg, ret);
+ return ret;
+}
+
+#define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg))
+#define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO)
+
+static void pasemi_smb_clear(struct pasemi_smbus *smbus)
+{
+ unsigned int status;
+
+ status = reg_read(smbus, REG_SMSTA);
+ reg_write(smbus, REG_SMSTA, status);
+}
+
+static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
+{
+ int timeout = 10;
+ unsigned int status;
+
+ status = reg_read(smbus, REG_SMSTA);
+
+ while (!(status & SMSTA_XEN) && timeout--) {
+ msleep(1);
+ status = reg_read(smbus, REG_SMSTA);
+ }
+
+ /* Got NACK? */
+ if (status & SMSTA_MTN)
+ return -ENXIO;
+
+ if (timeout < 0) {
+ dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
+ reg_write(smbus, REG_SMSTA, status);
+ return -ETIME;
+ }
+
+ /* Clear XEN */
+ reg_write(smbus, REG_SMSTA, SMSTA_XEN);
+
+ return 0;
+}
+
+static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
+ struct i2c_msg *msg, int stop)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ int read, i, err;
+ u32 rd;
+
+ read = msg->flags & I2C_M_RD ? 1 : 0;
+
+ TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read);
+
+ if (read) {
+ TXFIFO_WR(smbus, msg->len | MTXFIFO_READ |
+ (stop ? MTXFIFO_STOP : 0));
+
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+
+ for (i = 0; i < msg->len; i++) {
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ msg->buf[i] = rd & MRXFIFO_DATA_M;
+ }
+ } else {
+ for (i = 0; i < msg->len - 1; i++)
+ TXFIFO_WR(smbus, msg->buf[i]);
+
+ TXFIFO_WR(smbus, msg->buf[msg->len-1] |
+ (stop ? MTXFIFO_STOP : 0));
+ }
+
+ return 0;
+
+ reset_out:
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+ return err;
+}
+
+static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ int ret, i;
+
+ pasemi_smb_clear(smbus);
+
+ ret = 0;
+
+ for (i = 0; i < num && !ret; i++)
+ ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
+
+ return ret ? ret : num;
+}
+
+static int pasemi_smb_xfer(struct i2c_adapter *adapter,
+ u16 addr, unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ unsigned int rd;
+ int read_flag, err;
+ int len = 0, i;
+
+ /* All our ops take 8-bit shifted addresses */
+ addr <<= 1;
+ read_flag = read_write == I2C_SMBUS_READ;
+
+ pasemi_smb_clear(smbus);
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START |
+ MTXFIFO_STOP);
+ break;
+ case I2C_SMBUS_BYTE:
+ TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START);
+ if (read_write)
+ TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ);
+ else
+ TXFIFO_WR(smbus, MTXFIFO_STOP | command);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP);
+ } else {
+ TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte);
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP);
+ } else {
+ TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8));
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 1 | MTXFIFO_READ);
+ rd = RXFIFO_RD(smbus);
+ len = min_t(u8, (rd & MRXFIFO_DATA_M),
+ I2C_SMBUS_BLOCK_MAX);
+ TXFIFO_WR(smbus, len | MTXFIFO_READ |
+ MTXFIFO_STOP);
+ } else {
+ len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX);
+ TXFIFO_WR(smbus, len);
+ for (i = 1; i < len; i++)
+ TXFIFO_WR(smbus, data->block[i]);
+ TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP);
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ read_write = I2C_SMBUS_READ;
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ);
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1);
+ read_write = I2C_SMBUS_READ;
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ TXFIFO_WR(smbus, len);
+ for (i = 1; i <= len; i++)
+ TXFIFO_WR(smbus, data->block[i]);
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ);
+ TXFIFO_WR(smbus, MTXFIFO_READ | 1);
+ rd = RXFIFO_RD(smbus);
+ len = min_t(u8, (rd & MRXFIFO_DATA_M),
+ I2C_SMBUS_BLOCK_MAX - len);
+ TXFIFO_WR(smbus, len | MTXFIFO_READ | MTXFIFO_STOP);
+ break;
+
+ default:
+ dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+ return -EINVAL;
+ }
+
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->byte = rd & MRXFIFO_DATA_M;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->word = rd & MRXFIFO_DATA_M;
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->word |= (rd & MRXFIFO_DATA_M) << 8;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ data->block[0] = len;
+ for (i = 1; i <= len; i ++) {
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->block[i] = rd & MRXFIFO_DATA_M;
+ }
+ break;
+ }
+
+ return 0;
+
+ reset_out:
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+ return err;
+}
+
+static u32 pasemi_smb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .master_xfer = pasemi_i2c_xfer,
+ .smbus_xfer = pasemi_smb_xfer,
+ .functionality = pasemi_smb_func,
+};
+
+static int __devinit pasemi_smb_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct pasemi_smbus *smbus;
+ int error;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+ return -ENODEV;
+
+ smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL);
+ if (!smbus)
+ return -ENOMEM;
+
+ smbus->dev = dev;
+ smbus->base = pci_resource_start(dev, 0);
+ smbus->size = pci_resource_len(dev, 0);
+
+ if (!request_region(smbus->base, smbus->size,
+ pasemi_smb_driver.name)) {
+ error = -EBUSY;
+ goto out_kfree;
+ }
+
+ smbus->adapter.owner = THIS_MODULE;
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+ "PA Semi SMBus adapter at 0x%lx", smbus->base);
+ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+ smbus->adapter.nr = PCI_FUNC(dev->devfn);
+
+ /* set up the sysfs linkage to our parent device */
+ smbus->adapter.dev.parent = &dev->dev;
+
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+
+ error = i2c_add_numbered_adapter(&smbus->adapter);
+ if (error)
+ goto out_release_region;
+
+ pci_set_drvdata(dev, smbus);
+
+ return 0;
+
+ out_release_region:
+ release_region(smbus->base, smbus->size);
+ out_kfree:
+ kfree(smbus);
+ return error;
+}
+
+static void __devexit pasemi_smb_remove(struct pci_dev *dev)
+{
+ struct pasemi_smbus *smbus = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&smbus->adapter);
+ release_region(smbus->base, smbus->size);
+ kfree(smbus);
+}
+
+static const struct pci_device_id pasemi_smb_ids[] = {
+ { PCI_DEVICE(0x1959, 0xa003) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_smb_ids);
+
+static struct pci_driver pasemi_smb_driver = {
+ .name = "i2c-pasemi",
+ .id_table = pasemi_smb_ids,
+ .probe = pasemi_smb_probe,
+ .remove = __devexit_p(pasemi_smb_remove),
+};
+
+static int __init pasemi_smb_init(void)
+{
+ return pci_register_driver(&pasemi_smb_driver);
+}
+
+static void __exit pasemi_smb_exit(void)
+{
+ pci_unregister_driver(&pasemi_smb_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
+
+module_init(pasemi_smb_init);
+module_exit(pasemi_smb_exit);
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
new file mode 100644
index 00000000..29933f87
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -0,0 +1,229 @@
+/*
+ * i2c-pca-isa.c driver for PCA9564 on ISA boards
+ * Copyright (C) 2004 Arcom Control Systems
+ * Copyright (C) 2008 Pengutronix
+ *
+ * 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/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/isa.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#define DRIVER "i2c-pca-isa"
+#define IO_SIZE 4
+
+static unsigned long base;
+static int irq = -1;
+
+/* Data sheet recommends 59kHz for 100kHz operation due to variation
+ * in the actual clock rate */
+static int clock = 59000;
+
+static struct i2c_adapter pca_isa_ops;
+static wait_queue_head_t pca_wait;
+
+static void pca_isa_writebyte(void *pd, int reg, int val)
+{
+#ifdef DEBUG_IO
+ static char *names[] = { "T/O", "DAT", "ADR", "CON" };
+ printk(KERN_DEBUG "*** write %s at %#lx <= %#04x\n", names[reg],
+ base+reg, val);
+#endif
+ outb(val, base+reg);
+}
+
+static int pca_isa_readbyte(void *pd, int reg)
+{
+ int res = inb(base+reg);
+#ifdef DEBUG_IO
+ {
+ static char *names[] = { "STA", "DAT", "ADR", "CON" };
+ printk(KERN_DEBUG "*** read %s => %#04x\n", names[reg], res);
+ }
+#endif
+ return res;
+}
+
+static int pca_isa_waitforcompletion(void *pd)
+{
+ unsigned long timeout;
+ long ret;
+
+ if (irq > -1) {
+ ret = wait_event_timeout(pca_wait,
+ pca_isa_readbyte(pd, I2C_PCA_CON)
+ & I2C_PCA_CON_SI, pca_isa_ops.timeout);
+ } else {
+ /* Do polling */
+ timeout = jiffies + pca_isa_ops.timeout;
+ do {
+ ret = time_before(jiffies, timeout);
+ if (pca_isa_readbyte(pd, I2C_PCA_CON)
+ & I2C_PCA_CON_SI)
+ break;
+ udelay(100);
+ } while (ret);
+ }
+
+ return ret > 0;
+}
+
+static void pca_isa_resetchip(void *pd)
+{
+ /* apparently only an external reset will do it. not a lot can be done */
+ printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
+}
+
+static irqreturn_t pca_handler(int this_irq, void *dev_id) {
+ wake_up(&pca_wait);
+ return IRQ_HANDLED;
+}
+
+static struct i2c_algo_pca_data pca_isa_data = {
+ /* .data intentionally left NULL, not needed with ISA */
+ .write_byte = pca_isa_writebyte,
+ .read_byte = pca_isa_readbyte,
+ .wait_for_completion = pca_isa_waitforcompletion,
+ .reset_chip = pca_isa_resetchip,
+};
+
+static struct i2c_adapter pca_isa_ops = {
+ .owner = THIS_MODULE,
+ .algo_data = &pca_isa_data,
+ .name = "PCA9564/PCA9665 ISA Adapter",
+ .timeout = HZ,
+};
+
+static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+{
+ int match = base != 0;
+
+ if (match) {
+ if (irq <= -1)
+ dev_warn(dev, "Using polling mode (specify irq)\n");
+ } else
+ dev_err(dev, "Please specify I/O base\n");
+
+ return match;
+}
+
+static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
+{
+ init_waitqueue_head(&pca_wait);
+
+ dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
+
+#ifdef CONFIG_PPC
+ if (check_legacy_ioport(base)) {
+ dev_err(dev, "I/O address %#08lx is not available\n", base);
+ goto out;
+ }
+#endif
+
+ if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
+ dev_err(dev, "I/O address %#08lx is in use\n", base);
+ goto out;
+ }
+
+ if (irq > -1) {
+ if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
+ dev_err(dev, "Request irq%d failed\n", irq);
+ goto out_region;
+ }
+ }
+
+ pca_isa_data.i2c_clock = clock;
+ if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
+ dev_err(dev, "Failed to add i2c bus\n");
+ goto out_irq;
+ }
+
+ return 0;
+
+ out_irq:
+ if (irq > -1)
+ free_irq(irq, &pca_isa_ops);
+ out_region:
+ release_region(base, IO_SIZE);
+ out:
+ return -ENODEV;
+}
+
+static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
+{
+ i2c_del_adapter(&pca_isa_ops);
+
+ if (irq > -1) {
+ disable_irq(irq);
+ free_irq(irq, &pca_isa_ops);
+ }
+ release_region(base, IO_SIZE);
+
+ return 0;
+}
+
+static struct isa_driver pca_isa_driver = {
+ .match = pca_isa_match,
+ .probe = pca_isa_probe,
+ .remove = __devexit_p(pca_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER,
+ }
+};
+
+static int __init pca_isa_init(void)
+{
+ return isa_register_driver(&pca_isa_driver, 1);
+}
+
+static void __exit pca_isa_exit(void)
+{
+ isa_unregister_driver(&pca_isa_driver);
+}
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
+MODULE_LICENSE("GPL");
+
+module_param(base, ulong, 0);
+MODULE_PARM_DESC(base, "I/O base address");
+
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "IRQ");
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
+ "For PCA9564: 330000,288000,217000,146000,"
+ "88000,59000,44000,36000\n"
+ "\t\tFor PCA9665:\tStandard: 60300 - 100099\n"
+ "\t\t\t\tFast: 100100 - 400099\n"
+ "\t\t\t\tFast+: 400100 - 10000099\n"
+ "\t\t\t\tTurbo: Up to 1265800");
+
+module_init(pca_isa_init);
+module_exit(pca_isa_exit);
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
new file mode 100644
index 00000000..ace67995
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -0,0 +1,305 @@
+/*
+ * i2c_pca_platform.c
+ *
+ * Platform driver for the PCA9564 I2C controller.
+ *
+ * Copyright (C) 2008 Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/i2c-pca-platform.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+struct i2c_pca_pf_data {
+ void __iomem *reg_base;
+ int irq; /* if 0, use polling */
+ int gpio;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_algo_pca_data algo_data;
+ unsigned long io_base;
+ unsigned long io_size;
+};
+
+/* Read/Write functions for different register alignments */
+
+static int i2c_pca_pf_readbyte8(void *pd, int reg)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ return ioread8(i2c->reg_base + reg);
+}
+
+static int i2c_pca_pf_readbyte16(void *pd, int reg)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ return ioread8(i2c->reg_base + reg * 2);
+}
+
+static int i2c_pca_pf_readbyte32(void *pd, int reg)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ return ioread8(i2c->reg_base + reg * 4);
+}
+
+static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ iowrite8(val, i2c->reg_base + reg);
+}
+
+static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ iowrite8(val, i2c->reg_base + reg * 2);
+}
+
+static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ iowrite8(val, i2c->reg_base + reg * 4);
+}
+
+
+static int i2c_pca_pf_waitforcompletion(void *pd)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ unsigned long timeout;
+ long ret;
+
+ if (i2c->irq) {
+ ret = wait_event_timeout(i2c->wait,
+ i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+ & I2C_PCA_CON_SI, i2c->adap.timeout);
+ } else {
+ /* Do polling */
+ timeout = jiffies + i2c->adap.timeout;
+ do {
+ ret = time_before(jiffies, timeout);
+ if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+ & I2C_PCA_CON_SI)
+ break;
+ udelay(100);
+ } while (ret);
+ }
+
+ return ret > 0;
+}
+
+static void i2c_pca_pf_dummyreset(void *pd)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ printk(KERN_WARNING "%s: No reset-pin found. Chip may get stuck!\n",
+ i2c->adap.name);
+}
+
+static void i2c_pca_pf_resetchip(void *pd)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+
+ gpio_set_value(i2c->gpio, 0);
+ ndelay(100);
+ gpio_set_value(i2c->gpio, 1);
+}
+
+static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
+{
+ struct i2c_pca_pf_data *i2c = dev_id;
+
+ if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
+ return IRQ_NONE;
+
+ wake_up(&i2c->wait);
+
+ return IRQ_HANDLED;
+}
+
+
+static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
+{
+ struct i2c_pca_pf_data *i2c;
+ struct resource *res;
+ struct i2c_pca9564_pf_platform_data *platform_data =
+ pdev->dev.platform_data;
+ int ret = 0;
+ int irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ /* If irq is 0, we do polling. */
+
+ if (res == NULL) {
+ ret = -ENODEV;
+ goto e_print;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), res->name)) {
+ ret = -ENOMEM;
+ goto e_print;
+ }
+
+ i2c = kzalloc(sizeof(struct i2c_pca_pf_data), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto e_alloc;
+ }
+
+ init_waitqueue_head(&i2c->wait);
+
+ i2c->reg_base = ioremap(res->start, resource_size(res));
+ if (!i2c->reg_base) {
+ ret = -ENOMEM;
+ goto e_remap;
+ }
+ i2c->io_base = res->start;
+ i2c->io_size = resource_size(res);
+ i2c->irq = irq;
+
+ i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+ i2c->adap.owner = THIS_MODULE;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "PCA9564/PCA9665 at 0x%08lx",
+ (unsigned long) res->start);
+ i2c->adap.algo_data = &i2c->algo_data;
+ i2c->adap.dev.parent = &pdev->dev;
+
+ if (platform_data) {
+ i2c->adap.timeout = platform_data->timeout;
+ i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
+ i2c->gpio = platform_data->gpio;
+ } else {
+ i2c->adap.timeout = HZ;
+ i2c->algo_data.i2c_clock = 59000;
+ i2c->gpio = -1;
+ }
+
+ i2c->algo_data.data = i2c;
+ i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
+ i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
+
+ switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
+ case IORESOURCE_MEM_32BIT:
+ i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
+ i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
+ break;
+ case IORESOURCE_MEM_16BIT:
+ i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
+ i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
+ break;
+ case IORESOURCE_MEM_8BIT:
+ default:
+ i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
+ i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
+ break;
+ }
+
+ /* Use gpio_is_valid() when in mainline */
+ if (i2c->gpio > -1) {
+ ret = gpio_request(i2c->gpio, i2c->adap.name);
+ if (ret == 0) {
+ gpio_direction_output(i2c->gpio, 1);
+ i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
+ } else {
+ printk(KERN_WARNING "%s: Registering gpio failed!\n",
+ i2c->adap.name);
+ i2c->gpio = ret;
+ }
+ }
+
+ if (irq) {
+ ret = request_irq(irq, i2c_pca_pf_handler,
+ IRQF_TRIGGER_FALLING, pdev->name, i2c);
+ if (ret)
+ goto e_reqirq;
+ }
+
+ if (i2c_pca_add_numbered_bus(&i2c->adap) < 0) {
+ ret = -ENODEV;
+ goto e_adapt;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ printk(KERN_INFO "%s registered.\n", i2c->adap.name);
+
+ return 0;
+
+e_adapt:
+ if (irq)
+ free_irq(irq, i2c);
+e_reqirq:
+ if (i2c->gpio > -1)
+ gpio_free(i2c->gpio);
+
+ iounmap(i2c->reg_base);
+e_remap:
+ kfree(i2c);
+e_alloc:
+ release_mem_region(res->start, resource_size(res));
+e_print:
+ printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret);
+ return ret;
+}
+
+static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
+{
+ struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&i2c->adap);
+
+ if (i2c->irq)
+ free_irq(i2c->irq, i2c);
+
+ if (i2c->gpio > -1)
+ gpio_free(i2c->gpio);
+
+ iounmap(i2c->reg_base);
+ release_mem_region(i2c->io_base, i2c->io_size);
+ kfree(i2c);
+
+ return 0;
+}
+
+static struct platform_driver i2c_pca_pf_driver = {
+ .probe = i2c_pca_pf_probe,
+ .remove = __devexit_p(i2c_pca_pf_remove),
+ .driver = {
+ .name = "i2c-pca-platform",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_pca_pf_init(void)
+{
+ return platform_driver_register(&i2c_pca_pf_driver);
+}
+
+static void __exit i2c_pca_pf_exit(void)
+{
+ platform_driver_unregister(&i2c_pca_pf_driver);
+}
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_pca_pf_init);
+module_exit(i2c_pca_pf_exit);
+
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
new file mode 100644
index 00000000..6d14ac2e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -0,0 +1,563 @@
+/*
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+*/
+
+/*
+ Supports:
+ Intel PIIX4, 440MX
+ Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
+ ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
+ AMD Hudson-2
+ SMSC Victory66
+
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/* PIIX4 SMBus address offsets */
+#define SMBHSTSTS (0 + piix4_smba)
+#define SMBHSLVSTS (1 + piix4_smba)
+#define SMBHSTCNT (2 + piix4_smba)
+#define SMBHSTCMD (3 + piix4_smba)
+#define SMBHSTADD (4 + piix4_smba)
+#define SMBHSTDAT0 (5 + piix4_smba)
+#define SMBHSTDAT1 (6 + piix4_smba)
+#define SMBBLKDAT (7 + piix4_smba)
+#define SMBSLVCNT (8 + piix4_smba)
+#define SMBSHDWCMD (9 + piix4_smba)
+#define SMBSLVEVT (0xA + piix4_smba)
+#define SMBSLVDAT (0xC + piix4_smba)
+
+/* count for request_region */
+#define SMBIOSIZE 8
+
+/* PCI Address Constants */
+#define SMBBA 0x090
+#define SMBHSTCFG 0x0D2
+#define SMBSLVC 0x0D3
+#define SMBSHDW1 0x0D4
+#define SMBSHDW2 0x0D5
+#define SMBREV 0x0D6
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+#define ENABLE_INT9 0
+
+/* PIIX4 constants */
+#define PIIX4_QUICK 0x00
+#define PIIX4_BYTE 0x04
+#define PIIX4_BYTE_DATA 0x08
+#define PIIX4_WORD_DATA 0x0C
+#define PIIX4_BLOCK_DATA 0x14
+
+/* insmod parameters */
+
+/* If force is set to anything different from 0, we forcibly enable the
+ PIIX4. DANGEROUS! */
+static int force;
+module_param (force, int, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!");
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the PIIX4 at the given address. VERY DANGEROUS! */
+static int force_addr;
+module_param (force_addr, int, 0);
+MODULE_PARM_DESC(force_addr,
+ "Forcibly enable the PIIX4 at the given address. "
+ "EXTREMELY DANGEROUS!");
+
+static unsigned short piix4_smba;
+static int srvrworks_csb5_delay;
+static struct pci_driver piix4_driver;
+static struct i2c_adapter piix4_adapter;
+
+static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
+ {
+ .ident = "Sapphire AM2RD790",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "SAPPHIRE Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "PC-AM2RD790"),
+ },
+ },
+ {
+ .ident = "DFI Lanparty UT 790FX",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "DFI Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "LP UT 790FX"),
+ },
+ },
+ { }
+};
+
+/* The IBM entry is in a separate table because we only check it
+ on Intel-based systems */
+static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
+ {
+ .ident = "IBM",
+ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
+ },
+ { },
+};
+
+static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id)
+{
+ unsigned char temp;
+
+ if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
+ (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
+ srvrworks_csb5_delay = 1;
+
+ /* On some motherboards, it was reported that accessing the SMBus
+ caused severe hardware problems */
+ if (dmi_check_system(piix4_dmi_blacklist)) {
+ dev_err(&PIIX4_dev->dev,
+ "Accessing the SMBus on this system is unsafe!\n");
+ return -EPERM;
+ }
+
+ /* Don't access SMBus on IBM systems which get corrupted eeproms */
+ if (dmi_check_system(piix4_dmi_ibm) &&
+ PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
+ dev_err(&PIIX4_dev->dev, "IBM system detected; this module "
+ "may corrupt your serial eeprom! Refusing to load "
+ "module!\n");
+ return -EPERM;
+ }
+
+ /* Determine the address of the SMBus areas */
+ if (force_addr) {
+ piix4_smba = force_addr & 0xfff0;
+ force = 0;
+ } else {
+ pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
+ piix4_smba &= 0xfff0;
+ if(piix4_smba == 0) {
+ dev_err(&PIIX4_dev->dev, "SMBus base address "
+ "uninitialized - upgrade BIOS or use "
+ "force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+ }
+
+ if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+ return -ENODEV;
+
+ if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+ dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
+ piix4_smba);
+ return -EBUSY;
+ }
+
+ pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
+
+ /* If force_addr is set, we program the new address here. Just to make
+ sure, we disable the PIIX4 first. */
+ if (force_addr) {
+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
+ pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
+ dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to "
+ "new address %04x!\n", piix4_smba);
+ } else if ((temp & 1) == 0) {
+ if (force) {
+ /* This should never need to be done, but has been
+ * noted that many Dell machines have the SMBus
+ * interface on the PIIX4 disabled!? NOTE: This assumes
+ * I/O space and other allocations WERE done by the
+ * Bios! Don't complain if your hardware does weird
+ * things after enabling this. :') Check for Bios
+ * updates before resorting to this.
+ */
+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
+ temp | 1);
+ dev_printk(KERN_NOTICE, &PIIX4_dev->dev,
+ "WARNING: SMBus interface has been "
+ "FORCEFULLY ENABLED!\n");
+ } else {
+ dev_err(&PIIX4_dev->dev,
+ "Host SMBus controller not enabled!\n");
+ release_region(piix4_smba, SMBIOSIZE);
+ piix4_smba = 0;
+ return -ENODEV;
+ }
+ }
+
+ if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2))
+ dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n");
+ else if ((temp & 0x0E) == 0)
+ dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n");
+ else
+ dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration "
+ "(or code out of date)!\n");
+
+ pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
+ dev_info(&PIIX4_dev->dev,
+ "SMBus Host Controller at 0x%x, revision %d\n",
+ piix4_smba, temp);
+
+ return 0;
+}
+
+static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id)
+{
+ unsigned short smba_idx = 0xcd6;
+ u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
+
+ /* SB800 and later SMBus does not support forcing address */
+ if (force || force_addr) {
+ dev_err(&PIIX4_dev->dev, "SMBus does not support "
+ "forcing address!\n");
+ return -EINVAL;
+ }
+
+ /* Determine the address of the SMBus areas */
+ if (!request_region(smba_idx, 2, "smba_idx")) {
+ dev_err(&PIIX4_dev->dev, "SMBus base address index region "
+ "0x%x already in use!\n", smba_idx);
+ return -EBUSY;
+ }
+ outb_p(smb_en, smba_idx);
+ smba_en_lo = inb_p(smba_idx + 1);
+ outb_p(smb_en + 1, smba_idx);
+ smba_en_hi = inb_p(smba_idx + 1);
+ release_region(smba_idx, 2);
+
+ if ((smba_en_lo & 1) == 0) {
+ dev_err(&PIIX4_dev->dev,
+ "Host SMBus controller not enabled!\n");
+ return -ENODEV;
+ }
+
+ piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+ if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+ return -ENODEV;
+
+ if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+ dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
+ piix4_smba);
+ return -EBUSY;
+ }
+
+ /* Request the SMBus I2C bus config region */
+ if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) {
+ dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
+ "0x%x already in use!\n", piix4_smba + i2ccfg_offset);
+ release_region(piix4_smba, SMBIOSIZE);
+ piix4_smba = 0;
+ return -EBUSY;
+ }
+ i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
+ release_region(piix4_smba + i2ccfg_offset, 1);
+
+ if (i2ccfg & 1)
+ dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus.\n");
+ else
+ dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus.\n");
+
+ dev_info(&PIIX4_dev->dev,
+ "SMBus Host Controller at 0x%x, revision %d\n",
+ piix4_smba, i2ccfg >> 4);
+
+ return 0;
+}
+
+static int piix4_transaction(void)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+ dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+ "Resetting...\n", temp);
+ outb_p(temp, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+ dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&piix4_adapter.dev, "Successful!\n");
+ }
+ }
+
+ /* start the transaction by setting bit 6 */
+ outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
+
+ /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
+ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */
+ msleep(2);
+ else
+ msleep(1);
+
+ while ((++timeout < MAX_TIMEOUT) &&
+ ((temp = inb_p(SMBHSTSTS)) & 0x01))
+ msleep(1);
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout == MAX_TIMEOUT) {
+ dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+
+ if (temp & 0x10) {
+ result = -EIO;
+ dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
+ }
+
+ if (temp & 0x08) {
+ result = -EIO;
+ dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+ "locked until next hard reset. (sorry!)\n");
+ /* Clock stops and slave is stuck in mid-transmission */
+ }
+
+ if (temp & 0x04) {
+ result = -ENXIO;
+ dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
+ }
+
+ if (inb_p(SMBHSTSTS) != 0x00)
+ outb_p(inb(SMBHSTSTS), SMBHSTSTS);
+
+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+ dev_err(&piix4_adapter.dev, "Failed reset at end of "
+ "transaction (%02x)\n", temp);
+ }
+ dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ int i, len;
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ size = PIIX4_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ size = PIIX4_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ size = PIIX4_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = PIIX4_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ outb_p(len, SMBHSTDAT0);
+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ size = PIIX4_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
+
+ status = piix4_transaction();
+ if (status)
+ return status;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
+ return 0;
+
+
+ switch (size) {
+ case PIIX4_BYTE:
+ case PIIX4_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case PIIX4_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case PIIX4_BLOCK_DATA:
+ data->block[0] = inb_p(SMBHSTDAT0);
+ if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb_p(SMBBLKDAT);
+ break;
+ }
+ return 0;
+}
+
+static u32 piix4_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = piix4_access,
+ .functionality = piix4_func,
+};
+
+static struct i2c_adapter piix4_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+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) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_HT1100LD) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, piix4_ids);
+
+static int __devinit piix4_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int retval;
+
+ if ((dev->vendor == PCI_VENDOR_ID_ATI &&
+ dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+ dev->revision >= 0x40) ||
+ dev->vendor == PCI_VENDOR_ID_AMD)
+ /* base address location etc changed in SB800 */
+ retval = piix4_setup_sb800(dev, id);
+ else
+ retval = piix4_setup(dev, id);
+
+ if (retval)
+ return retval;
+
+ /* set up the sysfs linkage to our parent device */
+ piix4_adapter.dev.parent = &dev->dev;
+
+ snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
+ "SMBus PIIX4 adapter at %04x", piix4_smba);
+
+ if ((retval = i2c_add_adapter(&piix4_adapter))) {
+ dev_err(&dev->dev, "Couldn't register adapter!\n");
+ release_region(piix4_smba, SMBIOSIZE);
+ piix4_smba = 0;
+ }
+
+ return retval;
+}
+
+static void __devexit piix4_remove(struct pci_dev *dev)
+{
+ if (piix4_smba) {
+ i2c_del_adapter(&piix4_adapter);
+ release_region(piix4_smba, SMBIOSIZE);
+ piix4_smba = 0;
+ }
+}
+
+static struct pci_driver piix4_driver = {
+ .name = "piix4_smbus",
+ .id_table = piix4_ids,
+ .probe = piix4_probe,
+ .remove = __devexit_p(piix4_remove),
+};
+
+static int __init i2c_piix4_init(void)
+{
+ return pci_register_driver(&piix4_driver);
+}
+
+static void __exit i2c_piix4_exit(void)
+{
+ pci_unregister_driver(&piix4_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+ "Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("PIIX4 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_piix4_init);
+module_exit(i2c_piix4_exit);
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 00000000..dfa7ae9c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,656 @@
+/*
+ * Specific bus support for PMC-TWI compliant implementation on MSP71xx.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#define DRV_NAME "pmcmsptwi"
+
+#define MSP_TWI_SF_CLK_REG_OFFSET 0x00
+#define MSP_TWI_HS_CLK_REG_OFFSET 0x04
+#define MSP_TWI_CFG_REG_OFFSET 0x08
+#define MSP_TWI_CMD_REG_OFFSET 0x0c
+#define MSP_TWI_ADD_REG_OFFSET 0x10
+#define MSP_TWI_DAT_0_REG_OFFSET 0x14
+#define MSP_TWI_DAT_1_REG_OFFSET 0x18
+#define MSP_TWI_INT_STS_REG_OFFSET 0x1c
+#define MSP_TWI_INT_MSK_REG_OFFSET 0x20
+#define MSP_TWI_BUSY_REG_OFFSET 0x24
+
+#define MSP_TWI_INT_STS_DONE (1 << 0)
+#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1)
+#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2)
+#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3)
+#define MSP_TWI_INT_STS_BUSY (1 << 4)
+#define MSP_TWI_INT_STS_ALL 0x1f
+
+#define MSP_MAX_BYTES_PER_RW 8
+#define MSP_MAX_POLL 5
+#define MSP_POLL_DELAY 10
+#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY)
+
+/* IO Operation macros */
+#define pmcmsptwi_readl __raw_readl
+#define pmcmsptwi_writel __raw_writel
+
+/* TWI command type */
+enum pmcmsptwi_cmd_type {
+ MSP_TWI_CMD_WRITE = 0, /* Write only */
+ MSP_TWI_CMD_READ = 1, /* Read only */
+ MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */
+};
+
+/* The possible results of the xferCmd */
+enum pmcmsptwi_xfer_result {
+ MSP_TWI_XFER_OK = 0,
+ MSP_TWI_XFER_TIMEOUT,
+ MSP_TWI_XFER_BUSY,
+ MSP_TWI_XFER_DATA_COLLISION,
+ MSP_TWI_XFER_NO_RESPONSE,
+ MSP_TWI_XFER_LOST_ARBITRATION,
+};
+
+/* Corresponds to a PMCTWI clock configuration register */
+struct pmcmsptwi_clock {
+ u8 filter; /* Bits 15:12, default = 0x03 */
+ u16 clock; /* Bits 9:0, default = 0x001f */
+};
+
+struct pmcmsptwi_clockcfg {
+ struct pmcmsptwi_clock standard; /* The standard/fast clock config */
+ struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
+};
+
+/* Corresponds to the main TWI configuration register */
+struct pmcmsptwi_cfg {
+ u8 arbf; /* Bits 15:12, default=0x03 */
+ u8 nak; /* Bits 11:8, default=0x03 */
+ u8 add10; /* Bit 7, default=0x00 */
+ u8 mst_code; /* Bits 6:4, default=0x00 */
+ u8 arb; /* Bit 1, default=0x01 */
+ u8 highspeed; /* Bit 0, default=0x00 */
+};
+
+/* A single pmctwi command to issue */
+struct pmcmsptwi_cmd {
+ u16 addr; /* The slave address (7 or 10 bits) */
+ enum pmcmsptwi_cmd_type type; /* The command type */
+ u8 write_len; /* Number of bytes in the write buffer */
+ u8 read_len; /* Number of bytes in the read buffer */
+ u8 *write_data; /* Buffer of characters to send */
+ u8 *read_data; /* Buffer to fill with incoming data */
+};
+
+/* The private data */
+struct pmcmsptwi_data {
+ void __iomem *iobase; /* iomapped base for IO */
+ int irq; /* IRQ to use (0 disables) */
+ struct completion wait; /* Completion for xfer */
+ struct mutex lock; /* Used for threadsafeness */
+ enum pmcmsptwi_xfer_result last_result; /* result of last xfer */
+};
+
+/* The default settings */
+static const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
+ .standard = {
+ .filter = 0x3,
+ .clock = 0x1f,
+ },
+ .highspeed = {
+ .filter = 0x3,
+ .clock = 0x1f,
+ },
+};
+
+static const struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
+ .arbf = 0x03,
+ .nak = 0x03,
+ .add10 = 0x00,
+ .mst_code = 0x00,
+ .arb = 0x01,
+ .highspeed = 0x00,
+};
+
+static struct pmcmsptwi_data pmcmsptwi_data;
+
+static struct i2c_adapter pmcmsptwi_adapter;
+
+/* inline helper functions */
+static inline u32 pmcmsptwi_clock_to_reg(
+ const struct pmcmsptwi_clock *clock)
+{
+ return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
+}
+
+static inline void pmcmsptwi_reg_to_clock(
+ u32 reg, struct pmcmsptwi_clock *clock)
+{
+ clock->filter = (reg >> 12) & 0xf;
+ clock->clock = reg & 0x03ff;
+}
+
+static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
+{
+ return ((cfg->arbf & 0xf) << 12) |
+ ((cfg->nak & 0xf) << 8) |
+ ((cfg->add10 & 0x1) << 7) |
+ ((cfg->mst_code & 0x7) << 4) |
+ ((cfg->arb & 0x1) << 1) |
+ (cfg->highspeed & 0x1);
+}
+
+static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
+{
+ cfg->arbf = (reg >> 12) & 0xf;
+ cfg->nak = (reg >> 8) & 0xf;
+ cfg->add10 = (reg >> 7) & 0x1;
+ cfg->mst_code = (reg >> 4) & 0x7;
+ cfg->arb = (reg >> 1) & 0x1;
+ cfg->highspeed = reg & 0x1;
+}
+
+/*
+ * Sets the current clock configuration
+ */
+static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
+ data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
+ pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
+ data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Gets the current TWI bus configuration
+ */
+static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
+ data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Sets the current TWI bus configuration
+ */
+static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
+ data->iobase + MSP_TWI_CFG_REG_OFFSET);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Parses the 'int_sts' register and returns a well-defined error code
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
+{
+ if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Lost arbitration\n");
+ return MSP_TWI_XFER_LOST_ARBITRATION;
+ } else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: No response\n");
+ return MSP_TWI_XFER_NO_RESPONSE;
+ } else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Data collision\n");
+ return MSP_TWI_XFER_DATA_COLLISION;
+ } else if (reg & MSP_TWI_INT_STS_BUSY) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Bus busy\n");
+ return MSP_TWI_XFER_BUSY;
+ }
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
+ return MSP_TWI_XFER_OK;
+}
+
+/*
+ * In interrupt mode, handle the interrupt.
+ * NOTE: Assumes data->lock is held.
+ */
+static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
+{
+ struct pmcmsptwi_data *data = ptr;
+
+ u32 reason = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
+ if (!(reason & MSP_TWI_INT_STS_DONE))
+ return IRQ_NONE;
+
+ data->last_result = pmcmsptwi_get_result(reason);
+ complete(&data->wait);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Probe for and register the device and return 0 if there is one.
+ */
+static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
+{
+ struct resource *res;
+ int rc = -ENODEV;
+
+ /* get the static platform resources */
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pldev->dev, "IOMEM resource not found\n");
+ goto ret_err;
+ }
+
+ /* reserve the memory region */
+ if (!request_mem_region(res->start, resource_size(res),
+ pldev->name)) {
+ dev_err(&pldev->dev,
+ "Unable to get memory/io address region 0x%08x\n",
+ res->start);
+ rc = -EBUSY;
+ goto ret_err;
+ }
+
+ /* remap the memory */
+ pmcmsptwi_data.iobase = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!pmcmsptwi_data.iobase) {
+ dev_err(&pldev->dev,
+ "Unable to ioremap address 0x%08x\n", res->start);
+ rc = -EIO;
+ goto ret_unreserve;
+ }
+
+ /* request the irq */
+ pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
+ if (pmcmsptwi_data.irq) {
+ rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
+ IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ pldev->name, &pmcmsptwi_data);
+ if (rc == 0) {
+ /*
+ * Enable 'DONE' interrupt only.
+ *
+ * If you enable all interrupts, you will get one on
+ * error and another when the operation completes.
+ * This way you only have to handle one interrupt,
+ * but you can still check all result flags.
+ */
+ pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
+ pmcmsptwi_data.iobase +
+ MSP_TWI_INT_MSK_REG_OFFSET);
+ } else {
+ dev_warn(&pldev->dev,
+ "Could not assign TWI IRQ handler "
+ "to irq %d (continuing with poll)\n",
+ pmcmsptwi_data.irq);
+ pmcmsptwi_data.irq = 0;
+ }
+ }
+
+ init_completion(&pmcmsptwi_data.wait);
+ mutex_init(&pmcmsptwi_data.lock);
+
+ pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
+ pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
+
+ printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
+
+ pmcmsptwi_adapter.dev.parent = &pldev->dev;
+ platform_set_drvdata(pldev, &pmcmsptwi_adapter);
+ i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
+
+ rc = i2c_add_adapter(&pmcmsptwi_adapter);
+ if (rc) {
+ dev_err(&pldev->dev, "Unable to register I2C adapter\n");
+ goto ret_unmap;
+ }
+
+ return 0;
+
+ret_unmap:
+ platform_set_drvdata(pldev, NULL);
+ if (pmcmsptwi_data.irq) {
+ pmcmsptwi_writel(0,
+ pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+ free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+ }
+
+ iounmap(pmcmsptwi_data.iobase);
+
+ret_unreserve:
+ release_mem_region(res->start, resource_size(res));
+
+ret_err:
+ return rc;
+}
+
+/*
+ * Release the device and return 0 if there is one.
+ */
+static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
+{
+ struct resource *res;
+
+ i2c_del_adapter(&pmcmsptwi_adapter);
+
+ platform_set_drvdata(pldev, NULL);
+ if (pmcmsptwi_data.irq) {
+ pmcmsptwi_writel(0,
+ pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+ free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+ }
+
+ iounmap(pmcmsptwi_data.iobase);
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ return 0;
+}
+
+/*
+ * Polls the 'busy' register until the command is complete.
+ * NOTE: Assumes data->lock is held.
+ */
+static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
+{
+ int i;
+
+ for (i = 0; i < MSP_MAX_POLL; i++) {
+ u32 val = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_BUSY_REG_OFFSET);
+ if (val == 0) {
+ u32 reason = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ pmcmsptwi_writel(reason, data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ data->last_result = pmcmsptwi_get_result(reason);
+ return;
+ }
+ udelay(MSP_POLL_DELAY);
+ }
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
+ data->last_result = MSP_TWI_XFER_TIMEOUT;
+}
+
+/*
+ * Do the transfer (low level):
+ * May use interrupt-driven or polling, depending on if an IRQ is
+ * presently registered.
+ * NOTE: Assumes data->lock is held.
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
+ u32 reg, struct pmcmsptwi_data *data)
+{
+ dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
+ pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
+ if (data->irq) {
+ unsigned long timeleft = wait_for_completion_timeout(
+ &data->wait, MSP_IRQ_TIMEOUT);
+ if (timeleft == 0) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: IRQ timeout\n");
+ complete(&data->wait);
+ data->last_result = MSP_TWI_XFER_TIMEOUT;
+ }
+ } else
+ pmcmsptwi_poll_complete(data);
+
+ return data->last_result;
+}
+
+/*
+ * Helper routine, converts 'pmctwi_cmd' struct to register format
+ */
+static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
+{
+ return ((cmd->type & 0x3) << 8) |
+ (((cmd->write_len - 1) & 0x7) << 4) |
+ ((cmd->read_len - 1) & 0x7);
+}
+
+/*
+ * Do the transfer (high level)
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
+ struct pmcmsptwi_cmd *cmd,
+ struct pmcmsptwi_data *data)
+{
+ enum pmcmsptwi_xfer_result retval;
+
+ if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
+ (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
+ (cmd->type == MSP_TWI_CMD_WRITE_READ &&
+ (cmd->read_len == 0 || cmd->write_len == 0))) {
+ dev_err(&pmcmsptwi_adapter.dev,
+ "%s: Cannot transfer less than 1 byte\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
+ cmd->write_len > MSP_MAX_BYTES_PER_RW) {
+ dev_err(&pmcmsptwi_adapter.dev,
+ "%s: Cannot transfer more than %d bytes\n",
+ __func__, MSP_MAX_BYTES_PER_RW);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->lock);
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Setting address to 0x%04x\n", cmd->addr);
+ pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
+
+ if (cmd->type == MSP_TWI_CMD_WRITE ||
+ cmd->type == MSP_TWI_CMD_WRITE_READ) {
+ u64 tmp = be64_to_cpup((__be64 *)cmd->write_data);
+ tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
+ dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
+ pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
+ data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
+ if (cmd->write_len > 4)
+ pmcmsptwi_writel(tmp >> 32,
+ data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
+ }
+
+ retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
+ if (retval != MSP_TWI_XFER_OK)
+ goto xfer_err;
+
+ if (cmd->type == MSP_TWI_CMD_READ ||
+ cmd->type == MSP_TWI_CMD_WRITE_READ) {
+ int i;
+ u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
+ u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
+ MSP_TWI_DAT_0_REG_OFFSET);
+ if (cmd->read_len > 4)
+ tmp |= (u64)pmcmsptwi_readl(data->iobase +
+ MSP_TWI_DAT_1_REG_OFFSET) << 32;
+ tmp &= rmsk;
+ dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
+
+ for (i = 0; i < cmd->read_len; i++)
+ cmd->read_data[i] = tmp >> i;
+ }
+
+xfer_err:
+ mutex_unlock(&data->lock);
+
+ return retval;
+}
+
+/* -- Algorithm functions -- */
+
+/*
+ * Sends an i2c command out on the adapter
+ */
+static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int num)
+{
+ struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
+ struct pmcmsptwi_cmd cmd;
+ struct pmcmsptwi_cfg oldcfg, newcfg;
+ int ret;
+
+ if (num > 2) {
+ dev_dbg(&adap->dev, "%d messages unsupported\n", num);
+ return -EINVAL;
+ } else if (num == 2) {
+ /* Check for a dual write-then-read command */
+ struct i2c_msg *nextmsg = msg + 1;
+ if (!(msg->flags & I2C_M_RD) &&
+ (nextmsg->flags & I2C_M_RD) &&
+ msg->addr == nextmsg->addr) {
+ cmd.type = MSP_TWI_CMD_WRITE_READ;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ cmd.read_len = nextmsg->len;
+ cmd.read_data = nextmsg->buf;
+ } else {
+ dev_dbg(&adap->dev,
+ "Non write-read dual messages unsupported\n");
+ return -EINVAL;
+ }
+ } else if (msg->flags & I2C_M_RD) {
+ cmd.type = MSP_TWI_CMD_READ;
+ cmd.read_len = msg->len;
+ cmd.read_data = msg->buf;
+ cmd.write_len = 0;
+ cmd.write_data = NULL;
+ } else {
+ cmd.type = MSP_TWI_CMD_WRITE;
+ cmd.read_len = 0;
+ cmd.read_data = NULL;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ }
+
+ if (msg->len == 0) {
+ dev_err(&adap->dev, "Zero-byte messages unsupported\n");
+ return -EINVAL;
+ }
+
+ cmd.addr = msg->addr;
+
+ if (msg->flags & I2C_M_TEN) {
+ pmcmsptwi_get_twi_config(&newcfg, data);
+ memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
+
+ /* Set the special 10-bit address flag */
+ newcfg.add10 = 1;
+
+ pmcmsptwi_set_twi_config(&newcfg, data);
+ }
+
+ /* Execute the command */
+ ret = pmcmsptwi_xfer_cmd(&cmd, data);
+
+ if (msg->flags & I2C_M_TEN)
+ pmcmsptwi_set_twi_config(&oldcfg, data);
+
+ dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n",
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
+ (ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed");
+
+ if (ret != MSP_TWI_XFER_OK) {
+ /*
+ * TODO: We could potentially loop and retry in the case
+ * of MSP_TWI_XFER_TIMEOUT.
+ */
+ return -1;
+ }
+
+ return 0;
+}
+
+static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
+{
+ 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_PROC_CALL;
+}
+
+/* -- Initialization -- */
+
+static struct i2c_algorithm pmcmsptwi_algo = {
+ .master_xfer = pmcmsptwi_master_xfer,
+ .functionality = pmcmsptwi_i2c_func,
+};
+
+static struct i2c_adapter pmcmsptwi_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &pmcmsptwi_algo,
+ .name = DRV_NAME,
+};
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" DRV_NAME);
+
+static struct platform_driver pmcmsptwi_driver = {
+ .probe = pmcmsptwi_probe,
+ .remove = __devexit_p(pmcmsptwi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pmcmsptwi_init(void)
+{
+ return platform_driver_register(&pmcmsptwi_driver);
+}
+
+static void __exit pmcmsptwi_exit(void)
+{
+ platform_driver_unregister(&pmcmsptwi_driver);
+}
+
+MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
+MODULE_LICENSE("GPL");
+
+module_init(pmcmsptwi_init);
+module_exit(pmcmsptwi_exit);
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
new file mode 100644
index 00000000..eb8ad538
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -0,0 +1,733 @@
+/*
+ * Provides I2C support for Philips PNX010x/PNX4008 boards.
+ *
+ * Authors: Dennis Kovalev <dkovalev@ru.mvista.com>
+ * Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-pnx.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+#define I2C_PNX_TIMEOUT 10 /* msec */
+#define I2C_PNX_SPEED_KHZ 100
+#define I2C_PNX_REGION_SIZE 0x100
+
+static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+{
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(data)) & mstatus_active)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+{
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
+{
+ 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(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
+ jiffies, expires);
+
+ timer->expires = jiffies + expires;
+ timer->data = (unsigned long)alg_data;
+
+ add_timer(timer);
+}
+
+/**
+ * i2c_pnx_start - start a device
+ * @slave_addr: slave address
+ * @adap: pointer to adapter structure
+ *
+ * Generate a START signal in the desired mode.
+ */
+static int i2c_pnx_start(unsigned char slave_addr,
+ struct i2c_pnx_algo_data *alg_data)
+{
+ 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(&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(&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(&alg_data->adapter.dev,
+ "%s: Arbitration failure. Slave addr = %02x\n",
+ alg_data->adapter.name, slave_addr);
+ return -EIO;
+ }
+
+ /*
+ * OK, I2C is enabled and we have the bus.
+ * Clear the current TDI and AFI status flags.
+ */
+ iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
+ I2C_REG_STS(alg_data));
+
+ dev_dbg(&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(&alg_data->adapter.dev, "%s(): exit\n", __func__);
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_stop - stop a device
+ * @adap: pointer to I2C adapter structure
+ *
+ * Generate a STOP signal to terminate the master transaction.
+ */
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
+{
+ /* Only 1 msec max timeout due to interrupt context */
+ long timeout = 1000;
+
+ 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 */
+ iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
+
+ /* Wait until the STOP is seen. */
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) {
+ /* may be called from interrupt context */
+ udelay(1);
+ timeout--;
+ }
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+}
+
+/**
+ * i2c_pnx_master_xmit - transmit data to slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Sends one byte of data to the slave
+ */
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
+{
+ u32 val;
+
+ 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;
+
+ alg_data->mif.len--;
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ 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(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
+ }
+ /* Disable master interrupts */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ del_timer_sync(&alg_data->mif.timer);
+
+ dev_dbg(&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(alg_data);
+
+ /* Disable master interrupts. */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ /* Stop timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine after zero-xfer.\n",
+ __func__);
+
+ complete(&alg_data->mif.complete);
+ }
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_master_rcv - receive data from slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Reads one byte data from the slave
+ */
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
+{
+ unsigned int val = 0;
+ u32 ctl = 0;
+
+ 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(&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;
+
+ /*
+ * Enable interrupt RFDAIE (data in Rx fifo),
+ * and disable DRMIE (need data for Tx)
+ */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl |= mcntrl_rffie | mcntrl_daie;
+ ctl &= ~mcntrl_drmie;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ }
+
+ /*
+ * Now we'll 'ask' for data:
+ * For each byte we want to receive, we must
+ * write a (dummy) byte to the Tx-FIFO.
+ */
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ return 0;
+ }
+
+ /* Handle data. */
+ if (alg_data->mif.len > 0) {
+ val = ioread32(I2C_REG_RX(alg_data));
+ *alg_data->mif.buf++ = (u8) (val & 0xff);
+ dev_dbg(&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(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
+
+ /* Disable master interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie | mcntrl_daie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Kill timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ }
+ }
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
+{
+ struct i2c_pnx_algo_data *alg_data = dev_id;
+ u32 stat, ctl;
+
+ 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)),
+ alg_data->mif.mode);
+ stat = ioread32(I2C_REG_STS(alg_data));
+
+ /* let's see what kind of event this is */
+ if (stat & mstatus_afi) {
+ /* We lost arbitration in the midst of a transfer */
+ alg_data->mif.ret = -EIO;
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else if (stat & mstatus_nai) {
+ /* Slave did not acknowledge, generate a STOP */
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Slave did not acknowledge, generating a STOP.\n",
+ __func__);
+ i2c_pnx_stop(alg_data);
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Our return value. */
+ alg_data->mif.ret = -EIO;
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else {
+ /*
+ * Two options:
+ * - Master Tx needs data.
+ * - There is data in the Rx-fifo
+ * The latter is only the case if we have requested for data,
+ * via a dummy write. (See 'i2c_pnx_master_rcv'.)
+ * We therefore check, as a sanity check, whether that interrupt
+ * has been enabled.
+ */
+ if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
+ if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
+ i2c_pnx_master_xmit(alg_data);
+ } else if (alg_data->mif.mode == I2C_SMBUS_READ) {
+ i2c_pnx_master_rcv(alg_data);
+ }
+ }
+ }
+
+ /* Clear TDI and AFI bits */
+ stat = ioread32(I2C_REG_STS(alg_data));
+ iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
+
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): exiting, stat = %x ctrl = %x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_pnx_timeout(unsigned long data)
+{
+ struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
+ u32 ctl;
+
+ 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));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ ctl |= mcntrl_reset;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ alg_data->mif.ret = -EIO;
+ complete(&alg_data->mif.complete);
+}
+
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
+{
+ u32 stat;
+
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
+ dev_err(&alg_data->adapter.dev,
+ "%s: Bus is still active after xfer. Reset it...\n",
+ 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);
+ } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
+ /* If there is data in the fifo's after transfer,
+ * flush fifo's by reset.
+ */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ } else if (stat & mstatus_nai) {
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ }
+}
+
+/**
+ * i2c_pnx_xfer - generic transfer entry point
+ * @adap: pointer to I2C adapter structure
+ * @msgs: array of messages
+ * @num: number of messages
+ *
+ * Initiates the transfer
+ */
+static int
+i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int rc = 0, completed = 0, i;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 stat = ioread32(I2C_REG_STS(alg_data));
+
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): entering: %d messages, stat = %04x.\n",
+ __func__, num, ioread32(I2C_REG_STS(alg_data)));
+
+ bus_reset_if_active(alg_data);
+
+ /* Process transactions in a loop. */
+ for (i = 0; rc >= 0 && i < num; i++) {
+ u8 addr;
+
+ pmsg = &msgs[i];
+ addr = pmsg->addr;
+
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&alg_data->adapter.dev,
+ "%s: 10 bits addr not supported!\n",
+ alg_data->adapter.name);
+ rc = -EINVAL;
+ break;
+ }
+
+ alg_data->mif.buf = pmsg->buf;
+ alg_data->mif.len = pmsg->len;
+ alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
+ I2C_SMBUS_READ : I2C_SMBUS_WRITE;
+ alg_data->mif.ret = 0;
+ alg_data->last = (i == num - 1);
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+ __func__, alg_data->mif.mode, alg_data->mif.len);
+
+ i2c_pnx_arm_timer(alg_data);
+
+ /* initialize the completion var */
+ init_completion(&alg_data->mif.complete);
+
+ /* Enable master interrupt */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie |
+ mcntrl_naie | mcntrl_drmie,
+ I2C_REG_CTL(alg_data));
+
+ /* Put start-code and slave-address on the bus. */
+ rc = i2c_pnx_start(addr, alg_data);
+ if (rc < 0)
+ break;
+
+ /* Wait for completion */
+ wait_for_completion(&alg_data->mif.complete);
+
+ if (!(rc = alg_data->mif.ret))
+ completed++;
+ 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(&alg_data->adapter.dev,
+ "%s: TDI still set... clearing now.\n",
+ alg_data->adapter.name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
+ dev_dbg(&alg_data->adapter.dev,
+ "%s: AFI still set... clearing now.\n",
+ alg_data->adapter.name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ }
+
+ bus_reset_if_active(alg_data);
+
+ /* Cleanup to be sure... */
+ alg_data->mif.buf = NULL;
+ alg_data->mif.len = 0;
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (completed != num)
+ return ((rc < 0) ? rc : -EREMOTEIO);
+
+ return num;
+}
+
+static u32 i2c_pnx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm pnx_algorithm = {
+ .master_xfer = i2c_pnx_xfer,
+ .functionality = i2c_pnx_func,
+};
+
+#ifdef CONFIG_PM
+static int i2c_pnx_controller_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ clk_disable(alg_data->clk);
+
+ return 0;
+}
+
+static int i2c_pnx_controller_resume(struct platform_device *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;
+ unsigned long freq;
+ struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
+
+ if (!i2c_pnx || !i2c_pnx->name) {
+ dev_err(&pdev->dev, "%s: no platform data supplied\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
+ if (!alg_data) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ 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;
+ }
+
+ init_timer(&alg_data->mif.timer);
+ alg_data->mif.timer.function = i2c_pnx_timeout;
+ alg_data->mif.timer.data = (unsigned long)alg_data;
+
+ /* Register I/O resource */
+ 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",
+ i2c_pnx->base);
+ ret = -ENODEV;
+ goto out_clkget;
+ }
+
+ 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;
+ }
+
+ 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
+ * the serial clock (SCL) will be high.
+ * For example, if the system clock period is 50 ns and the maximum
+ * desired serial period is 10000 ns (100 kHz), then CLKHI would be
+ * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value
+ * programmed into CLKHI will vary from this slightly due to
+ * variations in the output pad's rise and fall times as well as
+ * the deglitching filter length.
+ */
+
+ tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ if (tmp > 0x3FF)
+ tmp = 0x3FF;
+ 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_clock;
+ }
+ init_completion(&alg_data->mif.complete);
+
+ 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 */
+ 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",
+ alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
+
+ return 0;
+
+out_irq:
+ free_irq(i2c_pnx->irq, alg_data);
+out_clock:
+ clk_disable(alg_data->clk);
+out_unmap:
+ iounmap(alg_data->ioaddr);
+out_release:
+ 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;
+}
+
+static int __devexit i2c_pnx_remove(struct platform_device *pdev)
+{
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+ struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
+
+ 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;
+}
+
+static struct platform_driver i2c_pnx_driver = {
+ .driver = {
+ .name = "pnx-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2c_pnx_probe,
+ .remove = __devexit_p(i2c_pnx_remove),
+ .suspend = i2c_pnx_controller_suspend,
+ .resume = i2c_pnx_controller_resume,
+};
+
+static int __init i2c_adap_pnx_init(void)
+{
+ return platform_driver_register(&i2c_pnx_driver);
+}
+
+static void __exit i2c_adap_pnx_exit(void)
+{
+ platform_driver_unregister(&i2c_pnx_driver);
+}
+
+MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
+MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pnx-i2c");
+
+/* We need to make sure I2C is initialized before USB */
+subsys_initcall(i2c_adap_pnx_init);
+module_exit(i2c_adap_pnx_exit);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
new file mode 100644
index 00000000..b289ec99
--- /dev/null
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -0,0 +1,341 @@
+/*
+ i2c Support for Apple SMU Controller
+
+ Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
+ <benh@kernel.crashing.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/pmac_low_i2c.h>
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
+MODULE_LICENSE("GPL");
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
+ u16 addr,
+ unsigned short flags,
+ char read_write,
+ u8 command,
+ int size,
+ union i2c_smbus_data* data)
+{
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(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];
+
+ 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:
+ buf = NULL;
+ len = 0;
+ break;
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ buf = &data->byte;
+ len = 1;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (!read) {
+ local[0] = data->word & 0xff;
+ local[1] = (data->word >> 8) & 0xff;
+ }
+ buf = local;
+ len = 2;
+ break;
+
+ /* Note that these are broken vs. the expected smbus API where
+ * on reads, the length is actually returned from the function,
+ * but I think the current API makes no sense and I don't want
+ * any driver that I haven't verified for correctness to go
+ * anywhere near a pmac i2c bus anyway ...
+ *
+ * I'm also not completely sure what kind of phases to do between
+ * the actual command and the data (what I am _supposed_ to do that
+ * is). For now, I assume writes are a single stream and reads have
+ * a repeat start/addr phase (but not stop in between)
+ */
+ case I2C_SMBUS_BLOCK_DATA:
+ buf = data->block;
+ len = data->block[0] + 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ buf = &data->block[1];
+ len = data->block[0];
+ break;
+
+ default:
+ 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;
+}
+
+/*
+ * Generic i2c master transfer entrypoint. This driver only support single
+ * messages (for "lame i2c" transfers). Anything else should use the smbus
+ * entry point
+ */
+static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
+ int rc = 0;
+ 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;
+
+ 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, pmac_i2c_mode_std);
+ 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;
+}
+
+static u32 i2c_powermac_func(struct i2c_adapter * adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
+}
+
+/* For now, we only handle smbus */
+static const struct i2c_algorithm i2c_powermac_algorithm = {
+ .smbus_xfer = i2c_powermac_smbus_xfer,
+ .master_xfer = i2c_powermac_master_xfer,
+ .functionality = i2c_powermac_func,
+};
+
+
+static int __devexit i2c_powermac_remove(struct platform_device *dev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(dev);
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ /* 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);
+ memset(adapter, 0, sizeof(*adapter));
+
+ return 0;
+}
+
+
+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;
+ 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
+ * controller's parent device node for keywest. PMU didn't have a
+ * naming convention and SMU has a different one
+ */
+ switch(pmac_i2c_get_type(bus)) {
+ case pmac_i2c_bus_keywest:
+ parent = of_get_parent(pmac_i2c_get_controller(bus));
+ if (parent == NULL)
+ return -EINVAL;
+ basename = parent->name;
+ break;
+ case pmac_i2c_bus_pmu:
+ basename = "pmu";
+ break;
+ case pmac_i2c_bus_smu:
+ /* This is not what we used to do but I'm fixing drivers at
+ * the same time as this change
+ */
+ basename = "smu";
+ break;
+ default:
+ return -EINVAL;
+ }
+ snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+ pmac_i2c_get_channel(bus));
+ of_node_put(parent);
+
+ platform_set_drvdata(dev, adapter);
+ adapter->algo = &i2c_powermac_algorithm;
+ i2c_set_adapdata(adapter, bus);
+ adapter->dev.parent = &dev->dev;
+ rc = i2c_add_adapter(adapter);
+ if (rc) {
+ printk(KERN_ERR "i2c-powermac: Adapter %s registration "
+ "failed\n", adapter->name);
+ memset(adapter, 0, sizeof(*adapter));
+ }
+
+ printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
+
+ if (!strncmp(basename, "uni-n", 5)) {
+ struct device_node *np;
+ const u32 *prop;
+ struct i2c_board_info info;
+
+ /* Instantiate I2C motion sensor if present */
+ np = of_find_node_by_name(NULL, "accelerometer");
+ if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
+ (prop = of_get_property(np, "reg", NULL))) {
+ int i2c_bus;
+ const char *tmp_bus;
+
+ /* look for bus either using "reg" or by path */
+ tmp_bus = strstr(np->full_name, "/i2c-bus@");
+ if (tmp_bus)
+ i2c_bus = *(tmp_bus + 9) - '0';
+ else
+ i2c_bus = ((*prop) >> 8) & 0x0f;
+
+ if (pmac_i2c_get_channel(bus) == i2c_bus) {
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = ((*prop) & 0xff) >> 1;
+ strlcpy(info.type, "ams", I2C_NAME_SIZE);
+ i2c_new_device(adapter, &info);
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c-powermac");
+
+static struct platform_driver i2c_powermac_driver = {
+ .probe = i2c_powermac_probe,
+ .remove = __devexit_p(i2c_powermac_remove),
+ .driver = {
+ .name = "i2c-powermac",
+ .bus = &platform_bus_type,
+ },
+};
+
+static int __init i2c_powermac_init(void)
+{
+ platform_driver_register(&i2c_powermac_driver);
+ return 0;
+}
+
+
+static void __exit i2c_powermac_cleanup(void)
+{
+ platform_driver_unregister(&i2c_powermac_driver);
+}
+
+module_init(i2c_powermac_init);
+module_exit(i2c_powermac_cleanup);
diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c
new file mode 100644
index 00000000..fac67394
--- /dev/null
+++ b/drivers/i2c/busses/i2c-puv3.c
@@ -0,0 +1,306 @@
+/*
+ * I2C driver for PKUnity-v3 SoC
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ * Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short poll_status(unsigned long bit)
+{
+ int loop_cntr = 1000;
+
+ if (bit & I2C_STATUS_TFNF) {
+ do {
+ udelay(10);
+ } while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0));
+ } else {
+ /* RXRDY handler */
+ do {
+ if (readl(I2C_TAR) == I2C_TAR_EEPROM)
+ msleep(20);
+ else
+ udelay(10);
+ } while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0));
+ }
+
+ return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ int i2c_reg = *buf;
+
+ /* Read data */
+ while (length--) {
+ if (!poll_status(I2C_STATUS_TFNF)) {
+ dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* send addr */
+ writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+ /* get ready to next write */
+ i2c_reg++;
+
+ /* send read CMD */
+ writel(I2C_DATACMD_READ, I2C_DATACMD);
+
+ /* wait until the Rx FIFO have available */
+ if (!poll_status(I2C_STATUS_RFNE)) {
+ dev_dbg(&adap->dev, "RXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* read the data to buf */
+ *buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK);
+ buf++;
+ }
+
+ return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ int i2c_reg = *buf;
+
+ /* Do nothing but storing the reg_num to a static variable */
+ if (i2c_reg == -1) {
+ printk(KERN_WARNING "Error i2c reg\n");
+ return -ETIMEDOUT;
+ }
+
+ if (length == 1)
+ return 0;
+
+ buf++;
+ length--;
+ while (length--) {
+ /* send addr */
+ writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+ /* send write CMD */
+ writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+ /* wait until the Rx FIFO have available */
+ msleep(20);
+
+ /* read the data to buf */
+ i2c_reg++;
+ buf++;
+ }
+
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ */
+static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+ int num)
+{
+ int i, ret;
+ unsigned char swap;
+
+ /* Disable i2c */
+ writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
+
+ /* Set the work mode and speed*/
+ writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON);
+
+ writel(pmsg->addr, I2C_TAR);
+
+ /* Enable i2c */
+ writel(I2C_ENABLE_ENABLE, I2C_ENABLE);
+
+ dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num);
+
+ for (i = 0; i < num; i++) {
+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+ pmsg->flags & I2C_M_RD ? "read" : "writ",
+ pmsg->len, pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+ if (pmsg->len && pmsg->buf) { /* sanity check */
+ if (pmsg->flags & I2C_M_RD)
+ ret = xfer_read(adap, pmsg->buf, pmsg->len);
+ else
+ ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+ if (ret)
+ return ret;
+
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+
+ /* XXX: fixup be16_to_cpu in bq27x00_battery.c */
+ if (pmsg->addr == I2C_TAR_PWIC) {
+ swap = pmsg->buf[0];
+ pmsg->buf[0] = pmsg->buf[1];
+ pmsg->buf[1] = swap;
+ }
+
+ return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 puv3_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm puv3_i2c_algorithm = {
+ .master_xfer = puv3_i2c_xfer,
+ .functionality = puv3_i2c_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit puv3_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct resource *mem;
+ int rc;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+
+ if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c"))
+ return -EBUSY;
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "can't allocate inteface!\n");
+ rc = -ENOMEM;
+ goto fail_nomem;
+ }
+ snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x",
+ mem->start);
+ adapter->algo = &puv3_i2c_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+
+ platform_set_drvdata(pdev, adapter);
+
+ adapter->nr = pdev->id;
+ rc = i2c_add_numbered_adapter(adapter);
+ if (rc) {
+ dev_err(&pdev->dev, "Adapter '%s' registration failed\n",
+ adapter->name);
+ goto fail_add_adapter;
+ }
+
+ dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n");
+ return 0;
+
+fail_add_adapter:
+ platform_set_drvdata(pdev, NULL);
+ kfree(adapter);
+fail_nomem:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return rc;
+}
+
+static int __devexit puv3_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct resource *mem;
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ if (rc) {
+ dev_err(&pdev->dev, "Adapter '%s' delete fail\n",
+ adapter->name);
+ return rc;
+ }
+
+ put_device(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+ return rc;
+}
+
+#ifdef CONFIG_PM
+static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
+{
+ int poll_count;
+ /* Disable the IIC */
+ writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
+ for (poll_count = 0; poll_count < 50; poll_count++) {
+ if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE)
+ udelay(25);
+ }
+
+ return 0;
+}
+
+static int puv3_i2c_resume(struct platform_device *dev)
+{
+ return 0 ;
+}
+#else
+#define puv3_i2c_suspend NULL
+#define puv3_i2c_resume NULL
+#endif
+
+MODULE_ALIAS("platform:puv3_i2c");
+
+static struct platform_driver puv3_i2c_driver = {
+ .probe = puv3_i2c_probe,
+ .remove = __devexit_p(puv3_i2c_remove),
+ .suspend = puv3_i2c_suspend,
+ .resume = puv3_i2c_resume,
+ .driver = {
+ .name = "PKUnity-v3-I2C",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init puv3_i2c_init(void)
+{
+ return platform_driver_register(&puv3_i2c_driver);
+}
+
+static void __exit puv3_i2c_exit(void)
+{
+ platform_driver_unregister(&puv3_i2c_driver);
+}
+
+module_init(puv3_i2c_init);
+module_exit(puv3_i2c_exit);
+
+MODULE_DESCRIPTION("PKUnity v3 I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
new file mode 100644
index 00000000..6659d269
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -0,0 +1,176 @@
+/*
+ * The CE4100's I2C device is more or less the same one as found on PXA.
+ * It does not support slave mode, the register slightly moved. This PCI
+ * device provides three bars, every contains a single I2C controller.
+ */
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/pxa-i2c.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#define CE4100_PCI_I2C_DEVS 3
+
+struct ce4100_devices {
+ struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
+};
+
+static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
+{
+ struct platform_device *pdev;
+ struct i2c_pxa_platform_data pdata;
+ struct resource res[2];
+ struct device_node *child;
+ static int devnum;
+ int ret;
+
+ memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
+ memset(&res, 0, sizeof(res));
+
+ res[0].flags = IORESOURCE_MEM;
+ res[0].start = pci_resource_start(dev, bar);
+ res[0].end = pci_resource_end(dev, bar);
+
+ res[1].flags = IORESOURCE_IRQ;
+ res[1].start = dev->irq;
+ res[1].end = dev->irq;
+
+ for_each_child_of_node(dev->dev.of_node, child) {
+ const void *prop;
+ struct resource r;
+ int ret;
+
+ ret = of_address_to_resource(child, 0, &r);
+ if (ret < 0)
+ continue;
+ if (r.start != res[0].start)
+ continue;
+ if (r.end != res[0].end)
+ continue;
+ if (r.flags != res[0].flags)
+ continue;
+
+ prop = of_get_property(child, "fast-mode", NULL);
+ if (prop)
+ pdata.fast_mode = 1;
+
+ break;
+ }
+
+ if (!child) {
+ dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
+ bar);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pdev = platform_device_alloc("ce4100-i2c", devnum);
+ if (!pdev) {
+ of_node_put(child);
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdev->dev.parent = &dev->dev;
+ pdev->dev.of_node = child;
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret)
+ goto err;
+
+ ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (ret)
+ goto err;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto err;
+ devnum++;
+ return pdev;
+err:
+ platform_device_put(pdev);
+out:
+ return ERR_PTR(ret);
+}
+
+static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+ int i;
+ struct ce4100_devices *sds;
+
+ ret = pci_enable_device_mem(dev);
+ if (ret)
+ return ret;
+
+ if (!dev->dev.of_node) {
+ dev_err(&dev->dev, "Missing device tree node.\n");
+ return -EINVAL;
+ }
+ sds = kzalloc(sizeof(*sds), GFP_KERNEL);
+ if (!sds)
+ goto err_mem;
+
+ for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
+ sds->pdev[i] = add_i2c_device(dev, i);
+ if (IS_ERR(sds->pdev[i])) {
+ while (--i >= 0)
+ platform_device_unregister(sds->pdev[i]);
+ goto err_dev_add;
+ }
+ }
+ pci_set_drvdata(dev, sds);
+ return 0;
+
+err_dev_add:
+ pci_set_drvdata(dev, NULL);
+ kfree(sds);
+err_mem:
+ pci_disable_device(dev);
+ return ret;
+}
+
+static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
+{
+ struct ce4100_devices *sds;
+ unsigned int i;
+
+ sds = pci_get_drvdata(dev);
+ pci_set_drvdata(dev, NULL);
+
+ for (i = 0; i < ARRAY_SIZE(sds->pdev); i++)
+ platform_device_unregister(sds->pdev[i]);
+
+ pci_disable_device(dev);
+ kfree(sds);
+}
+
+static struct pci_device_id ce4100_i2c_devices[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
+ { },
+};
+MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices);
+
+static struct pci_driver ce4100_i2c_driver = {
+ .name = "ce4100_i2c",
+ .id_table = ce4100_i2c_devices,
+ .probe = ce4100_i2c_probe,
+ .remove = __devexit_p(ce4100_i2c_remove),
+};
+
+static int __init ce4100_i2c_init(void)
+{
+ return pci_register_driver(&ce4100_i2c_driver);
+}
+module_init(ce4100_i2c_init);
+
+static void __exit ce4100_i2c_exit(void)
+{
+ pci_unregister_driver(&ce4100_i2c_driver);
+}
+module_exit(ce4100_i2c_exit);
+
+MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
new file mode 100644
index 00000000..f59224a5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -0,0 +1,1258 @@
+/*
+ * i2c_adap_pxa.c
+ *
+ * I2C adapter for the PXA I2C bus access.
+ *
+ * Copyright (C) 2002 Intrinsyc Software Inc.
+ * Copyright (C) 2004-2005 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * History:
+ * Apr 2002: Initial version [CS]
+ * 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]
+ * Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood]
+ * Feb 2005: Rework slave mode handling [RMK]
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/i2c-pxa.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c/pxa-i2c.h>
+
+#include <asm/irq.h>
+
+#ifndef CONFIG_HAVE_CLK
+#define clk_get(dev, id) NULL
+#define clk_put(clk) do { } while (0)
+#define clk_disable(clk) do { } while (0)
+#define clk_enable(clk) do { } while (0)
+#endif
+
+struct pxa_reg_layout {
+ u32 ibmr;
+ u32 idbr;
+ u32 icr;
+ u32 isr;
+ u32 isar;
+};
+
+enum pxa_i2c_types {
+ REGS_PXA2XX,
+ REGS_PXA3XX,
+ REGS_CE4100,
+};
+
+/*
+ * I2C registers definitions
+ */
+static struct pxa_reg_layout pxa_reg_layout[] = {
+ [REGS_PXA2XX] = {
+ .ibmr = 0x00,
+ .idbr = 0x08,
+ .icr = 0x10,
+ .isr = 0x18,
+ .isar = 0x20,
+ },
+ [REGS_PXA3XX] = {
+ .ibmr = 0x00,
+ .idbr = 0x04,
+ .icr = 0x08,
+ .isr = 0x0c,
+ .isar = 0x10,
+ },
+ [REGS_CE4100] = {
+ .ibmr = 0x14,
+ .idbr = 0x0c,
+ .icr = 0x00,
+ .isr = 0x04,
+ /* no isar register */
+ },
+};
+
+static const struct platform_device_id i2c_pxa_id_table[] = {
+ { "pxa2xx-i2c", REGS_PXA2XX },
+ { "pxa3xx-pwri2c", REGS_PXA3XX },
+ { "ce4100-i2c", REGS_CE4100 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
+
+/*
+ * I2C bit definitions
+ */
+
+#define ICR_START (1 << 0) /* start bit */
+#define ICR_STOP (1 << 1) /* stop bit */
+#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */
+#define ICR_TB (1 << 3) /* transfer byte bit */
+#define ICR_MA (1 << 4) /* master abort */
+#define ICR_SCLE (1 << 5) /* master clock enable */
+#define ICR_IUE (1 << 6) /* unit enable */
+#define ICR_GCD (1 << 7) /* general call disable */
+#define ICR_ITEIE (1 << 8) /* enable tx interrupts */
+#define ICR_IRFIE (1 << 9) /* enable rx interrupts */
+#define ICR_BEIE (1 << 10) /* enable bus error ints */
+#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */
+#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */
+#define ICR_SADIE (1 << 13) /* slave address detected int enable */
+#define ICR_UR (1 << 14) /* unit reset */
+#define ICR_FM (1 << 15) /* fast mode */
+
+#define ISR_RWM (1 << 0) /* read/write mode */
+#define ISR_ACKNAK (1 << 1) /* ack/nak status */
+#define ISR_UB (1 << 2) /* unit busy */
+#define ISR_IBB (1 << 3) /* bus busy */
+#define ISR_SSD (1 << 4) /* slave stop detected */
+#define ISR_ALD (1 << 5) /* arbitration loss detected */
+#define ISR_ITE (1 << 6) /* tx buffer empty */
+#define ISR_IRF (1 << 7) /* rx buffer full */
+#define ISR_GCAD (1 << 8) /* general call address detected */
+#define ISR_SAD (1 << 9) /* slave address detected */
+#define ISR_BED (1 << 10) /* bus error no ACK/NAK */
+
+struct pxa_i2c {
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int msg_idx;
+ unsigned int msg_ptr;
+ unsigned int slave_addr;
+
+ struct i2c_adapter adap;
+ struct clk *clk;
+#ifdef CONFIG_I2C_PXA_SLAVE
+ struct i2c_slave_client *slave;
+#endif
+
+ unsigned int irqlogidx;
+ u32 isrlog[32];
+ u32 icrlog[32];
+
+ void __iomem *reg_base;
+ void __iomem *reg_ibmr;
+ void __iomem *reg_idbr;
+ void __iomem *reg_icr;
+ void __iomem *reg_isr;
+ void __iomem *reg_isar;
+
+ unsigned long iobase;
+ unsigned long iosize;
+
+ int irq;
+ unsigned int use_pio :1;
+ unsigned int fast_mode :1;
+};
+
+#define _IBMR(i2c) ((i2c)->reg_ibmr)
+#define _IDBR(i2c) ((i2c)->reg_idbr)
+#define _ICR(i2c) ((i2c)->reg_icr)
+#define _ISR(i2c) ((i2c)->reg_isr)
+#define _ISAR(i2c) ((i2c)->reg_isar)
+
+/*
+ * I2C Slave mode address
+ */
+#define I2C_PXA_SLAVE_ADDR 0x1
+
+#ifdef DEBUG
+
+struct bits {
+ u32 mask;
+ const char *set;
+ const char *unset;
+};
+#define PXA_BIT(m, s, u) { .mask = m, .set = s, .unset = u }
+
+static inline void
+decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
+{
+ printk("%s %08x: ", prefix, val);
+ while (num--) {
+ const char *str = val & bits->mask ? bits->set : bits->unset;
+ if (str)
+ printk("%s ", str);
+ bits++;
+ }
+}
+
+static const struct bits isr_bits[] = {
+ PXA_BIT(ISR_RWM, "RX", "TX"),
+ PXA_BIT(ISR_ACKNAK, "NAK", "ACK"),
+ PXA_BIT(ISR_UB, "Bsy", "Rdy"),
+ PXA_BIT(ISR_IBB, "BusBsy", "BusRdy"),
+ PXA_BIT(ISR_SSD, "SlaveStop", NULL),
+ PXA_BIT(ISR_ALD, "ALD", NULL),
+ PXA_BIT(ISR_ITE, "TxEmpty", NULL),
+ PXA_BIT(ISR_IRF, "RxFull", NULL),
+ PXA_BIT(ISR_GCAD, "GenCall", NULL),
+ PXA_BIT(ISR_SAD, "SlaveAddr", NULL),
+ PXA_BIT(ISR_BED, "BusErr", NULL),
+};
+
+static void decode_ISR(unsigned int val)
+{
+ decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val);
+ printk("\n");
+}
+
+static const struct bits icr_bits[] = {
+ PXA_BIT(ICR_START, "START", NULL),
+ PXA_BIT(ICR_STOP, "STOP", NULL),
+ PXA_BIT(ICR_ACKNAK, "ACKNAK", NULL),
+ PXA_BIT(ICR_TB, "TB", NULL),
+ PXA_BIT(ICR_MA, "MA", NULL),
+ PXA_BIT(ICR_SCLE, "SCLE", "scle"),
+ PXA_BIT(ICR_IUE, "IUE", "iue"),
+ PXA_BIT(ICR_GCD, "GCD", NULL),
+ PXA_BIT(ICR_ITEIE, "ITEIE", NULL),
+ PXA_BIT(ICR_IRFIE, "IRFIE", NULL),
+ PXA_BIT(ICR_BEIE, "BEIE", NULL),
+ PXA_BIT(ICR_SSDIE, "SSDIE", NULL),
+ PXA_BIT(ICR_ALDIE, "ALDIE", NULL),
+ PXA_BIT(ICR_SADIE, "SADIE", NULL),
+ PXA_BIT(ICR_UR, "UR", "ur"),
+};
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static void decode_ICR(unsigned int val)
+{
+ decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val);
+ printk("\n");
+}
+#endif
+
+static unsigned int i2c_debug = DEBUG;
+
+static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
+{
+ dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno,
+ readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+}
+
+#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__)
+
+static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
+{
+ unsigned int i;
+ printk(KERN_ERR "i2c: error: %s\n", why);
+ printk(KERN_ERR "i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n",
+ i2c->msg_num, i2c->msg_idx, i2c->msg_ptr);
+ printk(KERN_ERR "i2c: ICR: %08x ISR: %08x\n",
+ readl(_ICR(i2c)), readl(_ISR(i2c)));
+ printk(KERN_DEBUG "i2c: log: ");
+ for (i = 0; i < i2c->irqlogidx; i++)
+ printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]);
+ printk("\n");
+}
+
+#else /* ifdef DEBUG */
+
+#define i2c_debug 0
+
+#define show_state(i2c) do { } while (0)
+#define decode_ISR(val) do { } while (0)
+#define decode_ICR(val) do { } while (0)
+#define i2c_pxa_scream_blue_murder(i2c, why) do { } while (0)
+
+#endif /* ifdef DEBUG / else */
+
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
+
+static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
+{
+ return !(readl(_ICR(i2c)) & ICR_SCLE);
+}
+
+static void i2c_pxa_abort(struct pxa_i2c *i2c)
+{
+ int i = 250;
+
+ if (i2c_pxa_is_slavemode(i2c)) {
+ dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__);
+ return;
+ }
+
+ while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+ unsigned long icr = readl(_ICR(i2c));
+
+ icr &= ~ICR_START;
+ icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
+
+ writel(icr, _ICR(i2c));
+
+ show_state(i2c);
+
+ mdelay(1);
+ i --;
+ }
+
+ writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
+ _ICR(i2c));
+}
+
+static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
+{
+ int timeout = DEF_TIMEOUT;
+
+ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+ if ((readl(_ISR(i2c)) & ISR_SAD) != 0)
+ timeout += 4;
+
+ msleep(2);
+ show_state(i2c);
+ }
+
+ if (timeout < 0)
+ show_state(i2c);
+
+ return timeout < 0 ? I2C_RETRY : 0;
+}
+
+static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
+{
+ unsigned long timeout = jiffies + HZ*4;
+
+ while (time_before(jiffies, timeout)) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+
+ if (readl(_ISR(i2c)) & ISR_SAD) {
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__);
+ goto out;
+ }
+
+ /* wait for unit and bus being not busy, and we also do a
+ * quick check of the i2c lines themselves to ensure they've
+ * gone high...
+ */
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) {
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+ return 1;
+ }
+
+ msleep(1);
+ }
+
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+ out:
+ return 0;
+}
+
+static int i2c_pxa_set_master(struct pxa_i2c *i2c)
+{
+ if (i2c_debug)
+ dev_dbg(&i2c->adap.dev, "setting to bus master\n");
+
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) {
+ dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__);
+ if (!i2c_pxa_wait_master(i2c)) {
+ dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__);
+ return I2C_RETRY;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+ return 0;
+}
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
+{
+ unsigned long timeout = jiffies + HZ*1;
+
+ /* wait for stop */
+
+ show_state(i2c);
+
+ while (time_before(jiffies, timeout)) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+
+ if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 ||
+ (readl(_ISR(i2c)) & ISR_SAD) != 0 ||
+ (readl(_ICR(i2c)) & ICR_SCLE) == 0) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+ return 1;
+ }
+
+ msleep(1);
+ }
+
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+ return 0;
+}
+
+/*
+ * clear the hold on the bus, and take of anything else
+ * that has been configured
+ */
+static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
+{
+ show_state(i2c);
+
+ if (errcode < 0) {
+ udelay(100); /* simple delay */
+ } else {
+ /* we need to wait for the stop condition to end */
+
+ /* if we where in stop, then clear... */
+ if (readl(_ICR(i2c)) & ICR_STOP) {
+ udelay(100);
+ writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c));
+ }
+
+ if (!i2c_pxa_wait_slave(i2c)) {
+ dev_err(&i2c->adap.dev, "%s: wait timedout\n",
+ __func__);
+ return;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+
+ if (i2c_debug) {
+ dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c)));
+ decode_ICR(readl(_ICR(i2c)));
+ }
+}
+#else
+#define i2c_pxa_set_slave(i2c, err) do { } while (0)
+#endif
+
+static void i2c_pxa_reset(struct pxa_i2c *i2c)
+{
+ pr_debug("Resetting I2C Controller Unit\n");
+
+ /* abort any transfer currently under way */
+ i2c_pxa_abort(i2c);
+
+ /* reset according to 9.8 */
+ writel(ICR_UR, _ICR(i2c));
+ writel(I2C_ISR_INIT, _ISR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
+
+ if (i2c->reg_isar)
+ writel(i2c->slave_addr, _ISAR(i2c));
+
+ /* set control register values */
+ writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+ dev_info(&i2c->adap.dev, "Enabling slave mode\n");
+ writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c));
+#endif
+
+ i2c_pxa_set_slave(i2c, 0);
+
+ /* enable unit */
+ writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c));
+ udelay(100);
+}
+
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+/*
+ * PXA I2C Slave mode
+ */
+
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+ if (isr & ISR_BED) {
+ /* what should we do here? */
+ } else {
+ int ret = 0;
+
+ if (i2c->slave != NULL)
+ ret = i2c->slave->read(i2c->slave->data);
+
+ writel(ret, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */
+ }
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+ unsigned int byte = readl(_IDBR(i2c));
+
+ if (i2c->slave != NULL)
+ i2c->slave->write(i2c->slave->data, byte);
+
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+ int timeout;
+
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n",
+ (isr & ISR_RWM) ? 'r' : 't');
+
+ if (i2c->slave != NULL)
+ i2c->slave->event(i2c->slave->data,
+ (isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE);
+
+ /*
+ * slave could interrupt in the middle of us generating a
+ * start condition... if this happens, we'd better back off
+ * and stop holding the poor thing up
+ */
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+
+ timeout = 0x10000;
+
+ while (1) {
+ if ((readl(_IBMR(i2c)) & 2) == 2)
+ break;
+
+ timeout--;
+
+ if (timeout <= 0) {
+ dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+ break;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+ if (i2c_debug > 2)
+ dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n");
+
+ if (i2c->slave != NULL)
+ i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP);
+
+ if (i2c_debug > 2)
+ dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n");
+
+ /*
+ * If we have a master-mode message waiting,
+ * kick it off now that the slave has completed.
+ */
+ if (i2c->msg)
+ i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#else
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+ if (isr & ISR_BED) {
+ /* what should we do here? */
+ } else {
+ writel(0, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+ }
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+ int timeout;
+
+ /*
+ * slave could interrupt in the middle of us generating a
+ * start condition... if this happens, we'd better back off
+ * and stop holding the poor thing up
+ */
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
+
+ timeout = 0x10000;
+
+ while (1) {
+ if ((readl(_IBMR(i2c)) & 2) == 2)
+ break;
+
+ timeout--;
+
+ if (timeout <= 0) {
+ dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+ break;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+ if (i2c->msg)
+ i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#endif
+
+/*
+ * PXA I2C Master mode
+ */
+
+static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg)
+{
+ unsigned int addr = (msg->addr & 0x7f) << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ return addr;
+}
+
+static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
+{
+ u32 icr;
+
+ /*
+ * Step 1: target slave address into IDBR
+ */
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+
+ /*
+ * Step 2: initiate the write.
+ */
+ icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+ writel(icr | ICR_START | ICR_TB, _ICR(i2c));
+}
+
+static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+{
+ u32 icr;
+
+ /*
+ * Clear the STOP and ACK flags
+ */
+ icr = readl(_ICR(i2c));
+ icr &= ~(ICR_STOP | ICR_ACKNAK);
+ writel(icr, _ICR(i2c));
+}
+
+static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
+{
+ /* make timeout the same as for interrupt based functions */
+ long timeout = 2 * DEF_TIMEOUT;
+
+ /*
+ * Wait for the bus to become free.
+ */
+ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+ udelay(1000);
+ show_state(i2c);
+ }
+
+ if (timeout < 0) {
+ show_state(i2c);
+ dev_err(&i2c->adap.dev,
+ "i2c_pxa: timeout waiting for bus free\n");
+ return I2C_RETRY;
+ }
+
+ /*
+ * Set master mode.
+ */
+ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+
+ return 0;
+}
+
+static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
+ struct i2c_msg *msg, int num)
+{
+ unsigned long timeout = 500000; /* 5 seconds */
+ int ret = 0;
+
+ ret = i2c_pxa_pio_set_master(i2c);
+ if (ret)
+ goto out;
+
+ i2c->msg = msg;
+ i2c->msg_num = num;
+ i2c->msg_idx = 0;
+ i2c->msg_ptr = 0;
+ i2c->irqlogidx = 0;
+
+ i2c_pxa_start_message(i2c);
+
+ while (i2c->msg_num > 0 && --timeout) {
+ i2c_pxa_handler(0, i2c);
+ udelay(10);
+ }
+
+ i2c_pxa_stop_message(i2c);
+
+ /*
+ * We place the return code in i2c->msg_idx.
+ */
+ ret = i2c->msg_idx;
+
+out:
+ if (timeout == 0)
+ i2c_pxa_scream_blue_murder(i2c, "timeout");
+
+ return ret;
+}
+
+/*
+ * We are protected by the adapter bus mutex.
+ */
+static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
+{
+ long timeout;
+ int ret;
+
+ /*
+ * Wait for the bus to become free.
+ */
+ ret = i2c_pxa_wait_bus_not_busy(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
+ goto out;
+ }
+
+ /*
+ * Set master mode.
+ */
+ ret = i2c_pxa_set_master(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret);
+ goto out;
+ }
+
+ spin_lock_irq(&i2c->lock);
+
+ i2c->msg = msg;
+ i2c->msg_num = num;
+ i2c->msg_idx = 0;
+ i2c->msg_ptr = 0;
+ i2c->irqlogidx = 0;
+
+ i2c_pxa_start_message(i2c);
+
+ spin_unlock_irq(&i2c->lock);
+
+ /*
+ * The rest of the processing occurs in the interrupt handler.
+ */
+ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+ i2c_pxa_stop_message(i2c);
+
+ /*
+ * We place the return code in i2c->msg_idx.
+ */
+ ret = i2c->msg_idx;
+
+ if (!timeout && i2c->msg_num) {
+ i2c_pxa_scream_blue_murder(i2c, "timeout");
+ ret = I2C_RETRY;
+ }
+
+ out:
+ return ret;
+}
+
+static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct pxa_i2c *i2c = adap->algo_data;
+ int ret, i;
+
+ /* If the I2C controller is disabled we need to reset it
+ (probably due to a suspend/resume destroying state). We do
+ this here as we can then avoid worrying about resuming the
+ controller before its users. */
+ if (!(readl(_ICR(i2c)) & ICR_IUE))
+ i2c_pxa_reset(i2c);
+
+ for (i = adap->retries; i >= 0; i--) {
+ ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+ if (ret != I2C_RETRY)
+ goto out;
+
+ if (i2c_debug)
+ dev_dbg(&adap->dev, "Retrying transmission\n");
+ udelay(100);
+ }
+ i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+ ret = -EREMOTEIO;
+ out:
+ i2c_pxa_set_slave(i2c, ret);
+ return ret;
+}
+
+/*
+ * i2c_pxa_master_complete - complete the message and wake up.
+ */
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
+{
+ i2c->msg_ptr = 0;
+ i2c->msg = NULL;
+ i2c->msg_idx ++;
+ i2c->msg_num = 0;
+ if (ret)
+ i2c->msg_idx = ret;
+ if (!i2c->use_pio)
+ wake_up(&i2c->wait);
+}
+
+static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+ again:
+ /*
+ * If ISR_ALD is set, we lost arbitration.
+ */
+ if (isr & ISR_ALD) {
+ /*
+ * Do we need to do anything here? The PXA docs
+ * are vague about what happens.
+ */
+ i2c_pxa_scream_blue_murder(i2c, "ALD set");
+
+ /*
+ * We ignore this error. We seem to see spurious ALDs
+ * for seemingly no reason. If we handle them as I think
+ * they should, we end up causing an I2C error, which
+ * is painful for some systems.
+ */
+ return; /* ignore */
+ }
+
+ if (isr & ISR_BED) {
+ int ret = BUS_ERROR;
+
+ /*
+ * I2C bus error - either the device NAK'd us, or
+ * something more serious happened. If we were NAK'd
+ * on the initial address phase, we can retry.
+ */
+ if (isr & ISR_ACKNAK) {
+ if (i2c->msg_ptr == 0 && i2c->msg_idx == 0)
+ ret = I2C_RETRY;
+ else
+ ret = XFER_NAKED;
+ }
+ i2c_pxa_master_complete(i2c, ret);
+ } else if (isr & ISR_RWM) {
+ /*
+ * Read mode. We have just sent the address byte, and
+ * now we must initiate the transfer.
+ */
+ if (i2c->msg_ptr == i2c->msg->len - 1 &&
+ i2c->msg_idx == i2c->msg_num - 1)
+ icr |= ICR_STOP | ICR_ACKNAK;
+
+ icr |= ICR_ALDIE | ICR_TB;
+ } else if (i2c->msg_ptr < i2c->msg->len) {
+ /*
+ * Write mode. Write the next data byte.
+ */
+ writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c));
+
+ icr |= ICR_ALDIE | ICR_TB;
+
+ /*
+ * If this is the last byte of the last message, send
+ * a STOP.
+ */
+ if (i2c->msg_ptr == i2c->msg->len &&
+ i2c->msg_idx == i2c->msg_num - 1)
+ icr |= ICR_STOP;
+ } else if (i2c->msg_idx < i2c->msg_num - 1) {
+ /*
+ * Next segment of the message.
+ */
+ i2c->msg_ptr = 0;
+ i2c->msg_idx ++;
+ i2c->msg++;
+
+ /*
+ * If we aren't doing a repeated start and address,
+ * go back and try to send the next byte. Note that
+ * we do not support switching the R/W direction here.
+ */
+ if (i2c->msg->flags & I2C_M_NOSTART)
+ goto again;
+
+ /*
+ * Write the next address.
+ */
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+
+ /*
+ * And trigger a repeated start, and send the byte.
+ */
+ icr &= ~ICR_ALDIE;
+ icr |= ICR_START | ICR_TB;
+ } else {
+ if (i2c->msg->len == 0) {
+ /*
+ * Device probes have a message length of zero
+ * and need the bus to be reset before it can
+ * be used again.
+ */
+ i2c_pxa_reset(i2c);
+ }
+ i2c_pxa_master_complete(i2c, 0);
+ }
+
+ i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+ writel(icr, _ICR(i2c));
+ show_state(i2c);
+}
+
+static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+ /*
+ * Read the byte.
+ */
+ i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c));
+
+ if (i2c->msg_ptr < i2c->msg->len) {
+ /*
+ * If this is the last byte of the last
+ * message, send a STOP.
+ */
+ if (i2c->msg_ptr == i2c->msg->len - 1)
+ icr |= ICR_STOP | ICR_ACKNAK;
+
+ icr |= ICR_ALDIE | ICR_TB;
+ } else {
+ i2c_pxa_master_complete(i2c, 0);
+ }
+
+ i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+ writel(icr, _ICR(i2c));
+}
+
+#define VALID_INT_SOURCE (ISR_SSD | ISR_ALD | ISR_ITE | ISR_IRF | \
+ ISR_SAD | ISR_BED)
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
+{
+ struct pxa_i2c *i2c = dev_id;
+ u32 isr = readl(_ISR(i2c));
+
+ if (!(isr & VALID_INT_SOURCE))
+ return IRQ_NONE;
+
+ if (i2c_debug > 2 && 0) {
+ dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
+ decode_ISR(isr);
+ }
+
+ if (i2c->irqlogidx < ARRAY_SIZE(i2c->isrlog))
+ i2c->isrlog[i2c->irqlogidx++] = isr;
+
+ show_state(i2c);
+
+ /*
+ * Always clear all pending IRQs.
+ */
+ writel(isr & VALID_INT_SOURCE, _ISR(i2c));
+
+ if (isr & ISR_SAD)
+ i2c_pxa_slave_start(i2c, isr);
+ if (isr & ISR_SSD)
+ i2c_pxa_slave_stop(i2c);
+
+ if (i2c_pxa_is_slavemode(i2c)) {
+ if (isr & ISR_ITE)
+ i2c_pxa_slave_txempty(i2c, isr);
+ if (isr & ISR_IRF)
+ i2c_pxa_slave_rxfull(i2c, isr);
+ } else if (i2c->msg) {
+ if (isr & ISR_ITE)
+ i2c_pxa_irq_txempty(i2c, isr);
+ if (isr & ISR_IRF)
+ i2c_pxa_irq_rxfull(i2c, isr);
+ } else {
+ i2c_pxa_scream_blue_murder(i2c, "spurious irq");
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct pxa_i2c *i2c = adap->algo_data;
+ int ret, i;
+
+ for (i = adap->retries; i >= 0; i--) {
+ ret = i2c_pxa_do_xfer(i2c, msgs, num);
+ if (ret != I2C_RETRY)
+ goto out;
+
+ if (i2c_debug)
+ dev_dbg(&adap->dev, "Retrying transmission\n");
+ udelay(100);
+ }
+ i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+ ret = -EREMOTEIO;
+ out:
+ i2c_pxa_set_slave(i2c, ret);
+ return ret;
+}
+
+static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm i2c_pxa_algorithm = {
+ .master_xfer = i2c_pxa_xfer,
+ .functionality = i2c_pxa_functionality,
+};
+
+static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
+ .master_xfer = i2c_pxa_pio_xfer,
+ .functionality = i2c_pxa_functionality,
+};
+
+static int i2c_pxa_probe(struct platform_device *dev)
+{
+ struct pxa_i2c *i2c;
+ struct resource *res;
+ struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
+ const struct platform_device_id *id = platform_get_device_id(dev);
+ enum pxa_i2c_types i2c_type = id->driver_data;
+ int ret;
+ int irq;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(dev, 0);
+ if (res == NULL || irq < 0)
+ return -ENODEV;
+
+ if (!request_mem_region(res->start, resource_size(res), res->name))
+ return -ENOMEM;
+
+ i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto emalloc;
+ }
+
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.retries = 5;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ /*
+ * If "dev->id" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ i2c->adap.nr = dev->id != -1 ? dev->id : 0;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u",
+ i2c->adap.nr);
+
+ i2c->clk = clk_get(&dev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ ret = PTR_ERR(i2c->clk);
+ goto eclk;
+ }
+
+ i2c->reg_base = ioremap(res->start, resource_size(res));
+ if (!i2c->reg_base) {
+ ret = -EIO;
+ goto eremap;
+ }
+
+ i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
+ i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+ i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+ i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+ if (i2c_type != REGS_CE4100)
+ i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
+
+ i2c->iobase = res->start;
+ i2c->iosize = resource_size(res);
+
+ i2c->irq = irq;
+
+ i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+ if (plat) {
+ i2c->slave_addr = plat->slave_addr;
+ i2c->slave = plat->slave;
+ }
+#endif
+
+ clk_enable(i2c->clk);
+
+ if (plat) {
+ i2c->adap.class = plat->class;
+ i2c->use_pio = plat->use_pio;
+ i2c->fast_mode = plat->fast_mode;
+ }
+
+ if (i2c->use_pio) {
+ i2c->adap.algo = &i2c_pxa_pio_algorithm;
+ } else {
+ i2c->adap.algo = &i2c_pxa_algorithm;
+ ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
+ i2c->adap.name, i2c);
+ if (ret)
+ goto ereqirq;
+ }
+
+ i2c_pxa_reset(i2c);
+
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &dev->dev;
+#ifdef CONFIG_OF
+ i2c->adap.dev.of_node = dev->dev.of_node;
+#endif
+
+ if (i2c_type == REGS_CE4100)
+ ret = i2c_add_adapter(&i2c->adap);
+ else
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0) {
+ printk(KERN_INFO "I2C: Failed to add bus\n");
+ goto eadapt;
+ }
+ of_i2c_register_devices(&i2c->adap);
+
+ platform_set_drvdata(dev, i2c);
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+ printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
+ dev_name(&i2c->adap.dev), i2c->slave_addr);
+#else
+ printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
+ dev_name(&i2c->adap.dev));
+#endif
+ return 0;
+
+eadapt:
+ if (!i2c->use_pio)
+ free_irq(irq, i2c);
+ereqirq:
+ clk_disable(i2c->clk);
+ iounmap(i2c->reg_base);
+eremap:
+ clk_put(i2c->clk);
+eclk:
+ kfree(i2c);
+emalloc:
+ release_mem_region(res->start, resource_size(res));
+ return ret;
+}
+
+static int __exit i2c_pxa_remove(struct platform_device *dev)
+{
+ struct pxa_i2c *i2c = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ i2c_del_adapter(&i2c->adap);
+ if (!i2c->use_pio)
+ free_irq(i2c->irq, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->reg_base);
+ release_mem_region(i2c->iobase, i2c->iosize);
+ kfree(i2c);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_pxa_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pxa_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_disable(i2c->clk);
+
+ return 0;
+}
+
+static int i2c_pxa_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pxa_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_enable(i2c->clk);
+ i2c_pxa_reset(i2c);
+
+ return 0;
+}
+
+static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
+ .suspend_noirq = i2c_pxa_suspend_noirq,
+ .resume_noirq = i2c_pxa_resume_noirq,
+};
+
+#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops)
+#else
+#define I2C_PXA_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver i2c_pxa_driver = {
+ .probe = i2c_pxa_probe,
+ .remove = __exit_p(i2c_pxa_remove),
+ .driver = {
+ .name = "pxa2xx-i2c",
+ .owner = THIS_MODULE,
+ .pm = I2C_PXA_DEV_PM_OPS,
+ },
+ .id_table = i2c_pxa_id_table,
+};
+
+static int __init i2c_adap_pxa_init(void)
+{
+ return platform_driver_register(&i2c_pxa_driver);
+}
+
+static void __exit i2c_adap_pxa_exit(void)
+{
+ platform_driver_unregister(&i2c_pxa_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2c");
+
+subsys_initcall(i2c_adap_pxa_init);
+module_exit(i2c_adap_pxa_exit);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
new file mode 100644
index 00000000..f84a63c6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -0,0 +1,1040 @@
+/* linux/drivers/i2c/busses/i2c-s3c2410.c
+ *
+ * Copyright (C) 2004,2005,2009 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 I2C Controller
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+
+/* i2c controller state */
+
+enum s3c24xx_i2c_state {
+ STATE_IDLE,
+ STATE_START,
+ STATE_READ,
+ STATE_WRITE,
+ STATE_STOP
+};
+
+enum s3c24xx_i2c_type {
+ TYPE_S3C2410,
+ TYPE_S3C2440,
+};
+
+struct s3c24xx_i2c {
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ unsigned int suspended:1;
+
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int msg_idx;
+ unsigned int msg_ptr;
+
+ unsigned int tx_setup;
+ unsigned int irq;
+
+ enum s3c24xx_i2c_state state;
+ unsigned long clkrate;
+
+ void __iomem *regs;
+ struct clk *clk;
+ struct device *dev;
+ struct resource *ioarea;
+ struct i2c_adapter adap;
+
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block freq_transition;
+#endif
+};
+
+/* default platform data removed, dev should always carry data. */
+
+/* s3c24xx_i2c_is2440()
+ *
+ * return true is this is an s3c2440
+*/
+
+static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
+{
+ struct platform_device *pdev = to_platform_device(i2c->dev);
+ enum s3c24xx_i2c_type type;
+
+ type = platform_get_device_id(pdev)->driver_data;
+ return type == TYPE_S3C2440;
+}
+
+/* s3c24xx_i2c_master_complete
+ *
+ * complete the message and wake up the caller, using the given return code,
+ * or zero to mean ok.
+*/
+
+static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
+{
+ dev_dbg(i2c->dev, "master_complete %d\n", ret);
+
+ i2c->msg_ptr = 0;
+ i2c->msg = NULL;
+ i2c->msg_idx++;
+ i2c->msg_num = 0;
+ if (ret)
+ i2c->msg_idx = ret;
+
+ wake_up(&i2c->wait);
+}
+
+static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+}
+
+/* irq enable/disable functions */
+
+static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+
+/* s3c24xx_i2c_message_start
+ *
+ * put the start of a message onto the bus
+*/
+
+static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
+ struct i2c_msg *msg)
+{
+ unsigned int addr = (msg->addr & 0x7f) << 1;
+ unsigned long stat;
+ unsigned long iiccon;
+
+ stat = 0;
+ stat |= S3C2410_IICSTAT_TXRXEN;
+
+ if (msg->flags & I2C_M_RD) {
+ stat |= S3C2410_IICSTAT_MASTER_RX;
+ addr |= 1;
+ } else
+ stat |= S3C2410_IICSTAT_MASTER_TX;
+
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
+ /* todo - check for wether ack wanted or not */
+ s3c24xx_i2c_enable_ack(i2c);
+
+ iiccon = readl(i2c->regs + S3C2410_IICCON);
+ writel(stat, i2c->regs + S3C2410_IICSTAT);
+
+ dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
+ writeb(addr, i2c->regs + S3C2410_IICDS);
+
+ /* delay here to ensure the data byte has gotten onto the bus
+ * before the transaction is started */
+
+ ndelay(i2c->tx_setup);
+
+ dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
+ writel(iiccon, i2c->regs + S3C2410_IICCON);
+
+ stat |= S3C2410_IICSTAT_START;
+ writel(stat, i2c->regs + S3C2410_IICSTAT);
+}
+
+static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
+{
+ unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+ dev_dbg(i2c->dev, "STOP\n");
+
+ /* stop the transfer */
+ iicstat &= ~S3C2410_IICSTAT_START;
+ writel(iicstat, i2c->regs + S3C2410_IICSTAT);
+
+ i2c->state = STATE_STOP;
+
+ s3c24xx_i2c_master_complete(i2c, ret);
+ s3c24xx_i2c_disable_irq(i2c);
+}
+
+/* helper functions to determine the current state in the set of
+ * messages we are sending */
+
+/* is_lastmsg()
+ *
+ * returns TRUE if the current message is the last in the set
+*/
+
+static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
+{
+ return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+/* is_msglast
+ *
+ * returns TRUE if we this is the last byte in the current message
+*/
+
+static inline int is_msglast(struct s3c24xx_i2c *i2c)
+{
+ return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/* is_msgend
+ *
+ * returns TRUE if we reached the end of the current message
+*/
+
+static inline int is_msgend(struct s3c24xx_i2c *i2c)
+{
+ return i2c->msg_ptr >= i2c->msg->len;
+}
+
+/* i2c_s3c_irq_nextbyte
+ *
+ * process an interrupt and work out what to do
+ */
+
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
+{
+ unsigned long tmp;
+ unsigned char byte;
+ int ret = 0;
+
+ switch (i2c->state) {
+
+ case STATE_IDLE:
+ dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
+ goto out;
+
+ case STATE_STOP:
+ dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
+ s3c24xx_i2c_disable_irq(i2c);
+ goto out_ack;
+
+ case STATE_START:
+ /* last thing we did was send a start condition on the
+ * bus, or started a new i2c message
+ */
+
+ if (iicstat & S3C2410_IICSTAT_LASTBIT &&
+ !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ /* ack was not received... */
+
+ dev_dbg(i2c->dev, "ack was not received\n");
+ s3c24xx_i2c_stop(i2c, -ENXIO);
+ goto out_ack;
+ }
+
+ if (i2c->msg->flags & I2C_M_RD)
+ i2c->state = STATE_READ;
+ else
+ i2c->state = STATE_WRITE;
+
+ /* terminate the transfer if there is nothing to do
+ * as this is used by the i2c probe to find devices. */
+
+ if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+ s3c24xx_i2c_stop(i2c, 0);
+ goto out_ack;
+ }
+
+ if (i2c->state == STATE_READ)
+ goto prepare_read;
+
+ /* fall through to the write state, as we will need to
+ * send a byte as well */
+
+ case STATE_WRITE:
+ /* we are writing data to the device... check for the
+ * end of the message, and if so, work out what to do
+ */
+
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+ dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+ s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+ goto out_ack;
+ }
+ }
+
+ retry_write:
+
+ if (!is_msgend(i2c)) {
+ byte = i2c->msg->buf[i2c->msg_ptr++];
+ writeb(byte, i2c->regs + S3C2410_IICDS);
+
+ /* delay after writing the byte to allow the
+ * data setup time on the bus, as writing the
+ * data to the register causes the first bit
+ * to appear on SDA, and SCL will change as
+ * soon as the interrupt is acknowledged */
+
+ ndelay(i2c->tx_setup);
+
+ } else if (!is_lastmsg(i2c)) {
+ /* we need to go to the next i2c message */
+
+ dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+
+ /* check to see if we need to do another message */
+ if (i2c->msg->flags & I2C_M_NOSTART) {
+
+ if (i2c->msg->flags & I2C_M_RD) {
+ /* cannot do this, the controller
+ * forces us to send a new START
+ * when we change direction */
+
+ s3c24xx_i2c_stop(i2c, -EINVAL);
+ }
+
+ goto retry_write;
+ } else {
+ /* send the new start */
+ s3c24xx_i2c_message_start(i2c, i2c->msg);
+ i2c->state = STATE_START;
+ }
+
+ } else {
+ /* send stop */
+
+ s3c24xx_i2c_stop(i2c, 0);
+ }
+ break;
+
+ case STATE_READ:
+ /* we have a byte of data in the data register, do
+ * something with it, and then work out wether we are
+ * going to do any more read/write
+ */
+
+ byte = readb(i2c->regs + S3C2410_IICDS);
+ i2c->msg->buf[i2c->msg_ptr++] = byte;
+
+ prepare_read:
+ if (is_msglast(i2c)) {
+ /* last byte of buffer */
+
+ if (is_lastmsg(i2c))
+ s3c24xx_i2c_disable_ack(i2c);
+
+ } else if (is_msgend(i2c)) {
+ /* ok, we've read the entire buffer, see if there
+ * is anything else we need to do */
+
+ if (is_lastmsg(i2c)) {
+ /* last message, send stop and complete */
+ dev_dbg(i2c->dev, "READ: Send Stop\n");
+
+ s3c24xx_i2c_stop(i2c, 0);
+ } else {
+ /* go to the next transfer */
+ dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+ }
+ }
+
+ break;
+ }
+
+ /* acknowlegde the IRQ and get back on with the work */
+
+ out_ack:
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~S3C2410_IICCON_IRQPEND;
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+ out:
+ return ret;
+}
+
+/* s3c24xx_i2c_irq
+ *
+ * top level IRQ servicing routine
+*/
+
+static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
+{
+ struct s3c24xx_i2c *i2c = dev_id;
+ unsigned long status;
+ unsigned long tmp;
+
+ status = readl(i2c->regs + S3C2410_IICSTAT);
+
+ if (status & S3C2410_IICSTAT_ARBITR) {
+ /* deal with arbitration loss */
+ dev_err(i2c->dev, "deal with arbitration loss\n");
+ }
+
+ if (i2c->state == STATE_IDLE) {
+ dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~S3C2410_IICCON_IRQPEND;
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+ goto out;
+ }
+
+ /* pretty much this leaves us with the fact that we've
+ * transmitted or received whatever byte we last sent */
+
+ i2c_s3c_irq_nextbyte(i2c, status);
+
+ out:
+ return IRQ_HANDLED;
+}
+
+
+/* s3c24xx_i2c_set_master
+ *
+ * get the i2c bus for a master transaction
+*/
+
+static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
+{
+ unsigned long iicstat;
+ int timeout = 400;
+
+ while (timeout-- > 0) {
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+ if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
+ return 0;
+
+ msleep(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/* s3c24xx_i2c_doxfer
+ *
+ * this starts an i2c transfer
+*/
+
+static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ unsigned long iicstat, timeout;
+ int spins = 20;
+ int ret;
+
+ if (i2c->suspended)
+ return -EIO;
+
+ ret = s3c24xx_i2c_set_master(i2c);
+ if (ret != 0) {
+ dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ spin_lock_irq(&i2c->lock);
+
+ i2c->msg = msgs;
+ i2c->msg_num = num;
+ i2c->msg_ptr = 0;
+ i2c->msg_idx = 0;
+ i2c->state = STATE_START;
+
+ s3c24xx_i2c_enable_irq(i2c);
+ s3c24xx_i2c_message_start(i2c, msgs);
+ spin_unlock_irq(&i2c->lock);
+
+ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+ ret = i2c->msg_idx;
+
+ /* having these next two as dev_err() makes life very
+ * noisy when doing an i2cdetect */
+
+ if (timeout == 0)
+ dev_dbg(i2c->dev, "timeout\n");
+ else if (ret != num)
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+ /* ensure the stop has been through the bus */
+
+ dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+ /* first, try busy waiting briefly */
+ do {
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ } while ((iicstat & S3C2410_IICSTAT_START) && --spins);
+
+ /* if that timed out sleep */
+ if (!spins) {
+ msleep(1);
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ }
+
+ if (iicstat & S3C2410_IICSTAT_START)
+ dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+
+ out:
+ return ret;
+}
+
+/* s3c24xx_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+*/
+
+static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
+ int retry;
+ int ret;
+
+ clk_enable(i2c->clk);
+
+ for (retry = 0; retry < adap->retries; retry++) {
+
+ ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
+
+ if (ret != -EAGAIN) {
+ clk_disable(i2c->clk);
+ return ret;
+ }
+
+ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+ udelay(100);
+ }
+
+ clk_disable(i2c->clk);
+ return -EREMOTEIO;
+}
+
+/* declare our i2c functionality */
+static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* i2c bus registration info */
+
+static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
+ .master_xfer = s3c24xx_i2c_xfer,
+ .functionality = s3c24xx_i2c_func,
+};
+
+/* s3c24xx_i2c_calcdivisor
+ *
+ * return the divisor settings for a given frequency
+*/
+
+static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
+ unsigned int *div1, unsigned int *divs)
+{
+ unsigned int calc_divs = clkin / wanted;
+ unsigned int calc_div1;
+
+ if (calc_divs > (16*16))
+ calc_div1 = 512;
+ else
+ calc_div1 = 16;
+
+ calc_divs += calc_div1-1;
+ calc_divs /= calc_div1;
+
+ if (calc_divs == 0)
+ calc_divs = 1;
+ if (calc_divs > 17)
+ calc_divs = 17;
+
+ *divs = calc_divs;
+ *div1 = calc_div1;
+
+ return clkin / (calc_divs * calc_div1);
+}
+
+/* s3c24xx_i2c_clockrate
+ *
+ * work out a divisor for the user requested frequency setting,
+ * either by the requested frequency, or scanning the acceptable
+ * range of frequencies until something is found
+*/
+
+static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
+{
+ struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;
+ unsigned long clkin = clk_get_rate(i2c->clk);
+ unsigned int divs, div1;
+ unsigned long target_frequency;
+ u32 iiccon;
+ int freq;
+
+ i2c->clkrate = clkin;
+ clkin /= 1000; /* clkin now in KHz */
+
+ dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);
+
+ target_frequency = pdata->frequency ? pdata->frequency : 100000;
+
+ target_frequency /= 1000; /* Target frequency now in KHz */
+
+ freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);
+
+ if (freq > target_frequency) {
+ dev_err(i2c->dev,
+ "Unable to achieve desired frequency %luKHz." \
+ " Lowest achievable %dKHz\n", target_frequency, freq);
+ return -EINVAL;
+ }
+
+ *got = freq;
+
+ iiccon = readl(i2c->regs + S3C2410_IICCON);
+ iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512);
+ iiccon |= (divs-1);
+
+ if (div1 == 512)
+ iiccon |= S3C2410_IICCON_TXDIV_512;
+
+ writel(iiccon, i2c->regs + S3C2410_IICCON);
+
+ if (s3c24xx_i2c_is2440(i2c)) {
+ unsigned long sda_delay;
+
+ if (pdata->sda_delay) {
+ sda_delay = clkin * pdata->sda_delay;
+ sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
+ sda_delay = DIV_ROUND_UP(sda_delay, 5);
+ if (sda_delay > 3)
+ sda_delay = 3;
+ sda_delay |= S3C2410_IICLC_FILTER_ON;
+ } else
+ sda_delay = 0;
+
+ dev_dbg(i2c->dev, "IICLC=%08lx\n", sda_delay);
+ writel(sda_delay, i2c->regs + S3C2440_IICLC);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition)
+
+static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct s3c24xx_i2c *i2c = freq_to_i2c(nb);
+ unsigned long flags;
+ unsigned int got;
+ int delta_f;
+ int ret;
+
+ delta_f = clk_get_rate(i2c->clk) - i2c->clkrate;
+
+ /* if we're post-change and the input clock has slowed down
+ * or at pre-change and the clock is about to speed up, then
+ * adjust our clock rate. <0 is slow, >0 speedup.
+ */
+
+ if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
+ (val == CPUFREQ_PRECHANGE && delta_f > 0)) {
+ spin_lock_irqsave(&i2c->lock, flags);
+ ret = s3c24xx_i2c_clockrate(i2c, &got);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ if (ret < 0)
+ dev_err(i2c->dev, "cannot find frequency\n");
+ else
+ dev_info(i2c->dev, "setting freq %d\n", got);
+ }
+
+ return 0;
+}
+
+static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)
+{
+ i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition;
+
+ return cpufreq_register_notifier(&i2c->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
+{
+ cpufreq_unregister_notifier(&i2c->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)
+{
+ return 0;
+}
+
+static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
+{
+}
+#endif
+
+/* s3c24xx_i2c_init
+ *
+ * initialise the controller, set the IO lines and frequency
+*/
+
+static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
+{
+ unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
+ struct s3c2410_platform_i2c *pdata;
+ unsigned int freq;
+
+ /* get the plafrom data */
+
+ pdata = i2c->dev->platform_data;
+
+ /* inititalise the gpio */
+
+ if (pdata->cfg_gpio)
+ pdata->cfg_gpio(to_platform_device(i2c->dev));
+
+ /* write slave address */
+
+ writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
+
+ dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
+
+ writel(iicon, i2c->regs + S3C2410_IICCON);
+
+ /* we need to work out the divisors for the clock... */
+
+ if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
+ writel(0, i2c->regs + S3C2410_IICCON);
+ dev_err(i2c->dev, "cannot meet bus frequency required\n");
+ return -EINVAL;
+ }
+
+ /* todo - check that the i2c lines aren't being dragged anywhere */
+
+ dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
+ dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
+
+ return 0;
+}
+
+/* s3c24xx_i2c_probe
+ *
+ * called by the bus driver when a suitable device is found
+*/
+
+static int s3c24xx_i2c_probe(struct platform_device *pdev)
+{
+ struct s3c24xx_i2c *i2c;
+ struct s3c2410_platform_i2c *pdata;
+ struct resource *res;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &s3c24xx_i2c_algorithm;
+ i2c->adap.retries = 2;
+ i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ i2c->tx_setup = 50;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ /* find the clock and enable it */
+
+ i2c->dev = &pdev->dev;
+ i2c->clk = clk_get(&pdev->dev, "i2c");
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ ret = -ENOENT;
+ goto err_noclk;
+ }
+
+ dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
+ clk_enable(i2c->clk);
+
+ /* map the registers */
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err_clk;
+ }
+
+ i2c->ioarea = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+
+ if (i2c->ioarea == NULL) {
+ dev_err(&pdev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err_clk;
+ }
+
+ i2c->regs = ioremap(res->start, resource_size(res));
+
+ if (i2c->regs == NULL) {
+ dev_err(&pdev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_ioarea;
+ }
+
+ dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+ i2c->regs, i2c->ioarea, res);
+
+ /* setup info block for the i2c core */
+
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &pdev->dev;
+
+ /* initialise the i2c controller */
+
+ ret = s3c24xx_i2c_init(i2c);
+ if (ret != 0)
+ goto err_iomap;
+
+ /* find the IRQ for this unit (note, this relies on the init call to
+ * ensure no current IRQs pending
+ */
+
+ i2c->irq = ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ goto err_iomap;
+ }
+
+ ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
+ dev_name(&pdev->dev), i2c);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ goto err_iomap;
+ }
+
+ ret = s3c24xx_i2c_register_cpufreq(i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+ goto err_irq;
+ }
+
+ /* Note, previous versions of the driver used i2c_add_adapter()
+ * to add the bus at any number. We now pass the bus number via
+ * the platform data, so if unset it will now default to always
+ * being bus 0.
+ */
+
+ i2c->adap.nr = pdata->bus_num;
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+ goto err_cpufreq;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
+ clk_disable(i2c->clk);
+ return 0;
+
+ err_cpufreq:
+ s3c24xx_i2c_deregister_cpufreq(i2c);
+
+ err_irq:
+ free_irq(i2c->irq, i2c);
+
+ err_iomap:
+ iounmap(i2c->regs);
+
+ err_ioarea:
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+
+ err_clk:
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ err_noclk:
+ kfree(i2c);
+ return ret;
+}
+
+/* s3c24xx_i2c_remove
+ *
+ * called when device is removed from the bus
+*/
+
+static int s3c24xx_i2c_remove(struct platform_device *pdev)
+{
+ struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+ s3c24xx_i2c_deregister_cpufreq(i2c);
+
+ i2c_del_adapter(&i2c->adap);
+ free_irq(i2c->irq, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->regs);
+
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+ kfree(i2c);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c24xx_i2c_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c->suspended = 1;
+
+ return 0;
+}
+
+static int s3c24xx_i2c_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c->suspended = 0;
+ clk_enable(i2c->clk);
+ s3c24xx_i2c_init(i2c);
+ clk_disable(i2c->clk);
+
+ return 0;
+}
+
+static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
+ .suspend_noirq = s3c24xx_i2c_suspend_noirq,
+ .resume = s3c24xx_i2c_resume,
+};
+
+#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
+#else
+#define S3C24XX_DEV_PM_OPS NULL
+#endif
+
+/* device driver for platform bus bits */
+
+static struct platform_device_id s3c24xx_driver_ids[] = {
+ {
+ .name = "s3c2410-i2c",
+ .driver_data = TYPE_S3C2410,
+ }, {
+ .name = "s3c2440-i2c",
+ .driver_data = TYPE_S3C2440,
+ }, { },
+};
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+
+static struct platform_driver s3c24xx_i2c_driver = {
+ .probe = s3c24xx_i2c_probe,
+ .remove = s3c24xx_i2c_remove,
+ .id_table = s3c24xx_driver_ids,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s3c-i2c",
+ .pm = S3C24XX_DEV_PM_OPS,
+ },
+};
+
+static int __init i2c_adap_s3c_init(void)
+{
+ return platform_driver_register(&s3c24xx_i2c_driver);
+}
+subsys_initcall(i2c_adap_s3c_init);
+
+static void __exit i2c_adap_s3c_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_i2c_driver);
+}
+module_exit(i2c_adap_s3c_exit);
+
+MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c
new file mode 100644
index 00000000..cb5d01e2
--- /dev/null
+++ b/drivers/i2c/busses/i2c-s6000.c
@@ -0,0 +1,407 @@
+/*
+ * drivers/i2c/busses/i2c-s6000.c
+ *
+ * Description: Driver for S6000 Family I2C Interface
+ * Copyright (c) 2008 emlix GmbH
+ * Author: Oskar Schirmer <os@emlix.com>
+ *
+ * Partially based on i2c-bfin-twi.c driver by <sonic.zhang@analog.com>
+ * Copyright (c) 2005-2007 Analog Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c/s6000.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include "i2c-s6000.h"
+
+#define DRV_NAME "i2c-s6000"
+
+#define POLL_TIMEOUT (2 * HZ)
+
+struct s6i2c_if {
+ u8 __iomem *reg; /* memory mapped registers */
+ int irq;
+ spinlock_t lock;
+ struct i2c_msg *msgs; /* messages currently handled */
+ int msgs_num; /* nb of msgs to do */
+ int msgs_push; /* nb of msgs read/written */
+ int msgs_done; /* nb of msgs finally handled */
+ unsigned push; /* nb of bytes read/written in msg */
+ unsigned done; /* nb of bytes finally handled */
+ int timeout_count; /* timeout retries left */
+ struct timer_list timeout_timer;
+ struct i2c_adapter adap;
+ struct completion complete;
+ struct clk *clk;
+ struct resource *res;
+};
+
+static inline u16 i2c_rd16(struct s6i2c_if *iface, unsigned n)
+{
+ return readw(iface->reg + (n));
+}
+
+static inline void i2c_wr16(struct s6i2c_if *iface, unsigned n, u16 v)
+{
+ writew(v, iface->reg + (n));
+}
+
+static inline u32 i2c_rd32(struct s6i2c_if *iface, unsigned n)
+{
+ return readl(iface->reg + (n));
+}
+
+static inline void i2c_wr32(struct s6i2c_if *iface, unsigned n, u32 v)
+{
+ writel(v, iface->reg + (n));
+}
+
+static struct s6i2c_if s6i2c_if;
+
+static void s6i2c_handle_interrupt(struct s6i2c_if *iface)
+{
+ if (i2c_rd16(iface, S6_I2C_INTRSTAT) & (1 << S6_I2C_INTR_TXABRT)) {
+ i2c_rd16(iface, S6_I2C_CLRTXABRT);
+ i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+ complete(&iface->complete);
+ return;
+ }
+ if (iface->msgs_done >= iface->msgs_num) {
+ dev_err(&iface->adap.dev, "s6i2c: spurious I2C irq: %04x\n",
+ i2c_rd16(iface, S6_I2C_INTRSTAT));
+ i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+ return;
+ }
+ while ((iface->msgs_push < iface->msgs_num)
+ && (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_TFNF))) {
+ struct i2c_msg *m = &iface->msgs[iface->msgs_push];
+ if (!(m->flags & I2C_M_RD))
+ i2c_wr16(iface, S6_I2C_DATACMD, m->buf[iface->push]);
+ else
+ i2c_wr16(iface, S6_I2C_DATACMD,
+ 1 << S6_I2C_DATACMD_READ);
+ if (++iface->push >= m->len) {
+ iface->push = 0;
+ iface->msgs_push += 1;
+ }
+ }
+ do {
+ struct i2c_msg *m = &iface->msgs[iface->msgs_done];
+ if (!(m->flags & I2C_M_RD)) {
+ if (iface->msgs_done < iface->msgs_push)
+ iface->msgs_done += 1;
+ else
+ break;
+ } else if (i2c_rd16(iface, S6_I2C_STATUS)
+ & (1 << S6_I2C_STATUS_RFNE)) {
+ m->buf[iface->done] = i2c_rd16(iface, S6_I2C_DATACMD);
+ if (++iface->done >= m->len) {
+ iface->done = 0;
+ iface->msgs_done += 1;
+ }
+ } else{
+ break;
+ }
+ } while (iface->msgs_done < iface->msgs_num);
+ if (iface->msgs_done >= iface->msgs_num) {
+ i2c_wr16(iface, S6_I2C_INTRMASK, 1 << S6_I2C_INTR_TXABRT);
+ complete(&iface->complete);
+ } else if (iface->msgs_push >= iface->msgs_num) {
+ i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXABRT) |
+ (1 << S6_I2C_INTR_RXFULL));
+ } else {
+ i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXABRT) |
+ (1 << S6_I2C_INTR_TXEMPTY) |
+ (1 << S6_I2C_INTR_RXFULL));
+ }
+}
+
+static irqreturn_t s6i2c_interrupt_entry(int irq, void *dev_id)
+{
+ struct s6i2c_if *iface = dev_id;
+ if (!(i2c_rd16(iface, S6_I2C_STATUS) & ((1 << S6_I2C_INTR_RXUNDER)
+ | (1 << S6_I2C_INTR_RXOVER)
+ | (1 << S6_I2C_INTR_RXFULL)
+ | (1 << S6_I2C_INTR_TXOVER)
+ | (1 << S6_I2C_INTR_TXEMPTY)
+ | (1 << S6_I2C_INTR_RDREQ)
+ | (1 << S6_I2C_INTR_TXABRT)
+ | (1 << S6_I2C_INTR_RXDONE)
+ | (1 << S6_I2C_INTR_ACTIVITY)
+ | (1 << S6_I2C_INTR_STOPDET)
+ | (1 << S6_I2C_INTR_STARTDET)
+ | (1 << S6_I2C_INTR_GENCALL))))
+ return IRQ_NONE;
+
+ spin_lock(&iface->lock);
+ del_timer(&iface->timeout_timer);
+ s6i2c_handle_interrupt(iface);
+ spin_unlock(&iface->lock);
+ return IRQ_HANDLED;
+}
+
+static void s6i2c_timeout(unsigned long data)
+{
+ struct s6i2c_if *iface = (struct s6i2c_if *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ s6i2c_handle_interrupt(iface);
+ if (--iface->timeout_count > 0) {
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+ } else {
+ complete(&iface->complete);
+ i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+ }
+ spin_unlock_irqrestore(&iface->lock, flags);
+}
+
+static int s6i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct s6i2c_if *iface = adap->algo_data;
+ int i;
+ if (num == 0)
+ return 0;
+ if (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_ACTIVITY))
+ yield();
+ i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+ i2c_rd16(iface, S6_I2C_CLRINTR);
+ for (i = 0; i < num; i++) {
+ if (msgs[i].flags & I2C_M_TEN) {
+ dev_err(&adap->dev,
+ "s6i2c: 10 bits addr not supported\n");
+ return -EINVAL;
+ }
+ if (msgs[i].len == 0) {
+ dev_err(&adap->dev,
+ "s6i2c: zero length message not supported\n");
+ return -EINVAL;
+ }
+ if (msgs[i].addr != msgs[0].addr) {
+ dev_err(&adap->dev,
+ "s6i2c: multiple xfer cannot change target\n");
+ return -EINVAL;
+ }
+ }
+
+ iface->msgs = msgs;
+ iface->msgs_num = num;
+ iface->msgs_push = 0;
+ iface->msgs_done = 0;
+ iface->push = 0;
+ iface->done = 0;
+ iface->timeout_count = 10;
+ i2c_wr16(iface, S6_I2C_TAR, msgs[0].addr);
+ i2c_wr16(iface, S6_I2C_ENABLE, 1);
+ i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXEMPTY) |
+ (1 << S6_I2C_INTR_TXABRT));
+
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+ wait_for_completion(&iface->complete);
+ del_timer_sync(&iface->timeout_timer);
+ while (i2c_rd32(iface, S6_I2C_TXFLR) > 0)
+ schedule();
+ while (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_ACTIVITY))
+ schedule();
+
+ i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+ i2c_wr16(iface, S6_I2C_ENABLE, 0);
+ return iface->msgs_done;
+}
+
+static u32 s6i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm s6i2c_algorithm = {
+ .master_xfer = s6i2c_master_xfer,
+ .functionality = s6i2c_functionality,
+};
+
+static u16 __devinit nanoseconds_on_clk(struct s6i2c_if *iface, u32 ns)
+{
+ u32 dividend = ((clk_get_rate(iface->clk) / 1000) * ns) / 1000000;
+ if (dividend > 0xffff)
+ return 0xffff;
+ return dividend;
+}
+
+static int __devinit s6i2c_probe(struct platform_device *dev)
+{
+ struct s6i2c_if *iface = &s6i2c_if;
+ struct i2c_adapter *p_adap;
+ const char *clock;
+ int bus_num, rc;
+ spin_lock_init(&iface->lock);
+ init_completion(&iface->complete);
+ iface->irq = platform_get_irq(dev, 0);
+ if (iface->irq < 0) {
+ rc = iface->irq;
+ goto err_out;
+ }
+ iface->res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!iface->res) {
+ rc = -ENXIO;
+ goto err_out;
+ }
+ iface->res = request_mem_region(iface->res->start,
+ resource_size(iface->res),
+ dev->dev.bus_id);
+ if (!iface->res) {
+ rc = -EBUSY;
+ goto err_out;
+ }
+ iface->reg = ioremap_nocache(iface->res->start,
+ resource_size(iface->res));
+ if (!iface->reg) {
+ rc = -ENOMEM;
+ goto err_reg;
+ }
+
+ clock = 0;
+ bus_num = -1;
+ if (dev->dev.platform_data) {
+ struct s6_i2c_platform_data *pdata = dev->dev.platform_data;
+ bus_num = pdata->bus_num;
+ clock = pdata->clock;
+ }
+ iface->clk = clk_get(&dev->dev, clock);
+ if (IS_ERR(iface->clk)) {
+ rc = PTR_ERR(iface->clk);
+ goto err_map;
+ }
+ rc = clk_enable(iface->clk);
+ if (rc < 0)
+ goto err_clk_put;
+ init_timer(&iface->timeout_timer);
+ iface->timeout_timer.function = s6i2c_timeout;
+ iface->timeout_timer.data = (unsigned long)iface;
+
+ p_adap = &iface->adap;
+ strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+ p_adap->algo = &s6i2c_algorithm;
+ p_adap->algo_data = iface;
+ p_adap->nr = bus_num;
+ p_adap->class = 0;
+ p_adap->dev.parent = &dev->dev;
+ i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+ rc = request_irq(iface->irq, s6i2c_interrupt_entry,
+ IRQF_SHARED, dev->name, iface);
+ if (rc) {
+ dev_err(&p_adap->dev, "s6i2c: can't get IRQ %d\n", iface->irq);
+ goto err_clk_dis;
+ }
+
+ i2c_wr16(iface, S6_I2C_ENABLE, 0);
+ udelay(1);
+ i2c_wr32(iface, S6_I2C_SRESET, 1 << S6_I2C_SRESET_IC_SRST);
+ i2c_wr16(iface, S6_I2C_CLRTXABRT, 1);
+ i2c_wr16(iface, S6_I2C_CON,
+ (1 << S6_I2C_CON_MASTER) |
+ (S6_I2C_CON_SPEED_NORMAL << S6_I2C_CON_SPEED) |
+ (0 << S6_I2C_CON_10BITSLAVE) |
+ (0 << S6_I2C_CON_10BITMASTER) |
+ (1 << S6_I2C_CON_RESTARTENA) |
+ (1 << S6_I2C_CON_SLAVEDISABLE));
+ i2c_wr16(iface, S6_I2C_SSHCNT, nanoseconds_on_clk(iface, 4000));
+ i2c_wr16(iface, S6_I2C_SSLCNT, nanoseconds_on_clk(iface, 4700));
+ i2c_wr16(iface, S6_I2C_FSHCNT, nanoseconds_on_clk(iface, 600));
+ i2c_wr16(iface, S6_I2C_FSLCNT, nanoseconds_on_clk(iface, 1300));
+ i2c_wr16(iface, S6_I2C_RXTL, 0);
+ i2c_wr16(iface, S6_I2C_TXTL, 0);
+
+ platform_set_drvdata(dev, iface);
+ if (bus_num < 0)
+ rc = i2c_add_adapter(p_adap);
+ else
+ rc = i2c_add_numbered_adapter(p_adap);
+ if (rc)
+ goto err_irq_free;
+ return 0;
+
+err_irq_free:
+ free_irq(iface->irq, iface);
+err_clk_dis:
+ clk_disable(iface->clk);
+err_clk_put:
+ clk_put(iface->clk);
+err_map:
+ iounmap(iface->reg);
+err_reg:
+ release_mem_region(iface->res->start,
+ resource_size(iface->res));
+err_out:
+ return rc;
+}
+
+static int __devexit s6i2c_remove(struct platform_device *pdev)
+{
+ struct s6i2c_if *iface = platform_get_drvdata(pdev);
+ i2c_wr16(iface, S6_I2C_ENABLE, 0);
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&iface->adap);
+ free_irq(iface->irq, iface);
+ clk_disable(iface->clk);
+ clk_put(iface->clk);
+ iounmap(iface->reg);
+ release_mem_region(iface->res->start,
+ resource_size(iface->res));
+ return 0;
+}
+
+static struct platform_driver s6i2c_driver = {
+ .probe = s6i2c_probe,
+ .remove = __devexit_p(s6i2c_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s6i2c_init(void)
+{
+ pr_info("I2C: S6000 I2C driver\n");
+ return platform_driver_register(&s6i2c_driver);
+}
+
+static void __exit s6i2c_exit(void)
+{
+ platform_driver_unregister(&s6i2c_driver);
+}
+
+MODULE_DESCRIPTION("I2C-Bus adapter routines for S6000 I2C");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+
+subsys_initcall(s6i2c_init);
+module_exit(s6i2c_exit);
diff --git a/drivers/i2c/busses/i2c-s6000.h b/drivers/i2c/busses/i2c-s6000.h
new file mode 100644
index 00000000..ff23b81d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-s6000.h
@@ -0,0 +1,79 @@
+/*
+ * drivers/i2c/busses/i2c-s6000.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Emlix GmbH <info@emlix.com>
+ * Author: Oskar Schirmer <os@emlix.com>
+ */
+
+#ifndef __DRIVERS_I2C_BUSSES_I2C_S6000_H
+#define __DRIVERS_I2C_BUSSES_I2C_S6000_H
+
+#define S6_I2C_CON 0x000
+#define S6_I2C_CON_MASTER 0
+#define S6_I2C_CON_SPEED 1
+#define S6_I2C_CON_SPEED_NORMAL 1
+#define S6_I2C_CON_SPEED_FAST 2
+#define S6_I2C_CON_SPEED_MASK 3
+#define S6_I2C_CON_10BITSLAVE 3
+#define S6_I2C_CON_10BITMASTER 4
+#define S6_I2C_CON_RESTARTENA 5
+#define S6_I2C_CON_SLAVEDISABLE 6
+#define S6_I2C_TAR 0x004
+#define S6_I2C_TAR_GCORSTART 10
+#define S6_I2C_TAR_SPECIAL 11
+#define S6_I2C_SAR 0x008
+#define S6_I2C_HSMADDR 0x00C
+#define S6_I2C_DATACMD 0x010
+#define S6_I2C_DATACMD_READ 8
+#define S6_I2C_SSHCNT 0x014
+#define S6_I2C_SSLCNT 0x018
+#define S6_I2C_FSHCNT 0x01C
+#define S6_I2C_FSLCNT 0x020
+#define S6_I2C_INTRSTAT 0x02C
+#define S6_I2C_INTRMASK 0x030
+#define S6_I2C_RAWINTR 0x034
+#define S6_I2C_INTR_RXUNDER 0
+#define S6_I2C_INTR_RXOVER 1
+#define S6_I2C_INTR_RXFULL 2
+#define S6_I2C_INTR_TXOVER 3
+#define S6_I2C_INTR_TXEMPTY 4
+#define S6_I2C_INTR_RDREQ 5
+#define S6_I2C_INTR_TXABRT 6
+#define S6_I2C_INTR_RXDONE 7
+#define S6_I2C_INTR_ACTIVITY 8
+#define S6_I2C_INTR_STOPDET 9
+#define S6_I2C_INTR_STARTDET 10
+#define S6_I2C_INTR_GENCALL 11
+#define S6_I2C_RXTL 0x038
+#define S6_I2C_TXTL 0x03C
+#define S6_I2C_CLRINTR 0x040
+#define S6_I2C_CLRRXUNDER 0x044
+#define S6_I2C_CLRRXOVER 0x048
+#define S6_I2C_CLRTXOVER 0x04C
+#define S6_I2C_CLRRDREQ 0x050
+#define S6_I2C_CLRTXABRT 0x054
+#define S6_I2C_CLRRXDONE 0x058
+#define S6_I2C_CLRACTIVITY 0x05C
+#define S6_I2C_CLRSTOPDET 0x060
+#define S6_I2C_CLRSTARTDET 0x064
+#define S6_I2C_CLRGENCALL 0x068
+#define S6_I2C_ENABLE 0x06C
+#define S6_I2C_STATUS 0x070
+#define S6_I2C_STATUS_ACTIVITY 0
+#define S6_I2C_STATUS_TFNF 1
+#define S6_I2C_STATUS_TFE 2
+#define S6_I2C_STATUS_RFNE 3
+#define S6_I2C_STATUS_RFF 4
+#define S6_I2C_TXFLR 0x074
+#define S6_I2C_RXFLR 0x078
+#define S6_I2C_SRESET 0x07C
+#define S6_I2C_SRESET_IC_SRST 0
+#define S6_I2C_SRESET_IC_MASTER_SRST 1
+#define S6_I2C_SRESET_IC_SLAVE_SRST 2
+#define S6_I2C_TXABRTSOURCE 0x080
+
+#endif
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
new file mode 100644
index 00000000..388cbdc9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -0,0 +1,445 @@
+/*
+ * SMBus driver for ACPI SMBus CMI
+ *
+ * Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#define ACPI_SMBUS_HC_CLASS "smbus"
+#define ACPI_SMBUS_HC_DEVICE_NAME "cmi"
+
+ACPI_MODULE_NAME("smbus_cmi");
+
+struct smbus_methods_t {
+ char *mt_info;
+ char *mt_sbr;
+ char *mt_sbw;
+};
+
+struct acpi_smbus_cmi {
+ acpi_handle handle;
+ struct i2c_adapter adapter;
+ 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 = {
+ .mt_info = "_SBI",
+ .mt_sbr = "_SBR",
+ .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", (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
+#define ACPI_SMBUS_STATUS_DNAK 0x10
+#define ACPI_SMBUS_STATUS_DERR 0x11
+#define ACPI_SMBUS_STATUS_CMD_DENY 0x12
+#define ACPI_SMBUS_STATUS_UNKNOWN 0x13
+#define ACPI_SMBUS_STATUS_ACC_DENY 0x17
+#define ACPI_SMBUS_STATUS_TIMEOUT 0x18
+#define ACPI_SMBUS_STATUS_NOTSUP 0x19
+#define ACPI_SMBUS_STATUS_BUSY 0x1a
+#define ACPI_SMBUS_STATUS_PEC 0x1f
+
+#define ACPI_SMBUS_PRTCL_WRITE 0x00
+#define ACPI_SMBUS_PRTCL_READ 0x01
+#define ACPI_SMBUS_PRTCL_QUICK 0x02
+#define ACPI_SMBUS_PRTCL_BYTE 0x04
+#define ACPI_SMBUS_PRTCL_BYTE_DATA 0x06
+#define ACPI_SMBUS_PRTCL_WORD_DATA 0x08
+#define ACPI_SMBUS_PRTCL_BLOCK_DATA 0x0a
+
+
+static int
+acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ int result = 0;
+ struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
+ unsigned char protocol;
+ acpi_status status = 0;
+ struct acpi_object_list input;
+ union acpi_object mt_params[5];
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ union acpi_object *pkg;
+ char *method;
+ int len = 0;
+
+ dev_dbg(&adap->dev, "access size: %d %s\n", size,
+ (read_write) ? "READ" : "WRITE");
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ protocol = ACPI_SMBUS_PRTCL_QUICK;
+ command = 0;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 0;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = 0;
+ }
+ break;
+
+ case I2C_SMBUS_BYTE:
+ protocol = ACPI_SMBUS_PRTCL_BYTE;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 0;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = 0;
+ } else {
+ command = 0;
+ }
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 1;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = data->byte;
+ }
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 2;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = data->word;
+ }
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = len;
+ mt_params[4].type = ACPI_TYPE_BUFFER;
+ mt_params[4].buffer.pointer = data->block + 1;
+ }
+ break;
+
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ if (read_write == I2C_SMBUS_READ) {
+ protocol |= ACPI_SMBUS_PRTCL_READ;
+ method = smbus_cmi->methods->mt_sbr;
+ input.count = 3;
+ } else {
+ protocol |= ACPI_SMBUS_PRTCL_WRITE;
+ method = smbus_cmi->methods->mt_sbw;
+ input.count = 5;
+ }
+
+ input.pointer = mt_params;
+ mt_params[0].type = ACPI_TYPE_INTEGER;
+ mt_params[0].integer.value = protocol;
+ mt_params[1].type = ACPI_TYPE_INTEGER;
+ mt_params[1].integer.value = addr;
+ mt_params[2].type = ACPI_TYPE_INTEGER;
+ mt_params[2].integer.value = command;
+
+ status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
+ &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "Evaluating %s: %i", method, status));
+ return -EIO;
+ }
+
+ pkg = buffer.pointer;
+ if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
+ obj = pkg->package.elements;
+ else {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ result = -EIO;
+ goto out;
+ }
+ if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ result = -EIO;
+ goto out;
+ }
+
+ result = obj->integer.value;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s return status: %i\n",
+ method, result));
+
+ switch (result) {
+ case ACPI_SMBUS_STATUS_OK:
+ result = 0;
+ break;
+ case ACPI_SMBUS_STATUS_BUSY:
+ result = -EBUSY;
+ goto out;
+ case ACPI_SMBUS_STATUS_TIMEOUT:
+ result = -ETIMEDOUT;
+ goto out;
+ case ACPI_SMBUS_STATUS_DNAK:
+ result = -ENXIO;
+ goto out;
+ default:
+ result = -EIO;
+ goto out;
+ }
+
+ if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
+ goto out;
+
+ obj = pkg->package.elements + 1;
+ if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ result = -EIO;
+ goto out;
+ }
+
+ len = obj->integer.value;
+ obj = pkg->package.elements + 2;
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ case I2C_SMBUS_WORD_DATA:
+ if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ result = -EIO;
+ goto out;
+ }
+ if (len == 2)
+ data->word = obj->integer.value;
+ else
+ data->byte = obj->integer.value;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ result = -EIO;
+ goto out;
+ }
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ data->block[0] = len;
+ memcpy(data->block + 1, obj->buffer.pointer, len);
+ break;
+ }
+
+out:
+ kfree(buffer.pointer);
+ dev_dbg(&adap->dev, "Transaction status: %i\n", result);
+ return result;
+}
+
+static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
+{
+ struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
+ u32 ret;
+
+ ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
+ I2C_FUNC_SMBUS_QUICK : 0;
+
+ ret |= smbus_cmi->cap_read ?
+ (I2C_FUNC_SMBUS_READ_BYTE |
+ I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
+
+ ret |= smbus_cmi->cap_write ?
+ (I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
+
+ return ret;
+}
+
+static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
+ .smbus_xfer = acpi_smbus_cmi_access,
+ .functionality = acpi_smbus_cmi_func,
+};
+
+
+static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
+ const char *name)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+
+ if (!strcmp(name, smbus_cmi->methods->mt_info)) {
+ status = acpi_evaluate_object(smbus_cmi->handle,
+ smbus_cmi->methods->mt_info,
+ NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
+ smbus_cmi->methods->mt_info, status));
+ return -EIO;
+ }
+
+ obj = buffer.pointer;
+ if (obj && obj->type == ACPI_TYPE_PACKAGE)
+ obj = obj->package.elements;
+ else {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ kfree(buffer.pointer);
+ return -EIO;
+ }
+
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ ACPI_ERROR((AE_INFO, "Invalid argument type"));
+ kfree(buffer.pointer);
+ return -EIO;
+ } else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SMBus CMI Version %x"
+ "\n", (int)obj->integer.value));
+
+ kfree(buffer.pointer);
+ smbus_cmi->cap_info = 1;
+ } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
+ smbus_cmi->cap_read = 1;
+ 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",
+ name));
+
+ return 0;
+}
+
+static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
+ void *context, void **return_value)
+{
+ char node_name[5];
+ struct acpi_buffer buffer = { sizeof(node_name), node_name };
+ struct acpi_smbus_cmi *smbus_cmi = context;
+ acpi_status status;
+
+ status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+
+ if (ACPI_SUCCESS(status))
+ acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
+
+ return AE_OK;
+}
+
+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)
+ return -ENOMEM;
+
+ smbus_cmi->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
+ device->driver_data = smbus_cmi;
+ smbus_cmi->cap_info = 0;
+ 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, NULL, smbus_cmi, NULL);
+
+ if (smbus_cmi->cap_info == 0)
+ goto err;
+
+ snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
+ "SMBus CMI adapter %s",
+ acpi_device_name(device));
+ smbus_cmi->adapter.owner = THIS_MODULE;
+ smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
+ smbus_cmi->adapter.algo_data = smbus_cmi;
+ smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus_cmi->adapter.dev.parent = &device->dev;
+
+ if (i2c_add_adapter(&smbus_cmi->adapter)) {
+ dev_err(&device->dev, "Couldn't register adapter!\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ kfree(smbus_cmi);
+ device->driver_data = NULL;
+ return -EIO;
+}
+
+static int acpi_smbus_cmi_remove(struct acpi_device *device, int type)
+{
+ struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
+
+ i2c_del_adapter(&smbus_cmi->adapter);
+ kfree(smbus_cmi);
+ device->driver_data = NULL;
+
+ return 0;
+}
+
+static struct acpi_driver acpi_smbus_cmi_driver = {
+ .name = ACPI_SMBUS_HC_DEVICE_NAME,
+ .class = ACPI_SMBUS_HC_CLASS,
+ .ids = acpi_smbus_cmi_ids,
+ .ops = {
+ .add = acpi_smbus_cmi_add,
+ .remove = acpi_smbus_cmi_remove,
+ },
+};
+
+static int __init acpi_smbus_cmi_init(void)
+{
+ return acpi_bus_register_driver(&acpi_smbus_cmi_driver);
+}
+
+static void __exit acpi_smbus_cmi_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_smbus_cmi_driver);
+}
+
+module_init(acpi_smbus_cmi_init);
+module_exit(acpi_smbus_cmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
+MODULE_DESCRIPTION("ACPI SMBus CMI driver");
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
new file mode 100644
index 00000000..3cad8fec
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -0,0 +1,577 @@
+/*
+ * I2C bus driver for the SH7760 I2C Interfaces.
+ *
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *
+ * licensed under the terms outlined in the file COPYING.
+ *
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <asm/clock.h>
+#include <asm/i2c-sh7760.h>
+
+/* register offsets */
+#define I2CSCR 0x0 /* slave ctrl */
+#define I2CMCR 0x4 /* master ctrl */
+#define I2CSSR 0x8 /* slave status */
+#define I2CMSR 0xC /* master status */
+#define I2CSIER 0x10 /* slave irq enable */
+#define I2CMIER 0x14 /* master irq enable */
+#define I2CCCR 0x18 /* clock dividers */
+#define I2CSAR 0x1c /* slave address */
+#define I2CMAR 0x20 /* master address */
+#define I2CRXTX 0x24 /* data port */
+#define I2CFCR 0x28 /* fifo control */
+#define I2CFSR 0x2C /* fifo status */
+#define I2CFIER 0x30 /* fifo irq enable */
+#define I2CRFDR 0x34 /* rx fifo count */
+#define I2CTFDR 0x38 /* tx fifo count */
+
+#define REGSIZE 0x3C
+
+#define MCR_MDBS 0x80 /* non-fifo mode switch */
+#define MCR_FSCL 0x40 /* override SCL pin */
+#define MCR_FSDA 0x20 /* override SDA pin */
+#define MCR_OBPC 0x10 /* override pins */
+#define MCR_MIE 0x08 /* master if enable */
+#define MCR_TSBE 0x04
+#define MCR_FSB 0x02 /* force stop bit */
+#define MCR_ESG 0x01 /* en startbit gen. */
+
+#define MSR_MNR 0x40 /* nack received */
+#define MSR_MAL 0x20 /* arbitration lost */
+#define MSR_MST 0x10 /* sent a stop */
+#define MSR_MDE 0x08
+#define MSR_MDT 0x04
+#define MSR_MDR 0x02
+#define MSR_MAT 0x01 /* slave addr xfer done */
+
+#define MIE_MNRE 0x40 /* nack irq en */
+#define MIE_MALE 0x20 /* arblos irq en */
+#define MIE_MSTE 0x10 /* stop irq en */
+#define MIE_MDEE 0x08
+#define MIE_MDTE 0x04
+#define MIE_MDRE 0x02
+#define MIE_MATE 0x01 /* address sent irq en */
+
+#define FCR_RFRST 0x02 /* reset rx fifo */
+#define FCR_TFRST 0x01 /* reset tx fifo */
+
+#define FSR_TEND 0x04 /* last byte sent */
+#define FSR_RDF 0x02 /* rx fifo trigger */
+#define FSR_TDFE 0x01 /* tx fifo empty */
+
+#define FIER_TEIE 0x04 /* tx fifo empty irq en */
+#define FIER_RXIE 0x02 /* rx fifo trig irq en */
+#define FIER_TXIE 0x01 /* tx fifo trig irq en */
+
+#define FIFO_SIZE 16
+
+struct cami2c {
+ void __iomem *iobase;
+ struct i2c_adapter adap;
+
+ /* message processing */
+ struct i2c_msg *msg;
+#define IDF_SEND 1
+#define IDF_RECV 2
+#define IDF_STOP 4
+ int flags;
+
+#define IDS_DONE 1
+#define IDS_ARBLOST 2
+#define IDS_NACK 4
+ int status;
+ struct completion xfer_done;
+
+ int irq;
+ struct resource *ioarea;
+};
+
+static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
+{
+ __raw_writel(val, (unsigned long)cam->iobase + reg);
+}
+
+static inline unsigned long IN32(struct cami2c *cam, int reg)
+{
+ return __raw_readl((unsigned long)cam->iobase + reg);
+}
+
+static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
+{
+ struct cami2c *id = ptr;
+ struct i2c_msg *msg = id->msg;
+ char *data = msg->buf;
+ unsigned long msr, fsr, fier, len;
+
+ msr = IN32(id, I2CMSR);
+ fsr = IN32(id, I2CFSR);
+
+ /* arbitration lost */
+ if (msr & MSR_MAL) {
+ OUT32(id, I2CMCR, 0);
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSAR, 0);
+ id->status |= IDS_DONE | IDS_ARBLOST;
+ goto out;
+ }
+
+ if (msr & MSR_MNR) {
+ /* NACK handling is very screwed up. After receiving a
+ * NAK IRQ one has to wait a bit before writing to any
+ * registers, or the ctl will lock up. After that delay
+ * do a normal i2c stop. Then wait at least 1 ms before
+ * attempting another transfer or ctl will stop working
+ */
+ udelay(100); /* wait or risk ctl hang */
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+ OUT32(id, I2CFIER, 0);
+ OUT32(id, I2CMIER, MIE_MSTE);
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSAR, 0);
+ id->status |= IDS_NACK;
+ msr &= ~MSR_MAT;
+ fsr = 0;
+ /* In some cases the MST bit is also set. */
+ }
+
+ /* i2c-stop was sent */
+ if (msr & MSR_MST) {
+ id->status |= IDS_DONE;
+ goto out;
+ }
+
+ /* i2c slave addr was sent; set to "normal" operation */
+ if (msr & MSR_MAT)
+ OUT32(id, I2CMCR, MCR_MIE);
+
+ fier = IN32(id, I2CFIER);
+
+ if (fsr & FSR_RDF) {
+ len = IN32(id, I2CRFDR);
+ if (msg->len <= len) {
+ if (id->flags & IDF_STOP) {
+ OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+ OUT32(id, I2CFIER, 0);
+ /* manual says: wait >= 0.5 SCL times */
+ udelay(5);
+ /* next int should be MST */
+ } else {
+ id->status |= IDS_DONE;
+ /* keep the RDF bit: ctrl holds SCL low
+ * until the setup for the next i2c_msg
+ * clears this bit.
+ */
+ fsr &= ~FSR_RDF;
+ }
+ }
+ while (msg->len && len) {
+ *data++ = IN32(id, I2CRXTX);
+ msg->len--;
+ len--;
+ }
+
+ if (msg->len) {
+ len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1
+ : msg->len - 1;
+
+ OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4));
+ }
+
+ } else if (id->flags & IDF_SEND) {
+ if ((fsr & FSR_TEND) && (msg->len < 1)) {
+ if (id->flags & IDF_STOP) {
+ OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+ } else {
+ id->status |= IDS_DONE;
+ /* keep the TEND bit: ctl holds SCL low
+ * until the setup for the next i2c_msg
+ * clears this bit.
+ */
+ fsr &= ~FSR_TEND;
+ }
+ }
+ if (fsr & FSR_TDFE) {
+ while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) {
+ OUT32(id, I2CRXTX, *data++);
+ msg->len--;
+ }
+
+ if (msg->len < 1) {
+ fier &= ~FIER_TXIE;
+ OUT32(id, I2CFIER, fier);
+ } else {
+ len = (msg->len >= FIFO_SIZE) ? 2 : 0;
+ OUT32(id, I2CFCR,
+ FCR_RFRST | ((len & 3) << 2));
+ }
+ }
+ }
+out:
+ if (id->status & IDS_DONE) {
+ OUT32(id, I2CMIER, 0);
+ OUT32(id, I2CFIER, 0);
+ id->msg = NULL;
+ complete(&id->xfer_done);
+ }
+ /* clear status flags and ctrl resumes work */
+ OUT32(id, I2CMSR, ~msr);
+ OUT32(id, I2CFSR, ~fsr);
+ OUT32(id, I2CSSR, 0);
+
+ return IRQ_HANDLED;
+}
+
+
+/* prepare and start a master receive operation */
+static void sh7760_i2c_mrecv(struct cami2c *id)
+{
+ int len;
+
+ id->flags |= IDF_RECV;
+
+ /* set the slave addr reg; otherwise rcv wont work! */
+ OUT32(id, I2CSAR, 0xfe);
+ OUT32(id, I2CMAR, (id->msg->addr << 1) | 1);
+
+ /* adjust rx fifo trigger */
+ if (id->msg->len >= FIFO_SIZE)
+ len = FIFO_SIZE - 1; /* trigger at fifo full */
+ else
+ len = id->msg->len - 1; /* trigger before all received */
+
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4));
+
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+ OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+ OUT32(id, I2CFIER, FIER_RXIE);
+}
+
+/* prepare and start a master send operation */
+static void sh7760_i2c_msend(struct cami2c *id)
+{
+ int len;
+
+ id->flags |= IDF_SEND;
+
+ /* set the slave addr reg; otherwise xmit wont work! */
+ OUT32(id, I2CSAR, 0xfe);
+ OUT32(id, I2CMAR, (id->msg->addr << 1) | 0);
+
+ /* adjust tx fifo trigger */
+ if (id->msg->len >= FIFO_SIZE)
+ len = 2; /* trig: 2 bytes left in TX fifo */
+ else
+ len = 0; /* trig: 8 bytes left in TX fifo */
+
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2));
+
+ while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) {
+ OUT32(id, I2CRXTX, *(id->msg->buf));
+ (id->msg->len)--;
+ (id->msg->buf)++;
+ }
+
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+ OUT32(id, I2CFSR, 0);
+ OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+ OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0));
+}
+
+static inline int sh7760_i2c_busy_check(struct cami2c *id)
+{
+ return (IN32(id, I2CMCR) & MCR_FSDA);
+}
+
+static int sh7760_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct cami2c *id = adap->algo_data;
+ int i, retr;
+
+ if (sh7760_i2c_busy_check(id)) {
+ dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr);
+ return -EBUSY;
+ }
+
+ i = 0;
+ while (i < num) {
+ retr = adap->retries;
+retry:
+ id->flags = ((i == (num-1)) ? IDF_STOP : 0);
+ id->status = 0;
+ id->msg = msgs;
+ init_completion(&id->xfer_done);
+
+ if (msgs->flags & I2C_M_RD)
+ sh7760_i2c_mrecv(id);
+ else
+ sh7760_i2c_msend(id);
+
+ wait_for_completion(&id->xfer_done);
+
+ if (id->status == 0) {
+ num = -EIO;
+ break;
+ }
+
+ if (id->status & IDS_NACK) {
+ /* wait a bit or i2c module stops working */
+ mdelay(1);
+ num = -EREMOTEIO;
+ break;
+ }
+
+ if (id->status & IDS_ARBLOST) {
+ if (retr--) {
+ mdelay(2);
+ goto retry;
+ }
+ num = -EREMOTEIO;
+ break;
+ }
+
+ msgs++;
+ i++;
+ }
+
+ id->msg = NULL;
+ id->flags = 0;
+ id->status = 0;
+
+ OUT32(id, I2CMCR, 0);
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMIER, 0);
+ OUT32(id, I2CFIER, 0);
+
+ /* reset slave module registers too: master mode enables slave
+ * module for receive ops (ack, data). Without this reset,
+ * eternal bus activity might be reported after NACK / ARBLOST.
+ */
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSAR, 0);
+ OUT32(id, I2CSSR, 0);
+
+ return num;
+}
+
+static u32 sh7760_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm sh7760_i2c_algo = {
+ .master_xfer = sh7760_i2c_master_xfer,
+ .functionality = sh7760_i2c_func,
+};
+
+/* calculate CCR register setting for a desired scl clock. SCL clock is
+ * derived from I2C module clock (iclk) which in turn is derived from
+ * peripheral module clock (mclk, usually around 33MHz):
+ * iclk = mclk/(CDF + 1). iclk must be < 20MHz.
+ * scl = iclk/(SCGD*8 + 20).
+ */
+static int __devinit calc_CCR(unsigned long scl_hz)
+{
+ struct clk *mclk;
+ unsigned long mck, m1, dff, odff, iclk;
+ signed char cdf, cdfm;
+ int scgd, scgdm, scgds;
+
+ mclk = clk_get(NULL, "peripheral_clk");
+ if (IS_ERR(mclk)) {
+ return PTR_ERR(mclk);
+ } else {
+ mck = mclk->rate;
+ clk_put(mclk);
+ }
+
+ odff = scl_hz;
+ scgdm = cdfm = m1 = 0;
+ for (cdf = 3; cdf >= 0; cdf--) {
+ iclk = mck / (1 + cdf);
+ if (iclk >= 20000000)
+ continue;
+ scgds = ((iclk / scl_hz) - 20) >> 3;
+ for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) {
+ m1 = iclk / (20 + (scgd << 3));
+ dff = abs(scl_hz - m1);
+ if (dff < odff) {
+ odff = dff;
+ cdfm = cdf;
+ scgdm = scgd;
+ }
+ }
+ }
+ /* fail if more than 25% off of requested SCL */
+ if (odff > (scl_hz >> 2))
+ return -EINVAL;
+
+ /* create a CCR register value */
+ return ((scgdm << 2) | cdfm);
+}
+
+static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
+{
+ struct sh7760_i2c_platdata *pd;
+ struct resource *res;
+ struct cami2c *id;
+ int ret;
+
+ pd = pdev->dev.platform_data;
+ if (!pd) {
+ dev_err(&pdev->dev, "no platform_data!\n");
+ ret = -ENODEV;
+ goto out0;
+ }
+
+ id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+ if (!id) {
+ dev_err(&pdev->dev, "no mem for private data\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mmio resources\n");
+ ret = -ENODEV;
+ goto out1;
+ }
+
+ id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name);
+ if (!id->ioarea) {
+ dev_err(&pdev->dev, "mmio already reserved\n");
+ ret = -EBUSY;
+ goto out1;
+ }
+
+ id->iobase = ioremap(res->start, REGSIZE);
+ if (!id->iobase) {
+ dev_err(&pdev->dev, "cannot ioremap\n");
+ ret = -ENODEV;
+ goto out2;
+ }
+
+ id->irq = platform_get_irq(pdev, 0);
+
+ id->adap.nr = pdev->id;
+ id->adap.algo = &sh7760_i2c_algo;
+ id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ id->adap.retries = 3;
+ id->adap.algo_data = id;
+ id->adap.dev.parent = &pdev->dev;
+ snprintf(id->adap.name, sizeof(id->adap.name),
+ "SH7760 I2C at %08lx", (unsigned long)res->start);
+
+ OUT32(id, I2CMCR, 0);
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMIER, 0);
+ OUT32(id, I2CMAR, 0);
+ OUT32(id, I2CSIER, 0);
+ OUT32(id, I2CSAR, 0);
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSSR, 0);
+ OUT32(id, I2CFIER, 0);
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CFSR, 0);
+
+ ret = calc_CCR(pd->speed_khz * 1000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n",
+ pd->speed_khz);
+ goto out3;
+ }
+ OUT32(id, I2CCCR, ret);
+
+ if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED,
+ SH7760_I2C_DEVNAME, id)) {
+ dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+ ret = -EBUSY;
+ goto out3;
+ }
+
+ ret = i2c_add_numbered_adapter(&id->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+ goto out4;
+ }
+
+ platform_set_drvdata(pdev, id);
+
+ dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n",
+ pd->speed_khz, res->start, id->irq);
+
+ return 0;
+
+out4:
+ free_irq(id->irq, id);
+out3:
+ iounmap(id->iobase);
+out2:
+ release_resource(id->ioarea);
+ kfree(id->ioarea);
+out1:
+ kfree(id);
+out0:
+ return ret;
+}
+
+static int __devexit sh7760_i2c_remove(struct platform_device *pdev)
+{
+ struct cami2c *id = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&id->adap);
+ free_irq(id->irq, id);
+ iounmap(id->iobase);
+ release_resource(id->ioarea);
+ kfree(id->ioarea);
+ kfree(id);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver sh7760_i2c_drv = {
+ .driver = {
+ .name = SH7760_I2C_DEVNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = sh7760_i2c_probe,
+ .remove = __devexit_p(sh7760_i2c_remove),
+};
+
+static int __init sh7760_i2c_init(void)
+{
+ return platform_driver_register(&sh7760_i2c_drv);
+}
+
+static void __exit sh7760_i2c_exit(void)
+{
+ platform_driver_unregister(&sh7760_i2c_drv);
+}
+
+module_init(sh7760_i2c_init);
+module_exit(sh7760_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 I2C bus driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
new file mode 100644
index 00000000..f633a53b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -0,0 +1,739 @@
+/*
+ * SuperH Mobile I2C Controller
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Portions of the code based on out-of-tree driver i2c-sh7343.c
+ * Copyright (c) 2006 Carlos Munoz <carlos@kenati.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
+
+/* Transmit operation: */
+/* */
+/* 0 byte transmit */
+/* BUS: S A8 ACK P */
+/* IRQ: DTE WAIT */
+/* ICIC: */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 */
+/* */
+/* 1 byte transmit */
+/* BUS: S A8 ACK D8(1) ACK P */
+/* IRQ: DTE WAIT WAIT */
+/* ICIC: -DTE */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 D8(1) */
+/* */
+/* 2 byte transmit */
+/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P */
+/* IRQ: DTE WAIT WAIT WAIT */
+/* ICIC: -DTE */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 D8(1) D8(2) */
+/* */
+/* 3 bytes or more, +---------+ gets repeated */
+/* */
+/* */
+/* Receive operation: */
+/* */
+/* 0 byte receive - not supported since slave may hold SDA low */
+/* */
+/* 1 byte receive [TX] | [RX] */
+/* BUS: S A8 ACK | D8(1) ACK P */
+/* IRQ: DTE WAIT | WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) */
+/* */
+/* 2 byte receive [TX]| [RX] */
+/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P */
+/* IRQ: DTE WAIT | WAIT WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) D8(2) */
+/* */
+/* 3 byte receive [TX] | [RX] */
+/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */
+/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) D8(2) D8(3) */
+/* */
+/* 4 bytes or more, this part is repeated +---------+ */
+/* */
+/* */
+/* Interrupt order and BUSY flag */
+/* ___ _ */
+/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */
+/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */
+/* */
+/* S D7 D6 D5 D4 D3 D2 D1 D0 P */
+/* ___ */
+/* WAIT IRQ ________________________________/ \___________ */
+/* TACK IRQ ____________________________________/ \_______ */
+/* DTE IRQ __________________________________________/ \_ */
+/* AL IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* _______________________________________________ */
+/* BUSY __/ \_ */
+/* */
+
+enum sh_mobile_i2c_op {
+ OP_START = 0,
+ OP_TX_FIRST,
+ OP_TX,
+ OP_TX_STOP,
+ OP_TX_TO_RX,
+ OP_RX,
+ OP_RX_STOP,
+ OP_RX_STOP_DATA,
+};
+
+struct sh_mobile_i2c_data {
+ struct device *dev;
+ void __iomem *reg;
+ struct i2c_adapter adap;
+ unsigned long bus_speed;
+ struct clk *clk;
+ u_int8_t icic;
+ u_int8_t iccl;
+ u_int8_t icch;
+ u_int8_t flags;
+
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ struct i2c_msg *msg;
+ int pos;
+ int sr;
+};
+
+#define IIC_FLAG_HAS_ICIC67 (1 << 0)
+
+#define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */
+
+/* Register offsets */
+#define ICDR 0x00
+#define ICCR 0x04
+#define ICSR 0x08
+#define ICIC 0x0c
+#define ICCL 0x10
+#define ICCH 0x14
+
+/* Register bits */
+#define ICCR_ICE 0x80
+#define ICCR_RACK 0x40
+#define ICCR_TRS 0x10
+#define ICCR_BBSY 0x04
+#define ICCR_SCP 0x01
+
+#define ICSR_SCLM 0x80
+#define ICSR_SDAM 0x40
+#define SW_DONE 0x20
+#define ICSR_BUSY 0x10
+#define ICSR_AL 0x08
+#define ICSR_TACK 0x04
+#define ICSR_WAIT 0x02
+#define ICSR_DTE 0x01
+
+#define ICIC_ICCLB8 0x80
+#define ICIC_ICCHB8 0x40
+#define ICIC_ALE 0x08
+#define ICIC_TACKE 0x04
+#define ICIC_WAITE 0x02
+#define ICIC_DTEE 0x01
+
+static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data)
+{
+ if (offs == ICIC)
+ data |= pd->icic;
+
+ iowrite8(data, pd->reg + offs);
+}
+
+static unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs)
+{
+ return ioread8(pd->reg + offs);
+}
+
+static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
+ unsigned char set, unsigned char clr)
+{
+ iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
+}
+
+static void activate_ch(struct sh_mobile_i2c_data *pd)
+{
+ unsigned long i2c_clk;
+ u_int32_t num;
+ u_int32_t denom;
+ u_int32_t tmp;
+
+ /* Wake up device and enable clock */
+ pm_runtime_get_sync(pd->dev);
+ clk_enable(pd->clk);
+
+ /* Get clock rate after clock is enabled */
+ i2c_clk = clk_get_rate(pd->clk);
+
+ /* Calculate the value for iccl. From the data sheet:
+ * iccl = (p clock / transfer rate) * (L / (L + H))
+ * where L and H are the SCL low/high ratio (5/4 in this case).
+ * We also round off the result.
+ */
+ num = i2c_clk * 5;
+ denom = pd->bus_speed * 9;
+ tmp = num * 10 / denom;
+ if (tmp % 10 >= 5)
+ pd->iccl = (u_int8_t)((num/denom) + 1);
+ else
+ pd->iccl = (u_int8_t)(num/denom);
+
+ /* one more bit of ICCL in ICIC */
+ if (pd->flags & IIC_FLAG_HAS_ICIC67) {
+ if ((num/denom) > 0xff)
+ pd->icic |= ICIC_ICCLB8;
+ else
+ pd->icic &= ~ICIC_ICCLB8;
+ }
+
+ /* Calculate the value for icch. From the data sheet:
+ icch = (p clock / transfer rate) * (H / (L + H)) */
+ num = i2c_clk * 4;
+ tmp = num * 10 / denom;
+ if (tmp % 10 >= 5)
+ pd->icch = (u_int8_t)((num/denom) + 1);
+ else
+ pd->icch = (u_int8_t)(num/denom);
+
+ /* one more bit of ICCH in ICIC */
+ if (pd->flags & IIC_FLAG_HAS_ICIC67) {
+ if ((num/denom) > 0xff)
+ pd->icic |= ICIC_ICCHB8;
+ else
+ pd->icic &= ~ICIC_ICCHB8;
+ }
+
+ /* Enable channel and configure rx ack */
+ iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+
+ /* Mask all interrupts */
+ iic_wr(pd, ICIC, 0);
+
+ /* Set the clock */
+ iic_wr(pd, ICCL, pd->iccl);
+ iic_wr(pd, ICCH, pd->icch);
+}
+
+static void deactivate_ch(struct sh_mobile_i2c_data *pd)
+{
+ /* Clear/disable interrupts */
+ iic_wr(pd, ICSR, 0);
+ iic_wr(pd, ICIC, 0);
+
+ /* Disable channel */
+ iic_set_clr(pd, ICCR, 0, ICCR_ICE);
+
+ /* Disable clock and mark device as idle */
+ clk_disable(pd->clk);
+ pm_runtime_put_sync(pd->dev);
+}
+
+static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
+ enum sh_mobile_i2c_op op, unsigned char data)
+{
+ unsigned char ret = 0;
+ unsigned long flags;
+
+ dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);
+
+ spin_lock_irqsave(&pd->lock, flags);
+
+ switch (op) {
+ case OP_START: /* issue start and trigger DTE interrupt */
+ iic_wr(pd, ICCR, 0x94);
+ break;
+ case OP_TX_FIRST: /* disable DTE interrupt and write data */
+ iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ iic_wr(pd, ICDR, data);
+ break;
+ case OP_TX: /* write data */
+ iic_wr(pd, ICDR, data);
+ break;
+ case OP_TX_STOP: /* write data and issue a stop afterwards */
+ iic_wr(pd, ICDR, data);
+ iic_wr(pd, ICCR, 0x90);
+ break;
+ case OP_TX_TO_RX: /* select read mode */
+ iic_wr(pd, ICCR, 0x81);
+ break;
+ case OP_RX: /* just read data */
+ ret = iic_rd(pd, ICDR);
+ break;
+ case OP_RX_STOP: /* enable DTE interrupt, issue stop */
+ iic_wr(pd, ICIC,
+ ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ iic_wr(pd, ICCR, 0xc0);
+ break;
+ case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
+ iic_wr(pd, ICIC,
+ ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ ret = iic_rd(pd, ICDR);
+ iic_wr(pd, ICCR, 0xc0);
+ break;
+ }
+
+ spin_unlock_irqrestore(&pd->lock, flags);
+
+ dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
+ return ret;
+}
+
+static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
+{
+ if (pd->pos == -1)
+ return 1;
+
+ return 0;
+}
+
+static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
+{
+ if (pd->pos == (pd->msg->len - 1))
+ return 1;
+
+ return 0;
+}
+
+static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
+ unsigned char *buf)
+{
+ switch (pd->pos) {
+ case -1:
+ *buf = (pd->msg->addr & 0x7f) << 1;
+ *buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
+ break;
+ default:
+ *buf = pd->msg->buf[pd->pos];
+ }
+}
+
+static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
+{
+ unsigned char data;
+
+ if (pd->pos == pd->msg->len)
+ return 1;
+
+ sh_mobile_i2c_get_data(pd, &data);
+
+ if (sh_mobile_i2c_is_last_byte(pd))
+ i2c_op(pd, OP_TX_STOP, data);
+ else if (sh_mobile_i2c_is_first_byte(pd))
+ i2c_op(pd, OP_TX_FIRST, data);
+ else
+ i2c_op(pd, OP_TX, data);
+
+ pd->pos++;
+ return 0;
+}
+
+static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
+{
+ unsigned char data;
+ int real_pos;
+
+ do {
+ if (pd->pos <= -1) {
+ sh_mobile_i2c_get_data(pd, &data);
+
+ if (sh_mobile_i2c_is_first_byte(pd))
+ i2c_op(pd, OP_TX_FIRST, data);
+ else
+ i2c_op(pd, OP_TX, data);
+ break;
+ }
+
+ if (pd->pos == 0) {
+ i2c_op(pd, OP_TX_TO_RX, 0);
+ break;
+ }
+
+ real_pos = pd->pos - 2;
+
+ if (pd->pos == pd->msg->len) {
+ if (real_pos < 0) {
+ i2c_op(pd, OP_RX_STOP, 0);
+ break;
+ }
+ data = i2c_op(pd, OP_RX_STOP_DATA, 0);
+ } else
+ data = i2c_op(pd, OP_RX, 0);
+
+ if (real_pos >= 0)
+ pd->msg->buf[real_pos] = data;
+ } while (0);
+
+ pd->pos++;
+ return pd->pos == (pd->msg->len + 2);
+}
+
+static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
+{
+ struct platform_device *dev = dev_id;
+ struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+ unsigned char sr;
+ int wakeup;
+
+ sr = iic_rd(pd, ICSR);
+ pd->sr |= sr; /* remember state */
+
+ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
+ (pd->msg->flags & I2C_M_RD) ? "read" : "write",
+ pd->pos, pd->msg->len);
+
+ if (sr & (ICSR_AL | ICSR_TACK)) {
+ /* don't interrupt transaction - continue to issue stop */
+ iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
+ wakeup = 0;
+ } else if (pd->msg->flags & I2C_M_RD)
+ wakeup = sh_mobile_i2c_isr_rx(pd);
+ else
+ wakeup = sh_mobile_i2c_isr_tx(pd);
+
+ if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
+ iic_wr(pd, ICSR, sr & ~ICSR_WAIT);
+
+ if (wakeup) {
+ pd->sr |= SW_DONE;
+ wake_up(&pd->wait);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
+{
+ if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
+ dev_err(pd->dev, "Unsupported zero length i2c read\n");
+ return -EIO;
+ }
+
+ /* Initialize channel registers */
+ iic_set_clr(pd, ICCR, 0, ICCR_ICE);
+
+ /* Enable channel and configure rx ack */
+ iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+
+ /* Set the clock */
+ iic_wr(pd, ICCL, pd->iccl);
+ iic_wr(pd, ICCH, pd->icch);
+
+ pd->msg = usr_msg;
+ pd->pos = -1;
+ pd->sr = 0;
+
+ /* Enable all interrupts to begin with */
+ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ return 0;
+}
+
+static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+ struct i2c_msg *msg;
+ int err = 0;
+ u_int8_t val;
+ int i, k, retry_count;
+
+ activate_ch(pd);
+
+ /* Process all messages */
+ for (i = 0; i < num; i++) {
+ msg = &msgs[i];
+
+ err = start_ch(pd, msg);
+ if (err)
+ break;
+
+ i2c_op(pd, OP_START, 0);
+
+ /* The interrupt handler takes care of the rest... */
+ k = wait_event_timeout(pd->wait,
+ pd->sr & (ICSR_TACK | SW_DONE),
+ 5 * HZ);
+ if (!k)
+ dev_err(pd->dev, "Transfer request timed out\n");
+
+ retry_count = 1000;
+again:
+ val = iic_rd(pd, ICSR);
+
+ dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
+
+ /* the interrupt handler may wake us up before the
+ * transfer is finished, so poll the hardware
+ * until we're done.
+ */
+ if (val & ICSR_BUSY) {
+ udelay(10);
+ if (retry_count--)
+ goto again;
+
+ err = -EIO;
+ dev_err(pd->dev, "Polling timed out\n");
+ break;
+ }
+
+ /* handle missing acknowledge and arbitration lost */
+ if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
+ err = -EIO;
+ break;
+ }
+ }
+
+ deactivate_ch(pd);
+
+ if (!err)
+ err = num;
+ return err;
+}
+
+static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm sh_mobile_i2c_algorithm = {
+ .functionality = sh_mobile_i2c_func,
+ .master_xfer = sh_mobile_i2c_xfer,
+};
+
+static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
+{
+ struct resource *res;
+ int ret = -ENXIO;
+ int n, k = 0;
+
+ while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
+ for (n = res->start; hook && n <= res->end; n++) {
+ if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
+ dev_name(&dev->dev), dev)) {
+ for (n--; n >= res->start; n--)
+ free_irq(n, dev);
+
+ goto rollback;
+ }
+ }
+ k++;
+ }
+
+ if (hook)
+ return k > 0 ? 0 : -ENOENT;
+
+ ret = 0;
+
+ rollback:
+ k--;
+
+ while (k >= 0) {
+ res = platform_get_resource(dev, IORESOURCE_IRQ, k);
+ for (n = res->start; n <= res->end; n++)
+ free_irq(n, dev);
+
+ k--;
+ }
+
+ return ret;
+}
+
+static int sh_mobile_i2c_probe(struct platform_device *dev)
+{
+ struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
+ struct sh_mobile_i2c_data *pd;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int size;
+ int ret;
+
+ pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
+ if (pd == NULL) {
+ dev_err(&dev->dev, "cannot allocate private data\n");
+ return -ENOMEM;
+ }
+
+ pd->clk = clk_get(&dev->dev, NULL);
+ if (IS_ERR(pd->clk)) {
+ dev_err(&dev->dev, "cannot get clock\n");
+ ret = PTR_ERR(pd->clk);
+ goto err;
+ }
+
+ ret = sh_mobile_i2c_hook_irqs(dev, 1);
+ if (ret) {
+ dev_err(&dev->dev, "cannot request IRQ\n");
+ goto err_clk;
+ }
+
+ pd->dev = &dev->dev;
+ platform_set_drvdata(dev, pd);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&dev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err_irq;
+ }
+
+ size = resource_size(res);
+
+ pd->reg = ioremap(res->start, size);
+ if (pd->reg == NULL) {
+ dev_err(&dev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_irq;
+ }
+
+ /* Use platformd data bus speed or NORMAL_SPEED */
+ pd->bus_speed = NORMAL_SPEED;
+ if (pdata && pdata->bus_speed)
+ pd->bus_speed = pdata->bus_speed;
+
+ /* The IIC blocks on SH-Mobile ARM processors
+ * come with two new bits in ICIC.
+ */
+ if (size > 0x17)
+ pd->flags |= IIC_FLAG_HAS_ICIC67;
+
+ /* Enable Runtime PM for this device.
+ *
+ * Also tell the Runtime PM core to ignore children
+ * for this device since it is valid for us to suspend
+ * this I2C master driver even though the slave devices
+ * on the I2C bus may not be suspended.
+ *
+ * The state of the I2C hardware bus is unaffected by
+ * the Runtime PM state.
+ */
+ pm_suspend_ignore_children(&dev->dev, true);
+ pm_runtime_enable(&dev->dev);
+
+ /* setup the private data */
+ adap = &pd->adap;
+ i2c_set_adapdata(adap, pd);
+
+ adap->owner = THIS_MODULE;
+ adap->algo = &sh_mobile_i2c_algorithm;
+ adap->dev.parent = &dev->dev;
+ adap->retries = 5;
+ adap->nr = dev->id;
+
+ strlcpy(adap->name, dev->name, sizeof(adap->name));
+
+ spin_lock_init(&pd->lock);
+ init_waitqueue_head(&pd->wait);
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret < 0) {
+ dev_err(&dev->dev, "cannot add numbered adapter\n");
+ goto err_all;
+ }
+
+ dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+ adap->nr, pd->bus_speed);
+ return 0;
+
+ err_all:
+ iounmap(pd->reg);
+ err_irq:
+ sh_mobile_i2c_hook_irqs(dev, 0);
+ err_clk:
+ clk_put(pd->clk);
+ err:
+ kfree(pd);
+ return ret;
+}
+
+static int sh_mobile_i2c_remove(struct platform_device *dev)
+{
+ struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&pd->adap);
+ iounmap(pd->reg);
+ sh_mobile_i2c_hook_irqs(dev, 0);
+ clk_put(pd->clk);
+ pm_runtime_disable(&dev->dev);
+ kfree(pd);
+ return 0;
+}
+
+static int sh_mobile_i2c_runtime_nop(struct device *dev)
+{
+ /* Runtime PM callback shared between ->runtime_suspend()
+ * and ->runtime_resume(). Simply returns success.
+ *
+ * This driver re-initializes all registers after
+ * pm_runtime_get_sync() anyway so there is no need
+ * to save and restore registers here.
+ */
+ return 0;
+}
+
+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,
+};
+
+static struct platform_driver sh_mobile_i2c_driver = {
+ .driver = {
+ .name = "i2c-sh_mobile",
+ .owner = THIS_MODULE,
+ .pm = &sh_mobile_i2c_dev_pm_ops,
+ },
+ .probe = sh_mobile_i2c_probe,
+ .remove = sh_mobile_i2c_remove,
+};
+
+static int __init sh_mobile_i2c_adap_init(void)
+{
+ return platform_driver_register(&sh_mobile_i2c_driver);
+}
+
+static void __exit sh_mobile_i2c_adap_exit(void)
+{
+ platform_driver_unregister(&sh_mobile_i2c_driver);
+}
+
+subsys_initcall(sh_mobile_i2c_adap_init);
+module_exit(sh_mobile_i2c_adap_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-sh_mobile");
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
new file mode 100644
index 00000000..0fe505d7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2004 Steven J. Hill
+ * Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 1995-2000 Simon G. Vogl
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_smbus.h>
+
+
+struct i2c_algo_sibyte_data {
+ void *data; /* private data */
+ int bus; /* which bus */
+ void *reg_base; /* CSR base */
+};
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+ int data_bytes = 0;
+ int error;
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ csr_out32((V_SMB_ADDR(addr) |
+ (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_LB(data->byte),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 2;
+ } else {
+ csr_out32(V_SMB_LB(data->word & 0xff),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32(V_SMB_MB(data->word >> 8),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+ if (error & M_SMB_ERROR) {
+ /* Clear error bit by writing a 1 */
+ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+ return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO;
+ }
+
+ if (data_bytes == 1)
+ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+ if (data_bytes == 2)
+ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+ return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm i2c_sibyte_algo = {
+ .smbus_xfer = smbus_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+ /* Register new adapter to i2c module... */
+ i2c_adap->algo = &i2c_sibyte_algo;
+
+ /* Set the requested frequency. */
+ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+ return i2c_add_numbered_adapter(i2c_adap);
+}
+
+
+static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
+ { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
+ { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
+};
+
+static struct i2c_adapter sibyte_board_adapter[2] = {
+ {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = NULL,
+ .algo_data = &sibyte_board_data[0],
+ .nr = 0,
+ .name = "SiByte SMBus 0",
+ },
+ {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = NULL,
+ .algo_data = &sibyte_board_data[1],
+ .nr = 1,
+ .name = "SiByte SMBus 1",
+ },
+};
+
+static int __init i2c_sibyte_init(void)
+{
+ pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n");
+ if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0)
+ return -ENODEV;
+ if (i2c_sibyte_add_bus(&sibyte_board_adapter[1],
+ K_SMB_FREQ_400KHZ) < 0) {
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit i2c_sibyte_exit(void)
+{
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ i2c_del_adapter(&sibyte_board_adapter[1]);
+}
+
+module_init(i2c_sibyte_init);
+module_exit(i2c_sibyte_exit);
+
+MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
new file mode 100644
index 00000000..2fc08fbf
--- /dev/null
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C Controller
+ *
+ * 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
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct simtec_i2c_data {
+ struct resource *ioarea;
+ void __iomem *reg;
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA (1<<2)
+#define CMD_SET_SCL (1<<3)
+
+#define STATE_SDA (1<<0)
+#define STATE_SCL (1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd;
+ struct resource *res;
+ int size;
+ int ret;
+
+ pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+ if (pd == NULL) {
+ dev_err(&dev->dev, "cannot allocate private data\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(dev, pd);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&dev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ size = resource_size(res);
+
+ pd->ioarea = request_mem_region(res->start, size, dev->name);
+ if (pd->ioarea == NULL) {
+ dev_err(&dev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err;
+ }
+
+ pd->reg = ioremap(res->start, size);
+ if (pd->reg == NULL) {
+ dev_err(&dev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_res;
+ }
+
+ /* setup the private data */
+
+ pd->adap.owner = THIS_MODULE;
+ pd->adap.algo_data = &pd->bit;
+ pd->adap.dev.parent = &dev->dev;
+
+ strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+ pd->bit.data = pd;
+ pd->bit.setsda = simtec_i2c_setsda;
+ pd->bit.setscl = simtec_i2c_setscl;
+ pd->bit.getsda = simtec_i2c_getsda;
+ pd->bit.getscl = simtec_i2c_getscl;
+ pd->bit.timeout = HZ;
+ pd->bit.udelay = 20;
+
+ ret = i2c_bit_add_bus(&pd->adap);
+ if (ret)
+ goto err_all;
+
+ return 0;
+
+ err_all:
+ iounmap(pd->reg);
+
+ err_res:
+ release_resource(pd->ioarea);
+ kfree(pd->ioarea);
+
+ err:
+ kfree(pd);
+ return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&pd->adap);
+
+ iounmap(pd->reg);
+ release_resource(pd->ioarea);
+ kfree(pd->ioarea);
+ kfree(pd);
+
+ return 0;
+}
+
+
+/* device driver */
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:simtec-i2c");
+
+static struct platform_driver simtec_i2c_driver = {
+ .driver = {
+ .name = "simtec-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = simtec_i2c_probe,
+ .remove = simtec_i2c_remove,
+};
+
+static int __init i2c_adap_simtec_init(void)
+{
+ return platform_driver_register(&simtec_i2c_driver);
+}
+
+static void __exit i2c_adap_simtec_exit(void)
+{
+ platform_driver_unregister(&simtec_i2c_driver);
+}
+
+module_init(i2c_adap_simtec_init);
+module_exit(i2c_adap_simtec_exit);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
new file mode 100644
index 00000000..6d60284c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -0,0 +1,434 @@
+/*
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+*/
+
+/* Note: we assume there can only be one SIS5595 with one SMBus interface */
+
+/*
+ Note: all have mfr. ID 0x1039.
+ SUPPORTED PCI ID
+ 5595 0008
+
+ Note: these chips contain a 0008 device which is incompatible with the
+ 5595. We recognize these by the presence of the listed
+ "blacklist" PCI ID and refuse to load.
+
+ NOT SUPPORTED PCI ID BLACKLIST PCI ID
+ 540 0008 0540
+ 550 0008 0550
+ 5513 0008 5511
+ 5581 0008 5597
+ 5582 0008 5597
+ 5597 0008 5597
+ 5598 0008 5597/5598
+ 630 0008 0630
+ 645 0008 0645
+ 646 0008 0646
+ 648 0008 0648
+ 650 0008 0650
+ 651 0008 0651
+ 730 0008 0730
+ 735 0008 0735
+ 745 0008 0745
+ 746 0008 0746
+*/
+
+/* TO DO:
+ * Add Block Transfers (ugly, but supported by the adapter)
+ * Add adapter resets
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static int blacklist[] = {
+ PCI_DEVICE_ID_SI_540,
+ PCI_DEVICE_ID_SI_550,
+ PCI_DEVICE_ID_SI_630,
+ PCI_DEVICE_ID_SI_645,
+ PCI_DEVICE_ID_SI_646,
+ PCI_DEVICE_ID_SI_648,
+ PCI_DEVICE_ID_SI_650,
+ PCI_DEVICE_ID_SI_651,
+ PCI_DEVICE_ID_SI_730,
+ PCI_DEVICE_ID_SI_735,
+ PCI_DEVICE_ID_SI_745,
+ PCI_DEVICE_ID_SI_746,
+ PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but that ID
+ shows up in other chips so we use the 5511
+ ID for recognition */
+ PCI_DEVICE_ID_SI_5597,
+ PCI_DEVICE_ID_SI_5598,
+ 0, /* terminates the list */
+};
+
+/* Length of ISA address segment */
+#define SIS5595_EXTENT 8
+/* SIS5595 SMBus registers */
+#define SMB_STS_LO 0x00
+#define SMB_STS_HI 0x01
+#define SMB_CTL_LO 0x02
+#define SMB_CTL_HI 0x03
+#define SMB_ADDR 0x04
+#define SMB_CMD 0x05
+#define SMB_PCNT 0x06
+#define SMB_CNT 0x07
+#define SMB_BYTE 0x08
+#define SMB_DEV 0x10
+#define SMB_DB0 0x11
+#define SMB_DB1 0x12
+#define SMB_HAA 0x13
+
+/* PCI Address Constants */
+#define SMB_INDEX 0x38
+#define SMB_DAT 0x39
+#define SIS5595_ENABLE_REG 0x40
+#define ACPI_BASE 0x90
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SIS5595 constants */
+#define SIS5595_QUICK 0x00
+#define SIS5595_BYTE 0x02
+#define SIS5595_BYTE_DATA 0x04
+#define SIS5595_WORD_DATA 0x06
+#define SIS5595_PROC_CALL 0x08
+#define SIS5595_BLOCK_DATA 0x0A
+
+/* insmod parameters */
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the device at the given address. */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
+
+static struct pci_driver sis5595_driver;
+static unsigned short sis5595_base;
+static struct pci_dev *sis5595_pdev;
+
+static u8 sis5595_read(u8 reg)
+{
+ outb(reg, sis5595_base + SMB_INDEX);
+ return inb(sis5595_base + SMB_DAT);
+}
+
+static void sis5595_write(u8 reg, u8 data)
+{
+ outb(reg, sis5595_base + SMB_INDEX);
+ outb(data, sis5595_base + SMB_DAT);
+}
+
+static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
+{
+ u16 a;
+ u8 val;
+ int *i;
+ int retval;
+
+ /* Look for imposters */
+ for (i = blacklist; *i != 0; i++) {
+ struct pci_dev *dev;
+ dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
+ if (dev) {
+ dev_err(&SIS5595_dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+ pci_dev_put(dev);
+ return -ENODEV;
+ }
+ }
+
+ /* Determine the address of the SMBus areas */
+ pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
+ if (sis5595_base == 0 && force_addr == 0) {
+ dev_err(&SIS5595_dev->dev, "ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+
+ if (force_addr)
+ sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
+ dev_dbg(&SIS5595_dev->dev, "ACPI Base address: %04x\n", sis5595_base);
+
+ /* NB: We grab just the two SMBus registers here, but this may still
+ * interfere with ACPI :-( */
+ retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
+ sis5595_driver.name);
+ if (retval)
+ return retval;
+
+ if (!request_region(sis5595_base + SMB_INDEX, 2,
+ sis5595_driver.name)) {
+ dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
+ sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1);
+ return -ENODEV;
+ }
+
+ if (force_addr) {
+ dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base);
+ if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
+ /* doesn't work for some chips! */
+ dev_err(&SIS5595_dev->dev, "force address failed - not supported?\n");
+ goto error;
+ }
+ }
+
+ if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if ((val & 0x80) == 0) {
+ dev_info(&SIS5595_dev->dev, "enabling ACPI\n");
+ if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if ((val & 0x80) == 0) {
+ /* doesn't work for some chips? */
+ dev_err(&SIS5595_dev->dev, "ACPI enable failed - not supported?\n");
+ goto error;
+ }
+ }
+
+ /* Everything is happy */
+ return 0;
+
+error:
+ release_region(sis5595_base + SMB_INDEX, 2);
+ return -ENODEV;
+}
+
+static int sis5595_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+ if (temp != 0x00) {
+ dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp);
+ sis5595_write(SMB_STS_LO, temp & 0xff);
+ sis5595_write(SMB_STS_HI, temp >> 8);
+ if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
+ dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&adap->dev, "Successful!\n");
+ }
+ }
+
+ /* start the transaction by setting bit 4 */
+ sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10);
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = sis5595_read(SMB_STS_LO);
+ } while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+
+ if (temp & 0x10) {
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ result = -ENXIO;
+ }
+
+ if (temp & 0x20) {
+ dev_err(&adap->dev, "Bus collision! SMBus may be locked until "
+ "next hard reset (or not...)\n");
+ /* Clock stops and slave is stuck in mid-transmission */
+ result = -EIO;
+ }
+
+ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+ if (temp != 0x00) {
+ sis5595_write(SMB_STS_LO, temp & 0xff);
+ sis5595_write(SMB_STS_HI, temp >> 8);
+ }
+
+ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+ if (temp != 0x00)
+ dev_dbg(&adap->dev, "Failed reset at end of transaction (%02x)\n", temp);
+
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ size = SIS5595_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ if (read_write == I2C_SMBUS_WRITE)
+ sis5595_write(SMB_CMD, command);
+ size = SIS5595_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis5595_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE)
+ sis5595_write(SMB_BYTE, data->byte);
+ size = SIS5595_BYTE_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ case I2C_SMBUS_WORD_DATA:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis5595_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ sis5595_write(SMB_BYTE, data->word & 0xff);
+ sis5595_write(SMB_BYTE + 1,
+ (data->word & 0xff00) >> 8);
+ }
+ size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
+
+ status = sis5595_transaction(adap);
+ if (status)
+ return status;
+
+ if ((size != SIS5595_PROC_CALL) &&
+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
+ return 0;
+
+
+ switch (size) {
+ case SIS5595_BYTE:
+ case SIS5595_BYTE_DATA:
+ data->byte = sis5595_read(SMB_BYTE);
+ break;
+ case SIS5595_WORD_DATA:
+ case SIS5595_PROC_CALL:
+ data->word = sis5595_read(SMB_BYTE) + (sis5595_read(SMB_BYTE + 1) << 8);
+ break;
+ }
+ return 0;
+}
+
+static u32 sis5595_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis5595_access,
+ .functionality = sis5595_func,
+};
+
+static struct i2c_adapter sis5595_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id sis5595_ids[] __devinitconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis5595_ids);
+
+static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int err;
+
+ if (sis5595_setup(dev)) {
+ dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ sis5595_adapter.dev.parent = &dev->dev;
+
+ snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name),
+ "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX);
+ err = i2c_add_adapter(&sis5595_adapter);
+ if (err) {
+ release_region(sis5595_base + SMB_INDEX, 2);
+ return err;
+ }
+
+ /* Always return failure here. This is to allow other drivers to bind
+ * to this pci device. We don't really want to have control over the
+ * pci device, we only wanted to read as few register values from it.
+ */
+ sis5595_pdev = pci_dev_get(dev);
+ return -ENODEV;
+}
+
+static struct pci_driver sis5595_driver = {
+ .name = "sis5595_smbus",
+ .id_table = sis5595_ids,
+ .probe = sis5595_probe,
+};
+
+static int __init i2c_sis5595_init(void)
+{
+ return pci_register_driver(&sis5595_driver);
+}
+
+static void __exit i2c_sis5595_exit(void)
+{
+ pci_unregister_driver(&sis5595_driver);
+ if (sis5595_pdev) {
+ i2c_del_adapter(&sis5595_adapter);
+ release_region(sis5595_base + SMB_INDEX, 2);
+ pci_dev_put(sis5595_pdev);
+ sis5595_pdev = NULL;
+ }
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("SIS5595 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_sis5595_init);
+module_exit(i2c_sis5595_exit);
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
new file mode 100644
index 00000000..b617fd06
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -0,0 +1,533 @@
+/*
+ Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.de>
+
+ 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.
+*/
+
+/*
+ Changes:
+ 24.08.2002
+ Fixed the typo in sis630_access (Thanks to Mark M. Hoffman)
+ Changed sis630_transaction.(Thanks to Mark M. Hoffman)
+ 18.09.2002
+ Added SIS730 as supported.
+ 21.09.2002
+ Added high_clock module option.If this option is set
+ used Host Master Clock 56KHz (default 14KHz).For now we save old Host
+ Master Clock and after transaction completed restore (otherwise
+ it's confuse BIOS and hung Machine).
+ 24.09.2002
+ Fixed typo in sis630_access
+ Fixed logical error by restoring of Host Master Clock
+ 31.07.2003
+ Added block data read/write support.
+*/
+
+/*
+ Status: beta
+
+ Supports:
+ SIS 630
+ SIS 730
+
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* SIS630 SMBus registers */
+#define SMB_STS 0x80 /* status */
+#define SMB_EN 0x81 /* status enable */
+#define SMB_CNT 0x82
+#define SMBHOST_CNT 0x83
+#define SMB_ADDR 0x84
+#define SMB_CMD 0x85
+#define SMB_PCOUNT 0x86 /* processed count */
+#define SMB_COUNT 0x87
+#define SMB_BYTE 0x88 /* ~0x8F data byte field */
+#define SMBDEV_ADDR 0x90
+#define SMB_DB0 0x91
+#define SMB_DB1 0x92
+#define SMB_SAA 0x93
+
+/* register count for request_region */
+#define SIS630_SMB_IOREGION 20
+
+/* PCI address constants */
+/* acpi base address register */
+#define SIS630_ACPI_BASE_REG 0x74
+/* bios control register */
+#define SIS630_BIOS_CTL_REG 0x40
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SIS630 constants */
+#define SIS630_QUICK 0x00
+#define SIS630_BYTE 0x01
+#define SIS630_BYTE_DATA 0x02
+#define SIS630_WORD_DATA 0x03
+#define SIS630_PCALL 0x04
+#define SIS630_BLOCK_DATA 0x05
+
+static struct pci_driver sis630_driver;
+
+/* insmod parameters */
+static int high_clock;
+static int force;
+module_param(high_clock, bool, 0);
+MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
+
+/* acpi base address */
+static unsigned short acpi_base;
+
+/* supported chips */
+static int supported[] = {
+ PCI_DEVICE_ID_SI_630,
+ PCI_DEVICE_ID_SI_730,
+ 0 /* terminates the list */
+};
+
+static inline u8 sis630_read(u8 reg)
+{
+ return inb(acpi_base + reg);
+}
+
+static inline void sis630_write(u8 reg, u8 data)
+{
+ outb(data, acpi_base + reg);
+}
+
+static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock)
+{
+ int temp;
+
+ /* Make sure the SMBus host is ready to start transmitting. */
+ if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
+ dev_dbg(&adap->dev, "SMBus busy (%02x).Resetting...\n",temp);
+ /* kill smbus transaction */
+ sis630_write(SMBHOST_CNT, 0x20);
+
+ if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
+ dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&adap->dev, "Successful!\n");
+ }
+ }
+
+ /* save old clock, so we can prevent machine for hung */
+ *oldclock = sis630_read(SMB_CNT);
+
+ dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock);
+
+ /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */
+ if (high_clock)
+ sis630_write(SMB_CNT, 0x20);
+ else
+ sis630_write(SMB_CNT, (*oldclock & ~0x40));
+
+ /* clear all sticky bits */
+ temp = sis630_read(SMB_STS);
+ sis630_write(SMB_STS, temp & 0x1e);
+
+ /* start the transaction by setting bit 4 and size */
+ sis630_write(SMBHOST_CNT,0x10 | (size & 0x07));
+
+ return 0;
+}
+
+static int sis630_transaction_wait(struct i2c_adapter *adap, int size)
+{
+ int temp, result = 0, timeout = 0;
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = sis630_read(SMB_STS);
+ /* check if block transmitted */
+ if (size == SIS630_BLOCK_DATA && (temp & 0x10))
+ break;
+ } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+
+ if (temp & 0x02) {
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ result = -ENXIO;
+ }
+
+ if (temp & 0x04) {
+ dev_err(&adap->dev, "Bus collision!\n");
+ result = -EIO;
+ /*
+ TBD: Datasheet say:
+ the software should clear this bit and restart SMBUS operation.
+ Should we do it or user start request again?
+ */
+ }
+
+ return result;
+}
+
+static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock)
+{
+ int temp = 0;
+
+ /* clear all status "sticky" bits */
+ sis630_write(SMB_STS, temp);
+
+ dev_dbg(&adap->dev, "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT));
+
+ /*
+ * restore old Host Master Clock if high_clock is set
+ * and oldclock was not 56KHz
+ */
+ if (high_clock && !(oldclock & 0x20))
+ sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20));
+
+ dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT));
+}
+
+static int sis630_transaction(struct i2c_adapter *adap, int size)
+{
+ int result = 0;
+ u8 oldclock = 0;
+
+ result = sis630_transaction_start(adap, size, &oldclock);
+ if (!result) {
+ result = sis630_transaction_wait(adap, size);
+ sis630_transaction_end(adap, oldclock);
+ }
+
+ return result;
+}
+
+static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *data, int read_write)
+{
+ int i, len = 0, rc = 0;
+ u8 oldclock = 0;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0)
+ len = 0;
+ else if (len > 32)
+ len = 32;
+ sis630_write(SMB_COUNT, len);
+ for (i=1; i <= len; i++) {
+ dev_dbg(&adap->dev, "set data 0x%02x\n", data->block[i]);
+ /* set data */
+ sis630_write(SMB_BYTE+(i-1)%8, data->block[i]);
+ if (i==8 || (len<8 && i==len)) {
+ dev_dbg(&adap->dev, "start trans len=%d i=%d\n",len ,i);
+ /* first transaction */
+ rc = sis630_transaction_start(adap,
+ SIS630_BLOCK_DATA, &oldclock);
+ if (rc)
+ return rc;
+ }
+ else if ((i-1)%8 == 7 || i==len) {
+ dev_dbg(&adap->dev, "trans_wait len=%d i=%d\n",len,i);
+ if (i>8) {
+ dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i);
+ /*
+ If this is not first transaction,
+ we must clear sticky bit.
+ clear SMBARY_STS
+ */
+ sis630_write(SMB_STS,0x10);
+ }
+ rc = sis630_transaction_wait(adap,
+ SIS630_BLOCK_DATA);
+ if (rc) {
+ dev_dbg(&adap->dev, "trans_wait failed\n");
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* read request */
+ data->block[0] = len = 0;
+ rc = sis630_transaction_start(adap,
+ SIS630_BLOCK_DATA, &oldclock);
+ if (rc)
+ return rc;
+ do {
+ rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA);
+ if (rc) {
+ dev_dbg(&adap->dev, "trans_wait failed\n");
+ break;
+ }
+ /* if this first transaction then read byte count */
+ if (len == 0)
+ data->block[0] = sis630_read(SMB_COUNT);
+
+ /* just to be sure */
+ if (data->block[0] > 32)
+ data->block[0] = 32;
+
+ dev_dbg(&adap->dev, "block data read len=0x%x\n", data->block[0]);
+
+ for (i=0; i < 8 && len < data->block[0]; i++,len++) {
+ dev_dbg(&adap->dev, "read i=%d len=%d\n", i, len);
+ data->block[len+1] = sis630_read(SMB_BYTE+i);
+ }
+
+ dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i);
+
+ /* clear SMBARY_STS */
+ sis630_write(SMB_STS,0x10);
+ } while(len < data->block[0]);
+ }
+
+ sis630_transaction_end(adap, oldclock);
+
+ return rc;
+}
+
+/* Return negative errno on error. */
+static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ size = SIS630_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ if (read_write == I2C_SMBUS_WRITE)
+ sis630_write(SMB_CMD, command);
+ size = SIS630_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis630_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE)
+ sis630_write(SMB_BYTE, data->byte);
+ size = SIS630_BYTE_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ case I2C_SMBUS_WORD_DATA:
+ sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis630_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ sis630_write(SMB_BYTE, data->word & 0xff);
+ sis630_write(SMB_BYTE + 1,(data->word & 0xff00) >> 8);
+ }
+ size = (size == I2C_SMBUS_PROC_CALL ? SIS630_PCALL : SIS630_WORD_DATA);
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis630_write(SMB_CMD, command);
+ size = SIS630_BLOCK_DATA;
+ return sis630_block_data(adap, data, read_write);
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n",
+ size);
+ return -EOPNOTSUPP;
+ }
+
+ status = sis630_transaction(adap, size);
+ if (status)
+ return status;
+
+ if ((size != SIS630_PCALL) &&
+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
+ return 0;
+ }
+
+ switch(size) {
+ case SIS630_BYTE:
+ case SIS630_BYTE_DATA:
+ data->byte = sis630_read(SMB_BYTE);
+ break;
+ case SIS630_PCALL:
+ case SIS630_WORD_DATA:
+ data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8);
+ break;
+ }
+
+ return 0;
+}
+
+static u32 sis630_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int __devinit sis630_setup(struct pci_dev *sis630_dev)
+{
+ unsigned char b;
+ struct pci_dev *dummy = NULL;
+ int retval, i;
+
+ /* check for supported SiS devices */
+ for (i=0; supported[i] > 0 ; i++) {
+ if ((dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy)))
+ break; /* found */
+ }
+
+ if (dummy) {
+ pci_dev_put(dummy);
+ }
+ else if (force) {
+ dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but "
+ "loading because of force option enabled\n");
+ }
+ else {
+ return -ENODEV;
+ }
+
+ /*
+ Enable ACPI first , so we can accsess reg 74-75
+ in acpi io space and read acpi base addr
+ */
+ if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
+ dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+ /* if ACPI already enabled , do nothing */
+ if (!(b & 0x80) &&
+ pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
+ dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* Determine the ACPI base address */
+ if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
+ dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);
+
+ retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
+ sis630_driver.name);
+ if (retval)
+ goto exit;
+
+ /* Everything is happy, let's grab the memory and set things up. */
+ if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
+ sis630_driver.name)) {
+ dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
+ "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ retval = 0;
+
+exit:
+ if (retval)
+ acpi_base = 0;
+ return retval;
+}
+
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis630_access,
+ .functionality = sis630_func,
+};
+
+static struct i2c_adapter sis630_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+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, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis630_ids);
+
+static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if (sis630_setup(dev)) {
+ dev_err(&dev->dev, "SIS630 comp. bus not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ sis630_adapter.dev.parent = &dev->dev;
+
+ snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
+ "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS);
+
+ return i2c_add_adapter(&sis630_adapter);
+}
+
+static void __devexit sis630_remove(struct pci_dev *dev)
+{
+ if (acpi_base) {
+ i2c_del_adapter(&sis630_adapter);
+ release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
+ acpi_base = 0;
+ }
+}
+
+
+static struct pci_driver sis630_driver = {
+ .name = "sis630_smbus",
+ .id_table = sis630_ids,
+ .probe = sis630_probe,
+ .remove = __devexit_p(sis630_remove),
+};
+
+static int __init i2c_sis630_init(void)
+{
+ return pci_register_driver(&sis630_driver);
+}
+
+
+static void __exit i2c_sis630_exit(void)
+{
+ pci_unregister_driver(&sis630_driver);
+}
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
+MODULE_DESCRIPTION("SIS630 SMBus driver");
+
+module_init(i2c_sis630_init);
+module_exit(i2c_sis630_exit);
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
new file mode 100644
index 00000000..86837f0c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -0,0 +1,344 @@
+/*
+ Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ This module must be considered BETA unless and until
+ the chipset manufacturer releases a datasheet.
+ The register definitions are based on the SiS630.
+
+ This module relies on quirk_sis_96x_smbus (drivers/pci/quirks.c)
+ for just about every machine for which users have reported.
+ If this module isn't detecting your 96x south bridge, have a
+ look there.
+
+ We assume there can only be one SiS96x with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* base address register in PCI config space */
+#define SIS96x_BAR 0x04
+
+/* SiS96x SMBus registers */
+#define SMB_STS 0x00
+#define SMB_EN 0x01
+#define SMB_CNT 0x02
+#define SMB_HOST_CNT 0x03
+#define SMB_ADDR 0x04
+#define SMB_CMD 0x05
+#define SMB_PCOUNT 0x06
+#define SMB_COUNT 0x07
+#define SMB_BYTE 0x08
+#define SMB_DEV_ADDR 0x10
+#define SMB_DB0 0x11
+#define SMB_DB1 0x12
+#define SMB_SAA 0x13
+
+/* register count for request_region */
+#define SMB_IOSIZE 0x20
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SiS96x SMBus constants */
+#define SIS96x_QUICK 0x00
+#define SIS96x_BYTE 0x01
+#define SIS96x_BYTE_DATA 0x02
+#define SIS96x_WORD_DATA 0x03
+#define SIS96x_PROC_CALL 0x04
+#define SIS96x_BLOCK_DATA 0x05
+
+static struct pci_driver sis96x_driver;
+static struct i2c_adapter sis96x_adapter;
+static u16 sis96x_smbus_base;
+
+static inline u8 sis96x_read(u8 reg)
+{
+ return inb(sis96x_smbus_base + reg) ;
+}
+
+static inline void sis96x_write(u8 reg, u8 data)
+{
+ outb(data, sis96x_smbus_base + reg) ;
+}
+
+/* Execute a SMBus transaction.
+ int size is from SIS96x_QUICK to SIS96x_BLOCK_DATA
+ */
+static int sis96x_transaction(int size)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&sis96x_adapter.dev, "SMBus transaction %d\n", size);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+
+ dev_dbg(&sis96x_adapter.dev, "SMBus busy (0x%02x). "
+ "Resetting...\n", temp);
+
+ /* kill the transaction */
+ sis96x_write(SMB_HOST_CNT, 0x20);
+
+ /* check it again */
+ if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+ dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&sis96x_adapter.dev, "Successful\n");
+ }
+ }
+
+ /* Turn off timeout interrupts, set fast host clock */
+ sis96x_write(SMB_CNT, 0x20);
+
+ /* clear all (sticky) status flags */
+ temp = sis96x_read(SMB_STS);
+ sis96x_write(SMB_STS, temp & 0x1e);
+
+ /* start the transaction by setting bit 4 and size bits */
+ sis96x_write(SMB_HOST_CNT, 0x10 | (size & 0x07));
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = sis96x_read(SMB_STS);
+ } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
+ result = -ETIMEDOUT;
+ }
+
+ /* device error - probably missing ACK */
+ if (temp & 0x02) {
+ dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
+ result = -ENXIO;
+ }
+
+ /* bus collision */
+ if (temp & 0x04) {
+ dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
+ result = -EIO;
+ }
+
+ /* Finish up by resetting the bus */
+ sis96x_write(SMB_STS, temp);
+ if ((temp = sis96x_read(SMB_STS))) {
+ dev_dbg(&sis96x_adapter.dev, "Failed reset at "
+ "end of transaction! (0x%02x)\n", temp);
+ }
+
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 sis96x_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ size = SIS96x_QUICK;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ if (read_write == I2C_SMBUS_WRITE)
+ sis96x_write(SMB_CMD, command);
+ size = SIS96x_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis96x_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE)
+ sis96x_write(SMB_BYTE, data->byte);
+ size = SIS96x_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_PROC_CALL:
+ case I2C_SMBUS_WORD_DATA:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis96x_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ sis96x_write(SMB_BYTE, data->word & 0xff);
+ sis96x_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
+ }
+ size = (size == I2C_SMBUS_PROC_CALL ?
+ SIS96x_PROC_CALL : SIS96x_WORD_DATA);
+ break;
+
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ status = sis96x_transaction(size);
+ if (status)
+ return status;
+
+ if ((size != SIS96x_PROC_CALL) &&
+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS96x_QUICK)))
+ return 0;
+
+ switch (size) {
+ case SIS96x_BYTE:
+ case SIS96x_BYTE_DATA:
+ data->byte = sis96x_read(SMB_BYTE);
+ break;
+
+ case SIS96x_WORD_DATA:
+ case SIS96x_PROC_CALL:
+ data->word = sis96x_read(SMB_BYTE) +
+ (sis96x_read(SMB_BYTE + 1) << 8);
+ break;
+ }
+ return 0;
+}
+
+static u32 sis96x_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis96x_access,
+ .functionality = sis96x_func,
+};
+
+static struct i2c_adapter sis96x_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id sis96x_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis96x_ids);
+
+static int __devinit sis96x_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ u16 ww = 0;
+ int retval;
+
+ if (sis96x_smbus_base) {
+ dev_err(&dev->dev, "Only one device supported.\n");
+ return -EBUSY;
+ }
+
+ pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
+ if (PCI_CLASS_SERIAL_SMBUS != ww) {
+ dev_err(&dev->dev, "Unsupported device class 0x%04x!\n", ww);
+ return -ENODEV;
+ }
+
+ sis96x_smbus_base = pci_resource_start(dev, SIS96x_BAR);
+ if (!sis96x_smbus_base) {
+ dev_err(&dev->dev, "SiS96x SMBus base address "
+ "not initialized!\n");
+ return -EINVAL;
+ }
+ dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
+ sis96x_smbus_base);
+
+ retval = acpi_check_resource_conflict(&dev->resource[SIS96x_BAR]);
+ if (retval)
+ return -ENODEV;
+
+ /* Everything is happy, let's grab the memory and set things up. */
+ if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
+ sis96x_driver.name)) {
+ dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x "
+ "already in use!\n", sis96x_smbus_base,
+ sis96x_smbus_base + SMB_IOSIZE - 1);
+
+ sis96x_smbus_base = 0;
+ return -EINVAL;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ sis96x_adapter.dev.parent = &dev->dev;
+
+ snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name),
+ "SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
+
+ if ((retval = i2c_add_adapter(&sis96x_adapter))) {
+ dev_err(&dev->dev, "Couldn't register adapter!\n");
+ release_region(sis96x_smbus_base, SMB_IOSIZE);
+ sis96x_smbus_base = 0;
+ }
+
+ return retval;
+}
+
+static void __devexit sis96x_remove(struct pci_dev *dev)
+{
+ if (sis96x_smbus_base) {
+ i2c_del_adapter(&sis96x_adapter);
+ release_region(sis96x_smbus_base, SMB_IOSIZE);
+ sis96x_smbus_base = 0;
+ }
+}
+
+static struct pci_driver sis96x_driver = {
+ .name = "sis96x_smbus",
+ .id_table = sis96x_ids,
+ .probe = sis96x_probe,
+ .remove = __devexit_p(sis96x_remove),
+};
+
+static int __init i2c_sis96x_init(void)
+{
+ return pci_register_driver(&sis96x_driver);
+}
+
+static void __exit i2c_sis96x_exit(void)
+{
+ pci_unregister_driver(&sis96x_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("SiS96x SMBus driver");
+MODULE_LICENSE("GPL");
+
+/* Register initialization functions using helper macros */
+module_init(i2c_sis96x_init);
+module_exit(i2c_sis96x_exit);
+
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
new file mode 100644
index 00000000..99879617
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * ST DDC I2C master mode driver, used in e.g. U300 series platforms.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#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"
+
+/* CR (Control Register) 8bit (R/W) */
+#define I2C_CR (0x00000000)
+#define I2C_CR_RESET_VALUE (0x00)
+#define I2C_CR_RESET_UMASK (0x00)
+#define I2C_CR_DDC1_ENABLE (0x80)
+#define I2C_CR_TRANS_ENABLE (0x40)
+#define I2C_CR_PERIPHERAL_ENABLE (0x20)
+#define I2C_CR_DDC2B_ENABLE (0x10)
+#define I2C_CR_START_ENABLE (0x08)
+#define I2C_CR_ACK_ENABLE (0x04)
+#define I2C_CR_STOP_ENABLE (0x02)
+#define I2C_CR_INTERRUPT_ENABLE (0x01)
+/* SR1 (Status Register 1) 8bit (R/-) */
+#define I2C_SR1 (0x00000004)
+#define I2C_SR1_RESET_VALUE (0x00)
+#define I2C_SR1_RESET_UMASK (0x00)
+#define I2C_SR1_EVF_IND (0x80)
+#define I2C_SR1_ADD10_IND (0x40)
+#define I2C_SR1_TRA_IND (0x20)
+#define I2C_SR1_BUSY_IND (0x10)
+#define I2C_SR1_BTF_IND (0x08)
+#define I2C_SR1_ADSL_IND (0x04)
+#define I2C_SR1_MSL_IND (0x02)
+#define I2C_SR1_SB_IND (0x01)
+/* SR2 (Status Register 2) 8bit (R/-) */
+#define I2C_SR2 (0x00000008)
+#define I2C_SR2_RESET_VALUE (0x00)
+#define I2C_SR2_RESET_UMASK (0x40)
+#define I2C_SR2_MASK (0xBF)
+#define I2C_SR2_SCLFAL_IND (0x80)
+#define I2C_SR2_ENDAD_IND (0x20)
+#define I2C_SR2_AF_IND (0x10)
+#define I2C_SR2_STOPF_IND (0x08)
+#define I2C_SR2_ARLO_IND (0x04)
+#define I2C_SR2_BERR_IND (0x02)
+#define I2C_SR2_DDC2BF_IND (0x01)
+/* CCR (Clock Control Register) 8bit (R/W) */
+#define I2C_CCR (0x0000000C)
+#define I2C_CCR_RESET_VALUE (0x00)
+#define I2C_CCR_RESET_UMASK (0x00)
+#define I2C_CCR_MASK (0xFF)
+#define I2C_CCR_FMSM (0x80)
+#define I2C_CCR_CC_MASK (0x7F)
+/* OAR1 (Own Address Register 1) 8bit (R/W) */
+#define I2C_OAR1 (0x00000010)
+#define I2C_OAR1_RESET_VALUE (0x00)
+#define I2C_OAR1_RESET_UMASK (0x00)
+#define I2C_OAR1_ADD_MASK (0xFF)
+/* OAR2 (Own Address Register 2) 8bit (R/W) */
+#define I2C_OAR2 (0x00000014)
+#define I2C_OAR2_RESET_VALUE (0x40)
+#define I2C_OAR2_RESET_UMASK (0x19)
+#define I2C_OAR2_MASK (0xE6)
+#define I2C_OAR2_FR_25_10MHZ (0x00)
+#define I2C_OAR2_FR_10_1667MHZ (0x20)
+#define I2C_OAR2_FR_1667_2667MHZ (0x40)
+#define I2C_OAR2_FR_2667_40MHZ (0x60)
+#define I2C_OAR2_FR_40_5333MHZ (0x80)
+#define I2C_OAR2_FR_5333_66MHZ (0xA0)
+#define I2C_OAR2_FR_66_80MHZ (0xC0)
+#define I2C_OAR2_FR_80_100MHZ (0xE0)
+#define I2C_OAR2_FR_MASK (0xE0)
+#define I2C_OAR2_ADD_MASK (0x06)
+/* DR (Data Register) 8bit (R/W) */
+#define I2C_DR (0x00000018)
+#define I2C_DR_RESET_VALUE (0x00)
+#define I2C_DR_RESET_UMASK (0xFF)
+#define I2C_DR_D_MASK (0xFF)
+/* ECCR (Extended Clock Control Register) 8bit (R/W) */
+#define I2C_ECCR (0x0000001C)
+#define I2C_ECCR_RESET_VALUE (0x00)
+#define I2C_ECCR_RESET_UMASK (0xE0)
+#define I2C_ECCR_MASK (0x1F)
+#define I2C_ECCR_CC_MASK (0x1F)
+
+/*
+ * These events are more or less responses to commands
+ * sent into the hardware, presumably reflecting the state
+ * of an internal state machine.
+ */
+enum stu300_event {
+ STU300_EVENT_NONE = 0,
+ STU300_EVENT_1,
+ STU300_EVENT_2,
+ STU300_EVENT_3,
+ STU300_EVENT_4,
+ STU300_EVENT_5,
+ STU300_EVENT_6,
+ STU300_EVENT_7,
+ STU300_EVENT_8,
+ STU300_EVENT_9
+};
+
+enum stu300_error {
+ STU300_ERROR_NONE = 0,
+ STU300_ERROR_ACKNOWLEDGE_FAILURE,
+ STU300_ERROR_BUS_ERROR,
+ STU300_ERROR_ARBITRATION_LOST,
+ STU300_ERROR_UNKNOWN
+};
+
+/* timeout waiting for the controller to respond */
+#define STU300_TIMEOUT (msecs_to_jiffies(1000))
+
+/*
+ * The number of address send athemps tried before giving up.
+ * If the first one failes it seems like 5 to 8 attempts are required.
+ */
+#define NUM_ADDR_RESEND_ATTEMPTS 12
+
+/* I2C clock speed, in Hz 0-400kHz*/
+static unsigned int scl_frequency = 100000;
+module_param(scl_frequency, uint, 0644);
+
+/**
+ * struct stu300_dev - the stu300 driver state holder
+ * @pdev: parent platform device
+ * @adapter: corresponding I2C adapter
+ * @phybase: location of I/O area in memory
+ * @physize: size of I/O area in memory
+ * @clk: hardware block clock
+ * @irq: assigned interrupt line
+ * @cmd_issue_lock: this locks the following cmd_ variables
+ * @cmd_complete: acknowledge completion for an I2C command
+ * @cmd_event: expected event coming in as a response to a command
+ * @cmd_err: error code as response to a command
+ * @speed: current bus speed in Hz
+ * @msg_index: index of current message
+ * @msg_len: length of current message
+ */
+
+struct stu300_dev {
+ struct platform_device *pdev;
+ struct i2c_adapter adapter;
+ resource_size_t phybase;
+ resource_size_t physize;
+ void __iomem *virtbase;
+ struct clk *clk;
+ int irq;
+ spinlock_t cmd_issue_lock;
+ struct completion cmd_complete;
+ enum stu300_event cmd_event;
+ enum stu300_error cmd_err;
+ unsigned int speed;
+ int msg_index;
+ int msg_len;
+};
+
+/* Local forward function declarations */
+static int stu300_init_hw(struct stu300_dev *dev);
+
+/*
+ * The block needs writes in both MSW and LSW in order
+ * for all data lines to reach their destination.
+ */
+static inline void stu300_wr8(u32 value, void __iomem *address)
+{
+ writel((value << 16) | value, address);
+}
+
+/*
+ * This merely masks off the duplicates which appear
+ * in bytes 1-3. You _MUST_ use 32-bit bus access on this
+ * device, else it will not work.
+ */
+static inline u32 stu300_r8(void __iomem *address)
+{
+ return readl(address) & 0x000000FFU;
+}
+
+static void stu300_irq_enable(struct stu300_dev *dev)
+{
+ u32 val;
+ val = stu300_r8(dev->virtbase + I2C_CR);
+ val |= I2C_CR_INTERRUPT_ENABLE;
+ /* Twice paranoia (possible HW glitch) */
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+}
+
+static void stu300_irq_disable(struct stu300_dev *dev)
+{
+ u32 val;
+ val = stu300_r8(dev->virtbase + I2C_CR);
+ val &= ~I2C_CR_INTERRUPT_ENABLE;
+ /* Twice paranoia (possible HW glitch) */
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+}
+
+
+/*
+ * Tells whether a certain event or events occurred in
+ * response to a command. The events represent states in
+ * the internal state machine of the hardware. The events
+ * are not very well described in the hardware
+ * documentation and can only be treated as abstract state
+ * machine states.
+ *
+ * @ret 0 = event has not occurred or unknown error, any
+ * other value means the correct event occurred or an error.
+ */
+
+static int stu300_event_occurred(struct stu300_dev *dev,
+ enum stu300_event mr_event) {
+ u32 status1;
+ u32 status2;
+
+ /* What event happened? */
+ status1 = stu300_r8(dev->virtbase + I2C_SR1);
+
+ if (!(status1 & I2C_SR1_EVF_IND))
+ /* No event at all */
+ return 0;
+
+ status2 = stu300_r8(dev->virtbase + I2C_SR2);
+
+ /* Block any multiple interrupts */
+ stu300_irq_disable(dev);
+
+ /* Check for errors first */
+ if (status2 & I2C_SR2_AF_IND) {
+ dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
+ return 1;
+ } else if (status2 & I2C_SR2_BERR_IND) {
+ dev->cmd_err = STU300_ERROR_BUS_ERROR;
+ return 1;
+ } else if (status2 & I2C_SR2_ARLO_IND) {
+ dev->cmd_err = STU300_ERROR_ARBITRATION_LOST;
+ return 1;
+ }
+
+ switch (mr_event) {
+ case STU300_EVENT_1:
+ if (status1 & I2C_SR1_ADSL_IND)
+ return 1;
+ break;
+ case STU300_EVENT_2:
+ case STU300_EVENT_3:
+ case STU300_EVENT_7:
+ case STU300_EVENT_8:
+ if (status1 & I2C_SR1_BTF_IND) {
+ return 1;
+ }
+ break;
+ case STU300_EVENT_4:
+ if (status2 & I2C_SR2_STOPF_IND)
+ return 1;
+ break;
+ case STU300_EVENT_5:
+ if (status1 & I2C_SR1_SB_IND)
+ /* Clear start bit */
+ return 1;
+ break;
+ case STU300_EVENT_6:
+ if (status2 & I2C_SR2_ENDAD_IND) {
+ /* First check for any errors */
+ return 1;
+ }
+ break;
+ case STU300_EVENT_9:
+ if (status1 & I2C_SR1_ADD10_IND)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ /* If we get here, we're on thin ice.
+ * Here we are in a status where we have
+ * gotten a response that does not match
+ * what we requested.
+ */
+ dev->cmd_err = STU300_ERROR_UNKNOWN;
+ dev_err(&dev->pdev->dev,
+ "Unhandled interrupt! %d sr1: 0x%x sr2: 0x%x\n",
+ mr_event, status1, status2);
+ return 0;
+}
+
+static irqreturn_t stu300_irh(int irq, void *data)
+{
+ struct stu300_dev *dev = data;
+ int res;
+
+ /* Just make sure that the block is clocked */
+ clk_enable(dev->clk);
+
+ /* See if this was what we were waiting for */
+ spin_lock(&dev->cmd_issue_lock);
+
+ res = stu300_event_occurred(dev, dev->cmd_event);
+ if (res || dev->cmd_err != STU300_ERROR_NONE)
+ complete(&dev->cmd_complete);
+
+ spin_unlock(&dev->cmd_issue_lock);
+
+ clk_disable(dev->clk);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Sends a command and then waits for the bits masked by *flagmask*
+ * to go high or low by IRQ awaiting.
+ */
+static int stu300_start_and_await_event(struct stu300_dev *dev,
+ u8 cr_value,
+ enum stu300_event mr_event)
+{
+ int ret;
+
+ if (unlikely(irqs_disabled())) {
+ /* TODO: implement polling for this case if need be. */
+ WARN(1, "irqs are disabled, cannot poll for event\n");
+ return -EIO;
+ }
+
+ /* Lock command issue, fill in an event we wait for */
+ spin_lock_irq(&dev->cmd_issue_lock);
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = STU300_ERROR_NONE;
+ dev->cmd_event = mr_event;
+ spin_unlock_irq(&dev->cmd_issue_lock);
+
+ /* Turn on interrupt, send command and wait. */
+ cr_value |= I2C_CR_INTERRUPT_ENABLE;
+ stu300_wr8(cr_value, dev->virtbase + I2C_CR);
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ STU300_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout() "
+ "returned %d waiting for event %04x\n", ret, mr_event);
+ return ret;
+ }
+
+ if (ret == 0) {
+ dev_err(&dev->pdev->dev, "controller timed out "
+ "waiting for event %d, reinit hardware\n", mr_event);
+ (void) stu300_init_hw(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (dev->cmd_err != STU300_ERROR_NONE) {
+ dev_err(&dev->pdev->dev, "controller (start) "
+ "error %d waiting for event %d, reinit hardware\n",
+ dev->cmd_err, mr_event);
+ (void) stu300_init_hw(dev);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * This waits for a flag to be set, if it is not set on entry, an interrupt is
+ * configured to wait for the flag using a completion.
+ */
+static int stu300_await_event(struct stu300_dev *dev,
+ enum stu300_event mr_event)
+{
+ int ret;
+
+ if (unlikely(irqs_disabled())) {
+ /* TODO: implement polling for this case if need be. */
+ dev_err(&dev->pdev->dev, "irqs are disabled on this "
+ "system!\n");
+ return -EIO;
+ }
+
+ /* Is it already here? */
+ spin_lock_irq(&dev->cmd_issue_lock);
+ dev->cmd_err = STU300_ERROR_NONE;
+ dev->cmd_event = mr_event;
+
+ init_completion(&dev->cmd_complete);
+
+ /* Turn on the I2C interrupt for current operation */
+ stu300_irq_enable(dev);
+
+ /* Unlock the command block and wait for the event to occur */
+ spin_unlock_irq(&dev->cmd_issue_lock);
+
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ STU300_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout()"
+ "returned %d waiting for event %04x\n", ret, mr_event);
+ return ret;
+ }
+
+ if (ret == 0) {
+ if (mr_event != STU300_EVENT_6) {
+ dev_err(&dev->pdev->dev, "controller "
+ "timed out waiting for event %d, reinit "
+ "hardware\n", mr_event);
+ (void) stu300_init_hw(dev);
+ }
+ return -ETIMEDOUT;
+ }
+
+ if (dev->cmd_err != STU300_ERROR_NONE) {
+ if (mr_event != STU300_EVENT_6) {
+ dev_err(&dev->pdev->dev, "controller "
+ "error (await_event) %d waiting for event %d, "
+ "reinit hardware\n", dev->cmd_err, mr_event);
+ (void) stu300_init_hw(dev);
+ }
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Waits for the busy bit to go low by repeated polling.
+ */
+#define BUSY_RELEASE_ATTEMPTS 10
+static int stu300_wait_while_busy(struct stu300_dev *dev)
+{
+ unsigned long timeout;
+ int i;
+
+ for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) {
+ timeout = jiffies + STU300_TIMEOUT;
+
+ while (!time_after(jiffies, timeout)) {
+ /* Is not busy? */
+ if ((stu300_r8(dev->virtbase + I2C_SR1) &
+ I2C_SR1_BUSY_IND) == 0)
+ return 0;
+ msleep(1);
+ }
+
+ dev_err(&dev->pdev->dev, "transaction timed out "
+ "waiting for device to be free (not busy). "
+ "Attempt: %d\n", i+1);
+
+ dev_err(&dev->pdev->dev, "base address = "
+ "0x%08x, reinit hardware\n", (u32) dev->virtbase);
+
+ (void) stu300_init_hw(dev);
+ }
+
+ dev_err(&dev->pdev->dev, "giving up after %d attempts "
+ "to reset the bus.\n", BUSY_RELEASE_ATTEMPTS);
+
+ return -ETIMEDOUT;
+}
+
+struct stu300_clkset {
+ unsigned long rate;
+ u32 setting;
+};
+
+static const struct stu300_clkset stu300_clktable[] = {
+ { 0, 0xFFU },
+ { 2500000, I2C_OAR2_FR_25_10MHZ },
+ { 10000000, I2C_OAR2_FR_10_1667MHZ },
+ { 16670000, I2C_OAR2_FR_1667_2667MHZ },
+ { 26670000, I2C_OAR2_FR_2667_40MHZ },
+ { 40000000, I2C_OAR2_FR_40_5333MHZ },
+ { 53330000, I2C_OAR2_FR_5333_66MHZ },
+ { 66000000, I2C_OAR2_FR_66_80MHZ },
+ { 80000000, I2C_OAR2_FR_80_100MHZ },
+ { 100000000, 0xFFU },
+};
+
+
+static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate)
+{
+
+ u32 val;
+ int i = 0;
+
+ /* Locate the appropriate clock setting */
+ while (i < ARRAY_SIZE(stu300_clktable) - 1 &&
+ stu300_clktable[i].rate < clkrate)
+ i++;
+
+ if (stu300_clktable[i].setting == 0xFFU) {
+ dev_err(&dev->pdev->dev, "too %s clock rate requested "
+ "(%lu Hz).\n", i ? "high" : "low", clkrate);
+ return -EINVAL;
+ }
+
+ stu300_wr8(stu300_clktable[i].setting,
+ dev->virtbase + I2C_OAR2);
+
+ dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz "
+ "virtbase %p\n", clkrate, dev->speed, dev->virtbase);
+
+ if (dev->speed > 100000)
+ /* Fast Mode I2C */
+ val = ((clkrate/dev->speed) - 9)/3 + 1;
+ else
+ /* Standard Mode I2C */
+ val = ((clkrate/dev->speed) - 7)/2 + 1;
+
+ /* According to spec the divider must be > 2 */
+ if (val < 0x002) {
+ dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n",
+ clkrate);
+ return -EINVAL;
+ }
+
+ /* We have 12 bits clock divider only! */
+ if (val & 0xFFFFF000U) {
+ dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n",
+ clkrate);
+ return -EINVAL;
+ }
+
+ if (dev->speed > 100000) {
+ /* CC6..CC0 */
+ stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM,
+ dev->virtbase + I2C_CCR);
+ dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, "
+ "Fast Mode I2C\n", val);
+ } else {
+ /* CC6..CC0 */
+ stu300_wr8((val & I2C_CCR_CC_MASK),
+ dev->virtbase + I2C_CCR);
+ dev_dbg(&dev->pdev->dev, "set clock divider to "
+ "0x%08x, Standard Mode I2C\n", val);
+ }
+
+ /* CC11..CC7 */
+ stu300_wr8(((val >> 7) & 0x1F),
+ dev->virtbase + I2C_ECCR);
+
+ return 0;
+}
+
+
+static int stu300_init_hw(struct stu300_dev *dev)
+{
+ u32 dummy;
+ unsigned long clkrate;
+ int ret;
+
+ /* Disable controller */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ /*
+ * Set own address to some default value (0x00).
+ * We do not support slave mode anyway.
+ */
+ stu300_wr8(0x00, dev->virtbase + I2C_OAR1);
+ /*
+ * The I2C controller only operates properly in 26 MHz but we
+ * program this driver as if we didn't know. This will also set the two
+ * high bits of the own address to zero as well.
+ * There is no known hardware issue with running in 13 MHz
+ * However, speeds over 200 kHz are not used.
+ */
+ clkrate = clk_get_rate(dev->clk);
+ ret = stu300_set_clk(dev, clkrate);
+
+ if (ret)
+ return ret;
+ /*
+ * Enable block, do it TWICE (hardware glitch)
+ * Setting bit 7 can enable DDC mode. (Not used currently.)
+ */
+ stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+ dev->virtbase + I2C_CR);
+ stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+ dev->virtbase + I2C_CR);
+ /* Make a dummy read of the status register SR1 & SR2 */
+ dummy = stu300_r8(dev->virtbase + I2C_SR2);
+ dummy = stu300_r8(dev->virtbase + I2C_SR1);
+
+ return 0;
+}
+
+
+
+/* Send slave address. */
+static int stu300_send_address(struct stu300_dev *dev,
+ struct i2c_msg *msg, int resend)
+{
+ u32 val;
+ int ret;
+
+ if (msg->flags & I2C_M_TEN)
+ /* This is probably how 10 bit addresses look */
+ val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) &
+ I2C_DR_D_MASK;
+ else
+ val = ((msg->addr << 1) & I2C_DR_D_MASK);
+
+ if (msg->flags & I2C_M_RD) {
+ /* This is the direction bit */
+ val |= 0x01;
+ if (resend)
+ dev_dbg(&dev->pdev->dev, "read resend\n");
+ } else if (resend)
+ dev_dbg(&dev->pdev->dev, "write resend\n");
+ stu300_wr8(val, dev->virtbase + I2C_DR);
+
+ /* For 10bit addressing, await 10bit request (EVENT 9) */
+ if (msg->flags & I2C_M_TEN) {
+ ret = stu300_await_event(dev, STU300_EVENT_9);
+ /*
+ * The slave device wants a 10bit address, send the rest
+ * of the bits (the LSBits)
+ */
+ val = msg->addr & I2C_DR_D_MASK;
+ /* This clears "event 9" */
+ stu300_wr8(val, dev->virtbase + I2C_DR);
+ if (ret != 0)
+ return ret;
+ }
+ /* FIXME: Why no else here? two events for 10bit?
+ * Await event 6 (normal) or event 9 (10bit)
+ */
+
+ if (resend)
+ dev_dbg(&dev->pdev->dev, "await event 6\n");
+ ret = stu300_await_event(dev, STU300_EVENT_6);
+
+ /*
+ * Clear any pending EVENT 6 no matter what happened during
+ * await_event.
+ */
+ val = stu300_r8(dev->virtbase + I2C_CR);
+ val |= I2C_CR_PERIPHERAL_ENABLE;
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+
+ return ret;
+}
+
+static int stu300_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ u32 cr;
+ u32 val;
+ u32 i;
+ int ret;
+ int attempts = 0;
+ struct stu300_dev *dev = i2c_get_adapdata(adap);
+
+ clk_enable(dev->clk);
+
+ /* Remove this if (0) to trace each and every message. */
+ if (0) {
+ dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, "
+ "flags: 0x%04x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+ }
+
+ /* Zero-length messages are not supported by this hardware */
+ if (msg->len == 0) {
+ ret = -EINVAL;
+ goto exit_disable;
+ }
+
+ /*
+ * For some reason, sending the address sometimes fails when running
+ * on the 13 MHz clock. No interrupt arrives. This is a work around,
+ * which tries to restart and send the address up to 10 times before
+ * really giving up. Usually 5 to 8 attempts are enough.
+ */
+ do {
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "wait while busy\n");
+ /* Check that the bus is free, or wait until some timeout */
+ ret = stu300_wait_while_busy(dev);
+ if (ret != 0)
+ goto exit_disable;
+
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "re-int hw\n");
+ /*
+ * According to ST, there is no problem if the clock is
+ * changed between 13 and 26 MHz during a transfer.
+ */
+ ret = stu300_init_hw(dev);
+ if (ret)
+ goto exit_disable;
+
+ /* Send a start condition */
+ cr = I2C_CR_PERIPHERAL_ENABLE;
+ /* Setting the START bit puts the block in master mode */
+ if (!(msg->flags & I2C_M_NOSTART))
+ cr |= I2C_CR_START_ENABLE;
+ if ((msg->flags & I2C_M_RD) && (msg->len > 1))
+ /* On read more than 1 byte, we need ack. */
+ cr |= I2C_CR_ACK_ENABLE;
+ /* Check that it gets through */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "send start event\n");
+ ret = stu300_start_and_await_event(dev, cr,
+ STU300_EVENT_5);
+ }
+
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "send address\n");
+
+ if (ret == 0)
+ /* Send address */
+ ret = stu300_send_address(dev, msg, attempts != 0);
+
+ if (ret != 0) {
+ attempts++;
+ dev_dbg(&dev->pdev->dev, "failed sending address, "
+ "retrying. Attempt: %d msg_index: %d/%d\n",
+ attempts, dev->msg_index, dev->msg_len);
+ }
+
+ } while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS);
+
+ if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) {
+ dev_dbg(&dev->pdev->dev, "managed to get address "
+ "through after %d attempts\n", attempts);
+ } else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) {
+ dev_dbg(&dev->pdev->dev, "I give up, tried %d times "
+ "to resend address.\n",
+ NUM_ADDR_RESEND_ATTEMPTS);
+ goto exit_disable;
+ }
+
+
+ if (msg->flags & I2C_M_RD) {
+ /* READ: we read the actual bytes one at a time */
+ for (i = 0; i < msg->len; i++) {
+ if (i == msg->len-1) {
+ /*
+ * Disable ACK and set STOP condition before
+ * reading last byte
+ */
+ val = I2C_CR_PERIPHERAL_ENABLE;
+
+ if (stop)
+ val |= I2C_CR_STOP_ENABLE;
+
+ stu300_wr8(val,
+ dev->virtbase + I2C_CR);
+ }
+ /* Wait for this byte... */
+ ret = stu300_await_event(dev, STU300_EVENT_7);
+ if (ret != 0)
+ goto exit_disable;
+ /* This clears event 7 */
+ msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR);
+ }
+ } else {
+ /* WRITE: we send the actual bytes one at a time */
+ for (i = 0; i < msg->len; i++) {
+ /* Write the byte */
+ stu300_wr8(msg->buf[i],
+ dev->virtbase + I2C_DR);
+ /* Check status */
+ ret = stu300_await_event(dev, STU300_EVENT_8);
+ /* Next write to DR will clear event 8 */
+ if (ret != 0) {
+ dev_err(&dev->pdev->dev, "error awaiting "
+ "event 8 (%d)\n", ret);
+ goto exit_disable;
+ }
+ }
+ /* Check NAK */
+ if (!(msg->flags & I2C_M_IGNORE_NAK)) {
+ if (stu300_r8(dev->virtbase + I2C_SR2) &
+ I2C_SR2_AF_IND) {
+ dev_err(&dev->pdev->dev, "I2C payload "
+ "send returned NAK!\n");
+ ret = -EIO;
+ goto exit_disable;
+ }
+ }
+ if (stop) {
+ /* Send stop condition */
+ val = I2C_CR_PERIPHERAL_ENABLE;
+ val |= I2C_CR_STOP_ENABLE;
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+ }
+ }
+
+ /* Check that the bus is free, or wait until some timeout occurs */
+ ret = stu300_wait_while_busy(dev);
+ if (ret != 0) {
+ dev_err(&dev->pdev->dev, "timout waiting for transfer "
+ "to commence.\n");
+ goto exit_disable;
+ }
+
+ /* Dummy read status registers */
+ val = stu300_r8(dev->virtbase + I2C_SR2);
+ val = stu300_r8(dev->virtbase + I2C_SR1);
+ ret = 0;
+
+ exit_disable:
+ /* Disable controller */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ clk_disable(dev->clk);
+ return ret;
+}
+
+static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int ret = -1;
+ int i;
+
+ struct stu300_dev *dev = i2c_get_adapdata(adap);
+ dev->msg_len = num;
+
+ for (i = 0; i < num; i++) {
+ /*
+ * Another driver appears to send stop for each message,
+ * here we only do that for the last message. Possibly some
+ * peripherals require this behaviour, then their drivers
+ * have to send single messages in order to get "stop" for
+ * each message.
+ */
+ dev->msg_index = i;
+
+ ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+
+ if (ret != 0) {
+ num = ret;
+ break;
+ }
+ }
+
+ return num;
+}
+
+static u32 stu300_func(struct i2c_adapter *adap)
+{
+ /* This is the simplest thing you can think of... */
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm stu300_algo = {
+ .master_xfer = stu300_xfer,
+ .functionality = stu300_func,
+};
+
+static int __init
+stu300_probe(struct platform_device *pdev)
+{
+ struct stu300_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int bus_nr;
+ int ret = 0;
+ char clk_name[] = "I2C0";
+
+ dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "could not allocate device struct\n");
+ ret = -ENOMEM;
+ goto err_no_devmem;
+ }
+
+ bus_nr = pdev->id;
+ clk_name[3] += (char)bus_nr;
+ dev->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(dev->clk)) {
+ ret = PTR_ERR(dev->clk);
+ dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
+ goto err_no_clk;
+ }
+
+ dev->pdev = pdev;
+ platform_set_drvdata(pdev, dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto err_no_resource;
+ }
+
+ dev->phybase = res->start;
+ dev->physize = resource_size(res);
+
+ if (request_mem_region(dev->phybase, dev->physize,
+ NAME " I/O Area") == NULL) {
+ ret = -EBUSY;
+ goto err_no_ioregion;
+ }
+
+ dev->virtbase = ioremap(dev->phybase, dev->physize);
+ dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
+ "base %p\n", bus_nr, dev->virtbase);
+ if (!dev->virtbase) {
+ ret = -ENOMEM;
+ goto err_no_ioremap;
+ }
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED,
+ NAME, dev)) {
+ ret = -EIO;
+ goto err_no_irq;
+ }
+
+ dev->speed = scl_frequency;
+
+ clk_enable(dev->clk);
+ ret = stu300_init_hw(dev);
+ clk_disable(dev->clk);
+
+ if (ret != 0) {
+ dev_err(&dev->pdev->dev, "error initializing hardware.\n");
+ goto err_init_hw;
+ }
+
+ /* IRQ event handling initialization */
+ spin_lock_init(&dev->cmd_issue_lock);
+ dev->cmd_event = STU300_EVENT_NONE;
+ dev->cmd_err = STU300_ERROR_NONE;
+
+ adap = &dev->adapter;
+ adap->owner = THIS_MODULE;
+ /* DDC class but actually often used for more generic I2C */
+ adap->class = I2C_CLASS_DDC;
+ strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
+ sizeof(adap->name));
+ adap->nr = bus_nr;
+ adap->algo = &stu300_algo;
+ adap->dev.parent = &pdev->dev;
+ i2c_set_adapdata(adap, dev);
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failure adding ST Micro DDC "
+ "I2C adapter\n");
+ goto err_add_adapter;
+ }
+ return 0;
+
+ err_add_adapter:
+ err_init_hw:
+ free_irq(dev->irq, dev);
+ err_no_irq:
+ iounmap(dev->virtbase);
+ err_no_ioremap:
+ release_mem_region(dev->phybase, dev->physize);
+ err_no_ioregion:
+ platform_set_drvdata(pdev, NULL);
+ err_no_resource:
+ clk_put(dev->clk);
+ err_no_clk:
+ kfree(dev);
+ err_no_devmem:
+ dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n",
+ pdev->id);
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int stu300_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+ /* Turn off everything */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ return 0;
+}
+
+static int stu300_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+ clk_enable(dev->clk);
+ ret = stu300_init_hw(dev);
+ clk_disable(dev->clk);
+
+ if (ret != 0)
+ dev_err(&pdev->dev, "error re-initializing hardware.\n");
+ return ret;
+}
+#else
+#define stu300_suspend NULL
+#define stu300_resume NULL
+#endif
+
+static int __exit
+stu300_remove(struct platform_device *pdev)
+{
+ struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+ /* Turn off everything */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ free_irq(dev->irq, dev);
+ iounmap(dev->virtbase);
+ release_mem_region(dev->phybase, dev->physize);
+ clk_put(dev->clk);
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+ return 0;
+}
+
+static struct platform_driver stu300_i2c_driver = {
+ .driver = {
+ .name = NAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(stu300_remove),
+ .suspend = stu300_suspend,
+ .resume = stu300_resume,
+
+};
+
+static int __init stu300_init(void)
+{
+ return platform_driver_probe(&stu300_i2c_driver, stu300_probe);
+}
+
+static void __exit stu300_exit(void)
+{
+ platform_driver_unregister(&stu300_i2c_driver);
+}
+
+/*
+ * The systems using this bus often have very basic devices such
+ * as regulators on the I2C bus, so this needs to be loaded early.
+ * Therefore it is registered in the subsys_initcall().
+ */
+subsys_initcall(stu300_init);
+module_exit(stu300_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" NAME);
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
new file mode 100644
index 00000000..b1b34479
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -0,0 +1,222 @@
+/*
+ i2c-stub.c - I2C/SMBus chip emulator
+
+ Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
+ Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ 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.
+*/
+
+#define DEBUG 1
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+
+#define MAX_CHIPS 10
+#define STUB_FUNC (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
+ I2C_FUNC_SMBUS_I2C_BLOCK)
+
+static unsigned short chip_addr[MAX_CHIPS];
+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 = STUB_FUNC;
+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
+ specification */
+};
+
+static struct stub_chip *stub_chips;
+
+/* Return negative errno on error. */
+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, len;
+ struct stub_chip *chip = NULL;
+
+ /* Search for the right chip */
+ for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+ if (addr == chip_addr[i]) {
+ chip = stub_chips + i;
+ break;
+ }
+ }
+ if (!chip)
+ return -ENODEV;
+
+ switch (size) {
+
+ case I2C_SMBUS_QUICK:
+ dev_dbg(&adap->dev, "smbus quick - addr 0x%02x\n", addr);
+ ret = 0;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE) {
+ chip->pointer = command;
+ dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
+ "wrote 0x%02x.\n",
+ addr, command);
+ } else {
+ data->byte = chip->words[chip->pointer++] & 0xff;
+ dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
+ "read 0x%02x.\n",
+ addr, data->byte);
+ }
+
+ ret = 0;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_WRITE) {
+ chip->words[command] &= 0xff00;
+ chip->words[command] |= data->byte;
+ dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+ "wrote 0x%02x at 0x%02x.\n",
+ addr, data->byte, command);
+ } else {
+ data->byte = chip->words[command] & 0xff;
+ dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+ "read 0x%02x at 0x%02x.\n",
+ addr, data->byte, command);
+ }
+ chip->pointer = command + 1;
+
+ ret = 0;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_WRITE) {
+ chip->words[command] = data->word;
+ dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
+ "wrote 0x%04x at 0x%02x.\n",
+ addr, data->word, command);
+ } else {
+ data->word = chip->words[command];
+ dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
+ "read 0x%04x at 0x%02x.\n",
+ addr, data->word, command);
+ }
+
+ 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;
+ break;
+ } /* switch (size) */
+
+ return ret;
+}
+
+static u32 stub_func(struct i2c_adapter *adapter)
+{
+ return STUB_FUNC & functionality;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .functionality = stub_func,
+ .smbus_xfer = stub_xfer,
+};
+
+static struct i2c_adapter stub_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+ .name = "SMBus stub driver",
+};
+
+static int __init i2c_stub_init(void)
+{
+ int i, ret;
+
+ if (!chip_addr[0]) {
+ printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+ if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
+ printk(KERN_ERR "i2c-stub: Invalid chip address "
+ "0x%02x\n", chip_addr[i]);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
+ chip_addr[i]);
+ }
+
+ /* Allocate memory for all chips at once */
+ stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
+ if (!stub_chips) {
+ printk(KERN_ERR "i2c-stub: Out of memory\n");
+ return -ENOMEM;
+ }
+
+ ret = i2c_add_adapter(&stub_adapter);
+ if (ret)
+ kfree(stub_chips);
+ return ret;
+}
+
+static void __exit i2c_stub_exit(void)
+{
+ i2c_del_adapter(&stub_adapter);
+ kfree(stub_chips);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("I2C stub driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_stub_init);
+module_exit(i2c_stub_exit);
+
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
new file mode 100644
index 00000000..26c352a0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -0,0 +1,331 @@
+/*
+ * Driver for the TAOS evaluation modules
+ * These devices include an I2C master which can be controlled over the
+ * serial port.
+ *
+ * Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#define TAOS_BUFFER_SIZE 63
+
+#define TAOS_STATE_INIT 0
+#define TAOS_STATE_IDLE 1
+#define TAOS_STATE_EOFF 2
+#define TAOS_STATE_RECV 3
+
+#define TAOS_CMD_RESET 0x12
+#define TAOS_CMD_ECHO_ON '+'
+#define TAOS_CMD_ECHO_OFF '-'
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+struct taos_data {
+ struct i2c_adapter adapter;
+ struct i2c_client *client;
+ int state;
+ u8 addr; /* last used address */
+ unsigned char buffer[TAOS_BUFFER_SIZE];
+ unsigned int pos; /* position inside the buffer */
+};
+
+/* TAOS TSL2550 EVM */
+static struct i2c_board_info tsl2550_info = {
+ I2C_BOARD_INFO("tsl2550", 0x39),
+};
+
+/* Instantiate i2c devices based on the adapter name */
+static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
+{
+ if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
+ dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
+ tsl2550_info.type, tsl2550_info.addr);
+ return i2c_new_device(adapter, &tsl2550_info);
+ }
+
+ return NULL;
+}
+
+static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct serio *serio = adapter->algo_data;
+ struct taos_data *taos = serio_get_drvdata(serio);
+ char *p;
+
+ /* Encode our transaction. "@" is for the device address, "$" for the
+ SMBus command and "#" for the data. */
+ p = taos->buffer;
+
+ /* The device remembers the last used address, no need to send it
+ again if it's the same */
+ if (addr != taos->addr)
+ p += sprintf(p, "@%02X", addr);
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ sprintf(p, "$#%02X", command);
+ else
+ sprintf(p, "$");
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_WRITE)
+ sprintf(p, "$%02X#%02X", command, data->byte);
+ else
+ sprintf(p, "$%02X", command);
+ break;
+ default:
+ dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ /* Send the transaction to the TAOS EVM */
+ dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
+ for (p = taos->buffer; *p; p++)
+ serio_write(serio, *p);
+
+ taos->addr = addr;
+
+ /* Start the transaction and read the answer */
+ taos->pos = 0;
+ taos->state = TAOS_STATE_RECV;
+ serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(150));
+ if (taos->state != TAOS_STATE_IDLE
+ || taos->pos != 5) {
+ dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
+ taos->pos);
+ return -EIO;
+ }
+ dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
+
+ /* Interpret the returned string */
+ p = taos->buffer + 1;
+ p[3] = '\0';
+ if (!strcmp(p, "NAK"))
+ return -ENODEV;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ if (!strcmp(p, "ACK"))
+ return 0;
+ } else {
+ if (p[0] == 'x') {
+ data->byte = simple_strtol(p + 1, NULL, 16);
+ return 0;
+ }
+ }
+
+ return -EIO;
+}
+
+static u32 taos_smbus_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm taos_algorithm = {
+ .smbus_xfer = taos_smbus_xfer,
+ .functionality = taos_smbus_func,
+};
+
+static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
+ unsigned int flags)
+{
+ struct taos_data *taos = serio_get_drvdata(serio);
+
+ switch (taos->state) {
+ case TAOS_STATE_INIT:
+ taos->buffer[taos->pos++] = data;
+ if (data == ':'
+ || taos->pos == TAOS_BUFFER_SIZE - 1) {
+ taos->buffer[taos->pos] = '\0';
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ case TAOS_STATE_EOFF:
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ break;
+ case TAOS_STATE_RECV:
+ taos->buffer[taos->pos++] = data;
+ if (data == ']') {
+ taos->buffer[taos->pos] = '\0';
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Extract the adapter name from the buffer received after reset.
+ The buffer is modified and a pointer inside the buffer is returned. */
+static char *taos_adapter_name(char *buffer)
+{
+ char *start, *end;
+
+ start = strstr(buffer, "TAOS ");
+ if (!start)
+ return NULL;
+
+ end = strchr(start, '\r');
+ if (!end)
+ return NULL;
+ *end = '\0';
+
+ return start;
+}
+
+static int taos_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct taos_data *taos;
+ struct i2c_adapter *adapter;
+ char *name;
+ int err;
+
+ taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
+ if (!taos) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ taos->state = TAOS_STATE_INIT;
+ serio_set_drvdata(serio, taos);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto exit_kfree;
+
+ adapter = &taos->adapter;
+ adapter->owner = THIS_MODULE;
+ adapter->algo = &taos_algorithm;
+ adapter->algo_data = serio;
+ adapter->dev.parent = &serio->dev;
+
+ /* Reset the TAOS evaluation module to identify it */
+ serio_write(serio, TAOS_CMD_RESET);
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(2000));
+
+ if (taos->state != TAOS_STATE_IDLE) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, "
+ "pos=%d)\n", taos->state, taos->pos);
+ goto exit_close;
+ }
+
+ name = taos_adapter_name(taos->buffer);
+ if (!name) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM identification failed\n");
+ goto exit_close;
+ }
+ strlcpy(adapter->name, name, sizeof(adapter->name));
+
+ /* Turn echo off for better performance */
+ taos->state = TAOS_STATE_EOFF;
+ serio_write(serio, TAOS_CMD_ECHO_OFF);
+
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(250));
+ if (taos->state != TAOS_STATE_IDLE) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM echo off failed "
+ "(state=%d)\n", taos->state);
+ goto exit_close;
+ }
+
+ err = i2c_add_adapter(adapter);
+ if (err)
+ goto exit_close;
+ dev_info(&serio->dev, "Connected to TAOS EVM\n");
+
+ taos->client = taos_instantiate_device(adapter);
+ return 0;
+
+ exit_close:
+ serio_close(serio);
+ exit_kfree:
+ serio_set_drvdata(serio, NULL);
+ kfree(taos);
+ exit:
+ return err;
+}
+
+static void taos_disconnect(struct serio *serio)
+{
+ struct taos_data *taos = serio_get_drvdata(serio);
+
+ if (taos->client)
+ i2c_unregister_device(taos->client);
+ i2c_del_adapter(&taos->adapter);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ kfree(taos);
+
+ dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
+}
+
+static struct serio_device_id taos_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_TAOSEVM,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(serio, taos_serio_ids);
+
+static struct serio_driver taos_drv = {
+ .driver = {
+ .name = "taos-evm",
+ },
+ .description = "TAOS evaluation module driver",
+ .id_table = taos_serio_ids,
+ .connect = taos_connect,
+ .disconnect = taos_disconnect,
+ .interrupt = taos_interrupt,
+};
+
+static int __init taos_init(void)
+{
+ return serio_register_driver(&taos_drv);
+}
+
+static void __exit taos_exit(void)
+{
+ serio_unregister_driver(&taos_drv);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("TAOS evaluation module driver");
+MODULE_LICENSE("GPL");
+
+module_init(taos_init);
+module_exit(taos_exit);
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
new file mode 100644
index 00000000..fb3b4f8f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -0,0 +1,735 @@
+/*
+ * drivers/i2c/busses/i2c-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c-tegra.h>
+
+#include <asm/unaligned.h>
+
+#include <mach/clk.h>
+
+#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
+#define BYTES_PER_FIFO_WORD 4
+
+#define I2C_CNFG 0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
+#define I2C_CNFG_PACKET_MODE_EN (1<<10)
+#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
+#define I2C_STATUS 0x01C
+#define I2C_SL_CNFG 0x020
+#define I2C_SL_CNFG_NACK (1<<1)
+#define I2C_SL_CNFG_NEWSL (1<<2)
+#define I2C_SL_ADDR1 0x02c
+#define I2C_SL_ADDR2 0x030
+#define I2C_TX_FIFO 0x050
+#define I2C_RX_FIFO 0x054
+#define I2C_PACKET_TRANSFER_STATUS 0x058
+#define I2C_FIFO_CONTROL 0x05c
+#define I2C_FIFO_CONTROL_TX_FLUSH (1<<1)
+#define I2C_FIFO_CONTROL_RX_FLUSH (1<<0)
+#define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5
+#define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2
+#define I2C_FIFO_STATUS 0x060
+#define I2C_FIFO_STATUS_TX_MASK 0xF0
+#define I2C_FIFO_STATUS_TX_SHIFT 4
+#define I2C_FIFO_STATUS_RX_MASK 0x0F
+#define I2C_FIFO_STATUS_RX_SHIFT 0
+#define I2C_INT_MASK 0x064
+#define I2C_INT_STATUS 0x068
+#define I2C_INT_PACKET_XFER_COMPLETE (1<<7)
+#define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1<<6)
+#define I2C_INT_TX_FIFO_OVERFLOW (1<<5)
+#define I2C_INT_RX_FIFO_UNDERFLOW (1<<4)
+#define I2C_INT_NO_ACK (1<<3)
+#define I2C_INT_ARBITRATION_LOST (1<<2)
+#define I2C_INT_TX_FIFO_DATA_REQ (1<<1)
+#define I2C_INT_RX_FIFO_DATA_REQ (1<<0)
+#define I2C_CLK_DIVISOR 0x06c
+
+#define DVC_CTRL_REG1 0x000
+#define DVC_CTRL_REG1_INTR_EN (1<<10)
+#define DVC_CTRL_REG2 0x004
+#define DVC_CTRL_REG3 0x008
+#define DVC_CTRL_REG3_SW_PROG (1<<26)
+#define DVC_CTRL_REG3_I2C_DONE_INTR_EN (1<<30)
+#define DVC_STATUS 0x00c
+#define DVC_STATUS_I2C_DONE_INTR (1<<30)
+
+#define I2C_ERR_NONE 0x00
+#define I2C_ERR_NO_ACK 0x01
+#define I2C_ERR_ARBITRATION_LOST 0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT 0x04
+
+#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
+#define PACKET_HEADER0_PACKET_ID_SHIFT 16
+#define PACKET_HEADER0_CONT_ID_SHIFT 12
+#define PACKET_HEADER0_PROTOCOL_I2C (1<<4)
+
+#define I2C_HEADER_HIGHSPEED_MODE (1<<22)
+#define I2C_HEADER_CONT_ON_NAK (1<<21)
+#define I2C_HEADER_SEND_START_BYTE (1<<20)
+#define I2C_HEADER_READ (1<<19)
+#define I2C_HEADER_10BIT_ADDR (1<<18)
+#define I2C_HEADER_IE_ENABLE (1<<17)
+#define I2C_HEADER_REPEAT_START (1<<16)
+#define I2C_HEADER_MASTER_ADDR_SHIFT 12
+#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
+
+/**
+ * struct tegra_i2c_dev - per device i2c context
+ * @dev: device reference for power management
+ * @adapter: core i2c layer adapter information
+ * @clk: clock reference for i2c controller
+ * @i2c_clk: clock reference for i2c bus
+ * @iomem: memory resource for registers
+ * @base: ioremapped registers cookie
+ * @cont_id: i2c controller id, used for for packet header
+ * @irq: irq number of transfer complete interrupt
+ * @is_dvc: identifies the DVC i2c controller, has a different register layout
+ * @msg_complete: transfer completion notifier
+ * @msg_err: error code for completed message
+ * @msg_buf: pointer to current message data
+ * @msg_buf_remaining: size of unsent data in the message buffer
+ * @msg_read: identifies read transfers
+ * @bus_clk_rate: current i2c bus clock rate
+ * @is_suspended: prevents i2c controller accesses after suspend is called
+ */
+struct tegra_i2c_dev {
+ struct device *dev;
+ struct i2c_adapter adapter;
+ struct clk *clk;
+ struct clk *i2c_clk;
+ struct resource *iomem;
+ void __iomem *base;
+ int cont_id;
+ int irq;
+ bool irq_disabled;
+ int is_dvc;
+ struct completion msg_complete;
+ int msg_err;
+ u8 *msg_buf;
+ size_t msg_buf_remaining;
+ int msg_read;
+ unsigned long bus_clk_rate;
+ bool is_suspended;
+};
+
+static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
+{
+ writel(val, i2c_dev->base + reg);
+}
+
+static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+ return readl(i2c_dev->base + reg);
+}
+
+/*
+ * i2c_writel and i2c_readl will offset the register if necessary to talk
+ * to the I2C block inside the DVC block
+ */
+static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
+ unsigned long reg)
+{
+ if (i2c_dev->is_dvc)
+ reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
+ return reg;
+}
+
+static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
+ unsigned long reg)
+{
+ writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+ return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
+ unsigned long reg, int len)
+{
+ writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
+ unsigned long reg, int len)
+{
+ readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+ u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
+ int_mask &= ~mask;
+ i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+ u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
+ int_mask |= mask;
+ i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
+{
+ unsigned long timeout = jiffies + HZ;
+ u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL);
+ val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH;
+ i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+
+ while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) &
+ (I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int rx_fifo_avail;
+ u8 *buf = i2c_dev->msg_buf;
+ size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ int words_to_transfer;
+
+ val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
+ I2C_FIFO_STATUS_RX_SHIFT;
+
+ /* Rounds down to not include partial word at the end of buf */
+ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+ if (words_to_transfer > rx_fifo_avail)
+ words_to_transfer = rx_fifo_avail;
+
+ i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ rx_fifo_avail -= words_to_transfer;
+
+ /*
+ * If there is a partial word at the end of buf, handle it manually to
+ * prevent overwriting past the end of buf
+ */
+ if (rx_fifo_avail > 0 && buf_remaining > 0) {
+ BUG_ON(buf_remaining > 3);
+ val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+ memcpy(buf, &val, buf_remaining);
+ buf_remaining = 0;
+ rx_fifo_avail--;
+ }
+
+ BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf;
+ return 0;
+}
+
+static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int tx_fifo_avail;
+ u8 *buf = i2c_dev->msg_buf;
+ size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ int words_to_transfer;
+
+ val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
+ I2C_FIFO_STATUS_TX_SHIFT;
+
+ /* Rounds down to not include partial word at the end of buf */
+ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+ if (words_to_transfer > tx_fifo_avail)
+ words_to_transfer = tx_fifo_avail;
+
+ i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ tx_fifo_avail -= words_to_transfer;
+
+ /*
+ * If there is a partial word at the end of buf, handle it manually to
+ * prevent reading past the end of buf, which could cross a page
+ * boundary and fault.
+ */
+ if (tx_fifo_avail > 0 && buf_remaining > 0) {
+ BUG_ON(buf_remaining > 3);
+ memcpy(&val, buf, buf_remaining);
+ i2c_writel(i2c_dev, val, I2C_TX_FIFO);
+ buf_remaining = 0;
+ tx_fifo_avail--;
+ }
+
+ BUG_ON(tx_fifo_avail > 0 && buf_remaining > 0);
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf;
+ return 0;
+}
+
+/*
+ * One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
+ * block. This block is identical to the rest of the I2C blocks, except that
+ * it only supports master mode, it has registers moved around, and it needs
+ * some extra init to get it into I2C mode. The register moves are handled
+ * by i2c_readl and i2c_writel
+ */
+static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val = 0;
+ val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
+ val |= DVC_CTRL_REG3_SW_PROG;
+ val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
+ dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
+
+ val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
+ val |= DVC_CTRL_REG1_INTR_EN;
+ dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
+}
+
+static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int err = 0;
+
+ clk_enable(i2c_dev->clk);
+
+ tegra_periph_reset_assert(i2c_dev->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(i2c_dev->clk);
+
+ if (i2c_dev->is_dvc)
+ tegra_dvc_init(i2c_dev);
+
+ val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+ (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
+ i2c_writel(i2c_dev, val, I2C_CNFG);
+ i2c_writel(i2c_dev, 0, I2C_INT_MASK);
+ clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
+
+ if (!i2c_dev->is_dvc) {
+ u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+ sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
+ i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
+ i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
+ i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
+
+ }
+
+ val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
+ 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
+ i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+
+ if (tegra_i2c_flush_fifos(i2c_dev))
+ err = -ETIMEDOUT;
+
+ clk_disable(i2c_dev->clk);
+
+ if (i2c_dev->irq_disabled) {
+ i2c_dev->irq_disabled = 0;
+ enable_irq(i2c_dev->irq);
+ }
+
+ return err;
+}
+
+static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
+{
+ u32 status;
+ const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ struct tegra_i2c_dev *i2c_dev = dev_id;
+
+ status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+
+ if (status == 0) {
+ dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+ i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+ i2c_readl(i2c_dev, I2C_STATUS),
+ i2c_readl(i2c_dev, I2C_CNFG));
+ i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+ if (!i2c_dev->irq_disabled) {
+ disable_irq_nosync(i2c_dev->irq);
+ i2c_dev->irq_disabled = 1;
+ }
+
+ complete(&i2c_dev->msg_complete);
+ goto err;
+ }
+
+ if (unlikely(status & status_err)) {
+ if (status & I2C_INT_NO_ACK)
+ i2c_dev->msg_err |= I2C_ERR_NO_ACK;
+ if (status & I2C_INT_ARBITRATION_LOST)
+ i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
+ complete(&i2c_dev->msg_complete);
+ goto err;
+ }
+
+ if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
+ if (i2c_dev->msg_buf_remaining)
+ tegra_i2c_empty_rx_fifo(i2c_dev);
+ else
+ BUG();
+ }
+
+ if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
+ if (i2c_dev->msg_buf_remaining)
+ tegra_i2c_fill_tx_fifo(i2c_dev);
+ else
+ tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
+ }
+
+ if ((status & I2C_INT_PACKET_XFER_COMPLETE) &&
+ !i2c_dev->msg_buf_remaining)
+ complete(&i2c_dev->msg_complete);
+
+ i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ if (i2c_dev->is_dvc)
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ return IRQ_HANDLED;
+err:
+ /* An error occurred, mask all interrupts */
+ tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
+ I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
+ I2C_INT_RX_FIFO_DATA_REQ);
+ i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ if (i2c_dev->is_dvc)
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ return IRQ_HANDLED;
+}
+
+static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, int stop)
+{
+ u32 packet_header;
+ u32 int_mask;
+ int ret;
+
+ tegra_i2c_flush_fifos(i2c_dev);
+ i2c_writel(i2c_dev, 0xFF, I2C_INT_STATUS);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ i2c_dev->msg_buf = msg->buf;
+ i2c_dev->msg_buf_remaining = msg->len;
+ i2c_dev->msg_err = I2C_ERR_NONE;
+ i2c_dev->msg_read = (msg->flags & I2C_M_RD);
+ INIT_COMPLETION(i2c_dev->msg_complete);
+
+ packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
+ PACKET_HEADER0_PROTOCOL_I2C |
+ (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
+ (1 << PACKET_HEADER0_PACKET_ID_SHIFT);
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ packet_header = msg->len - 1;
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
+ packet_header |= I2C_HEADER_IE_ENABLE;
+ if (!stop)
+ packet_header |= I2C_HEADER_REPEAT_START;
+ if (msg->flags & I2C_M_TEN)
+ packet_header |= I2C_HEADER_10BIT_ADDR;
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ packet_header |= I2C_HEADER_CONT_ON_NAK;
+ if (msg->flags & I2C_M_RD)
+ packet_header |= I2C_HEADER_READ;
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ if (!(msg->flags & I2C_M_RD))
+ tegra_i2c_fill_tx_fifo(i2c_dev);
+
+ int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ if (msg->flags & I2C_M_RD)
+ int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
+ else if (i2c_dev->msg_buf_remaining)
+ int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+ tegra_i2c_unmask_irq(i2c_dev, int_mask);
+ dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
+ i2c_readl(i2c_dev, I2C_INT_MASK));
+
+ ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT);
+ tegra_i2c_mask_irq(i2c_dev, int_mask);
+
+ if (WARN_ON(ret == 0)) {
+ dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+
+ tegra_i2c_init(i2c_dev);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n",
+ ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err);
+
+ if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
+ return 0;
+
+ tegra_i2c_init(i2c_dev);
+ if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ return -EREMOTEIO;
+ }
+
+ return -EIO;
+}
+
+static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ int i;
+ int ret = 0;
+
+ if (i2c_dev->is_suspended)
+ return -EBUSY;
+
+ clk_enable(i2c_dev->clk);
+ for (i = 0; i < num; i++) {
+ int stop = (i == (num - 1)) ? 1 : 0;
+ ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+ if (ret)
+ break;
+ }
+ clk_disable(i2c_dev->clk);
+ return ret ?: i;
+}
+
+static u32 tegra_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm tegra_i2c_algo = {
+ .master_xfer = tegra_i2c_xfer,
+ .functionality = tegra_i2c_func,
+};
+
+static int tegra_i2c_probe(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev;
+ struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct resource *iomem;
+ struct clk *clk;
+ struct clk *i2c_clk;
+ void *base;
+ int irq;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -EINVAL;
+ }
+ iomem = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!iomem) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ base = ioremap(iomem->start, resource_size(iomem));
+ if (!base) {
+ dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no irq resource\n");
+ ret = -EINVAL;
+ goto err_iounmap;
+ }
+ irq = res->start;
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "missing controller clock");
+ ret = PTR_ERR(clk);
+ goto err_release_region;
+ }
+
+ i2c_clk = clk_get(&pdev->dev, "i2c");
+ if (IS_ERR(i2c_clk)) {
+ dev_err(&pdev->dev, "missing bus clock");
+ ret = PTR_ERR(i2c_clk);
+ goto err_clk_put;
+ }
+
+ i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
+ if (!i2c_dev) {
+ ret = -ENOMEM;
+ goto err_i2c_clk_put;
+ }
+
+ i2c_dev->base = base;
+ i2c_dev->clk = clk;
+ i2c_dev->i2c_clk = i2c_clk;
+ i2c_dev->iomem = iomem;
+ i2c_dev->adapter.algo = &tegra_i2c_algo;
+ i2c_dev->irq = irq;
+ i2c_dev->cont_id = pdev->id;
+ i2c_dev->dev = &pdev->dev;
+ i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000;
+
+ if (pdev->id == 3)
+ i2c_dev->is_dvc = 1;
+ init_completion(&i2c_dev->msg_complete);
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ ret = tegra_i2c_init(i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize i2c controller");
+ goto err_free;
+ }
+
+ ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
+ goto err_free;
+ }
+
+ clk_enable(i2c_dev->i2c_clk);
+
+ i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
+ i2c_dev->adapter.owner = THIS_MODULE;
+ i2c_dev->adapter.class = I2C_CLASS_HWMON;
+ strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
+ sizeof(i2c_dev->adapter.name));
+ i2c_dev->adapter.algo = &tegra_i2c_algo;
+ i2c_dev->adapter.dev.parent = &pdev->dev;
+ i2c_dev->adapter.nr = pdev->id;
+
+ ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add I2C adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+err_free_irq:
+ free_irq(i2c_dev->irq, i2c_dev);
+err_free:
+ kfree(i2c_dev);
+err_i2c_clk_put:
+ clk_put(i2c_clk);
+err_clk_put:
+ clk_put(clk);
+err_release_region:
+ release_mem_region(iomem->start, resource_size(iomem));
+err_iounmap:
+ iounmap(base);
+ return ret;
+}
+
+static int tegra_i2c_remove(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ i2c_del_adapter(&i2c_dev->adapter);
+ free_irq(i2c_dev->irq, i2c_dev);
+ clk_put(i2c_dev->i2c_clk);
+ clk_put(i2c_dev->clk);
+ release_mem_region(i2c_dev->iomem->start,
+ resource_size(i2c_dev->iomem));
+ iounmap(i2c_dev->base);
+ kfree(i2c_dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ i2c_lock_adapter(&i2c_dev->adapter);
+ i2c_dev->is_suspended = true;
+ i2c_unlock_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static int tegra_i2c_resume(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ int ret;
+
+ i2c_lock_adapter(&i2c_dev->adapter);
+
+ ret = tegra_i2c_init(i2c_dev);
+
+ if (ret) {
+ i2c_unlock_adapter(&i2c_dev->adapter);
+ return ret;
+ }
+
+ i2c_dev->is_suspended = false;
+
+ i2c_unlock_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver tegra_i2c_driver = {
+ .probe = tegra_i2c_probe,
+ .remove = tegra_i2c_remove,
+#ifdef CONFIG_PM
+ .suspend = tegra_i2c_suspend,
+ .resume = tegra_i2c_resume,
+#endif
+ .driver = {
+ .name = "tegra-i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tegra_i2c_init_driver(void)
+{
+ return platform_driver_register(&tegra_i2c_driver);
+}
+
+static void __exit tegra_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&tegra_i2c_driver);
+}
+
+subsys_initcall(tegra_i2c_init_driver);
+module_exit(tegra_i2c_exit_driver);
+
+MODULE_DESCRIPTION("nVidia Tegra2 I2C Bus Controller driver");
+MODULE_AUTHOR("Colin Cross");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 00000000..d03b0400
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,284 @@
+/*
+ * driver for the i2c-tiny-usb adapter - 1.0
+ * http://www.harbaum.org/till/i2c_tiny_usb
+ *
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.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, version 2.
+ *
+ */
+
+#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>
+
+/* include interface to i2c layer */
+#include <linux/i2c.h>
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_ECHO 0
+#define CMD_GET_FUNC 1
+#define CMD_SET_DELAY 2
+#define CMD_GET_STATUS 3
+
+#define CMD_I2C_IO 4
+#define CMD_I2C_IO_BEGIN (1<<0)
+#define CMD_I2C_IO_END (1<<1)
+
+/* 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);
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+/* ----- begin of i2c layer ---------------------------------------------- */
+
+#define STATUS_IDLE 0
+#define STATUS_ADDRESS_ACK 1
+#define STATUS_ADDRESS_NAK 2
+
+static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ unsigned char status;
+ struct i2c_msg *pmsg;
+ int i;
+
+ dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+
+ for (i = 0 ; i < num ; i++) {
+ int cmd = CMD_I2C_IO;
+
+ if (i == 0)
+ cmd |= CMD_I2C_IO_BEGIN;
+
+ if (i == num-1)
+ cmd |= CMD_I2C_IO_END;
+
+ pmsg = &msgs[i];
+
+ dev_dbg(&adapter->dev,
+ " %d: %s (flags %d) %d bytes to 0x%02x\n",
+ i, pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->flags, pmsg->len, pmsg->addr);
+
+ /* and directly send the message */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read data */
+ if (usb_read(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure reading data\n");
+ return -EREMOTEIO;
+ }
+ } else {
+ /* write data */
+ if (usb_write(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure writing data\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ /* read status */
+ if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
+ dev_err(&adapter->dev, "failure reading status\n");
+ return -EREMOTEIO;
+ }
+
+ dev_dbg(&adapter->dev, " status = %d\n", status);
+ if (status == STATUS_ADDRESS_NAK)
+ return -EREMOTEIO;
+ }
+
+ return i;
+}
+
+static u32 usb_func(struct i2c_adapter *adapter)
+{
+ __le32 func;
+
+ /* get functionality from adapter */
+ if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
+ sizeof(func)) {
+ dev_err(&adapter->dev, "failure reading functionality\n");
+ return 0;
+ }
+
+ return le32_to_cpu(func);
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm usb_algorithm = {
+ .master_xfer = usb_xfer,
+ .functionality = usb_func,
+};
+
+/* ----- end of i2c layer ------------------------------------------------ */
+
+/* ----- begin of usb layer ---------------------------------------------- */
+
+/*
+ * Initially the usb i2c interface uses a vid/pid pair donated by
+ * Future Technology Devices International Ltd., later a pair was
+ * bought from EZPrototypes
+ */
+static const struct usb_device_id i2c_tiny_usb_table[] = {
+ { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
+ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_tiny_usb {
+ struct usb_device *usb_dev; /* the usb device for this device */
+ struct usb_interface *interface; /* the interface for this device */
+ struct i2c_adapter adapter; /* i2c related things */
+};
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+ /* do control transfer */
+ return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+ USB_DIR_IN, value, index, data, len, 2000);
+}
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+ /* do control transfer */
+ return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, data, len, 2000);
+}
+
+static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
+{
+ usb_put_dev(dev->usb_dev);
+ kfree(dev);
+}
+
+static int i2c_tiny_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct i2c_tiny_usb *dev;
+ int retval = -ENOMEM;
+ u16 version;
+
+ dev_dbg(&interface->dev, "probing usb device\n");
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ goto error;
+ }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
+ dev_info(&interface->dev,
+ "version %x.%02x found at bus %03d address %03d\n",
+ version >> 8, version & 0xff,
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ /* setup i2c adapter description */
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &usb_algorithm;
+ dev->adapter.algo_data = dev;
+ snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+ "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, delay, 0, NULL, 0) != 0) {
+ dev_err(&dev->adapter.dev,
+ "failure setting delay to %dus\n", delay);
+ retval = -EIO;
+ goto error;
+ }
+
+ dev->adapter.dev.parent = &dev->interface->dev;
+
+ /* and finally attach to i2c layer */
+ i2c_add_adapter(&dev->adapter);
+
+ /* inform user about successful attachment to i2c layer */
+ dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
+
+ return 0;
+
+ error:
+ if (dev)
+ i2c_tiny_usb_free(dev);
+
+ return retval;
+}
+
+static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
+{
+ struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&dev->adapter);
+ usb_set_intfdata(interface, NULL);
+ i2c_tiny_usb_free(dev);
+
+ dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver i2c_tiny_usb_driver = {
+ .name = "i2c-tiny-usb",
+ .probe = i2c_tiny_usb_probe,
+ .disconnect = i2c_tiny_usb_disconnect,
+ .id_table = i2c_tiny_usb_table,
+};
+
+static int __init usb_i2c_tiny_usb_init(void)
+{
+ /* register this driver with the USB subsystem */
+ return usb_register(&i2c_tiny_usb_driver);
+}
+
+static void __exit usb_i2c_tiny_usb_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&i2c_tiny_usb_driver);
+}
+
+module_init(usb_i2c_tiny_usb_init);
+module_exit(usb_i2c_tiny_usb_exit);
+
+/* ----- end of usb layer ------------------------------------------------ */
+
+MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
+MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
new file mode 100644
index 00000000..60556012
--- /dev/null
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -0,0 +1,160 @@
+/*
+ * i2c-versatile.c
+ *
+ * Copyright (C) 2006 ARM Ltd.
+ * written by Russell King, Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#define I2C_CONTROL 0x00
+#define I2C_CONTROLS 0x00
+#define I2C_CONTROLC 0x04
+#define SCL (1 << 0)
+#define SDA (1 << 1)
+
+struct i2c_versatile {
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data algo;
+ void __iomem *base;
+};
+
+static void i2c_versatile_setsda(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static void i2c_versatile_setscl(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static int i2c_versatile_getsda(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SDA);
+}
+
+static int i2c_versatile_getscl(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SCL);
+}
+
+static struct i2c_algo_bit_data i2c_versatile_algo = {
+ .setsda = i2c_versatile_setsda,
+ .setscl = i2c_versatile_setscl,
+ .getsda = i2c_versatile_getsda,
+ .getscl = i2c_versatile_getscl,
+ .udelay = 30,
+ .timeout = HZ,
+};
+
+static int i2c_versatile_probe(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c;
+ struct resource *r;
+ int ret;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) {
+ ret = -EBUSY;
+ goto err_out;
+ }
+
+ i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ i2c->base = ioremap(r->start, resource_size(r));
+ if (!i2c->base) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ writel(SCL | SDA, i2c->base + I2C_CONTROLS);
+
+ i2c->adap.owner = THIS_MODULE;
+ strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
+ i2c->adap.algo_data = &i2c->algo;
+ i2c->adap.dev.parent = &dev->dev;
+ i2c->algo = i2c_versatile_algo;
+ i2c->algo.data = i2c;
+
+ if (dev->id >= 0) {
+ /* static bus numbering */
+ i2c->adap.nr = dev->id;
+ ret = i2c_bit_add_numbered_bus(&i2c->adap);
+ } else
+ /* dynamic bus numbering */
+ ret = i2c_bit_add_bus(&i2c->adap);
+ if (ret >= 0) {
+ platform_set_drvdata(dev, i2c);
+ return 0;
+ }
+
+ iounmap(i2c->base);
+ err_free:
+ kfree(i2c);
+ err_release:
+ release_mem_region(r->start, resource_size(r));
+ err_out:
+ return ret;
+}
+
+static int i2c_versatile_remove(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+}
+
+static struct platform_driver i2c_versatile_driver = {
+ .probe = i2c_versatile_probe,
+ .remove = i2c_versatile_remove,
+ .driver = {
+ .name = "versatile-i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_versatile_init(void)
+{
+ return platform_driver_register(&i2c_versatile_driver);
+}
+
+static void __exit i2c_versatile_exit(void)
+{
+ platform_driver_unregister(&i2c_versatile_driver);
+}
+
+subsys_initcall(i2c_versatile_init);
+module_exit(i2c_versatile_exit);
+
+MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:versatile-i2c");
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
new file mode 100644
index 00000000..7799fe5b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-via.c
@@ -0,0 +1,180 @@
+/*
+ i2c Support for Via Technologies 82C586B South Bridge
+
+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ 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/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+/* Power management registers */
+#define PM_CFG_REVID 0x08 /* silicon revision code */
+#define PM_CFG_IOBASE0 0x20
+#define PM_CFG_IOBASE1 0x48
+
+#define I2C_DIR (pm_io_base+0x40)
+#define I2C_OUT (pm_io_base+0x42)
+#define I2C_IN (pm_io_base+0x44)
+#define I2C_SCL 0x02 /* clock bit in DIR/OUT/IN register */
+#define I2C_SDA 0x04
+
+/* io-region reservation */
+#define IOSPACE 0x06
+
+static struct pci_driver vt586b_driver;
+static u16 pm_io_base;
+
+/*
+ It does not appear from the datasheet that the GPIO pins are
+ open drain. So a we set a low value by setting the direction to
+ output and a high value by setting the direction to input and
+ relying on the required I2C pullup. The data value is initialized
+ to 0 in via_init() and never changed.
+*/
+static void bit_via_setscl(void *data, int state)
+{
+ outb(state ? inb(I2C_DIR) & ~I2C_SCL : inb(I2C_DIR) | I2C_SCL, I2C_DIR);
+}
+
+static void bit_via_setsda(void *data, int state)
+{
+ outb(state ? inb(I2C_DIR) & ~I2C_SDA : inb(I2C_DIR) | I2C_SDA, I2C_DIR);
+}
+
+static int bit_via_getscl(void *data)
+{
+ return (0 != (inb(I2C_IN) & I2C_SCL));
+}
+
+static int bit_via_getsda(void *data)
+{
+ return (0 != (inb(I2C_IN) & I2C_SDA));
+}
+
+
+static struct i2c_algo_bit_data bit_data = {
+ .setsda = bit_via_setsda,
+ .setscl = bit_via_setscl,
+ .getsda = bit_via_getsda,
+ .getscl = bit_via_getscl,
+ .udelay = 5,
+ .timeout = HZ
+};
+
+static struct i2c_adapter vt586b_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .name = "VIA i2c",
+ .algo_data = &bit_data,
+};
+
+
+static const struct pci_device_id vt586b_ids[] __devinitconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, vt586b_ids);
+
+static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u16 base;
+ u8 rev;
+ int res;
+
+ if (pm_io_base) {
+ dev_err(&dev->dev, "i2c-via: Will only support one host\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(dev, PM_CFG_REVID, &rev);
+
+ switch (rev) {
+ case 0x00:
+ base = PM_CFG_IOBASE0;
+ break;
+ case 0x01:
+ case 0x10:
+ base = PM_CFG_IOBASE1;
+ break;
+
+ default:
+ base = PM_CFG_IOBASE1;
+ /* later revision */
+ }
+
+ pci_read_config_word(dev, base, &pm_io_base);
+ pm_io_base &= (0xff << 8);
+
+ if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) {
+ dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE);
+ return -ENODEV;
+ }
+
+ outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR);
+ outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT);
+
+ /* set up the sysfs linkage to our parent device */
+ vt586b_adapter.dev.parent = &dev->dev;
+
+ res = i2c_bit_add_bus(&vt586b_adapter);
+ if ( res < 0 ) {
+ release_region(I2C_DIR, IOSPACE);
+ pm_io_base = 0;
+ return res;
+ }
+ return 0;
+}
+
+static void __devexit vt586b_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&vt586b_adapter);
+ release_region(I2C_DIR, IOSPACE);
+ pm_io_base = 0;
+}
+
+
+static struct pci_driver vt586b_driver = {
+ .name = "vt586b_smbus",
+ .id_table = vt586b_ids,
+ .probe = vt586b_probe,
+ .remove = __devexit_p(vt586b_remove),
+};
+
+static int __init i2c_vt586b_init(void)
+{
+ return pci_register_driver(&vt586b_driver);
+}
+
+static void __exit i2c_vt586b_exit(void)
+{
+ pci_unregister_driver(&vt586b_driver);
+}
+
+
+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
+MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_vt586b_init);
+module_exit(i2c_vt586b_exit);
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
new file mode 100644
index 00000000..58261d47
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -0,0 +1,508 @@
+/*
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+ Copyright (C) 2005 - 2008 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.
+*/
+
+/*
+ Supports the following VIA south bridges:
+
+ Chip name PCI ID REV I2C block
+ VT82C596A 0x3050 no
+ VT82C596B 0x3051 no
+ VT82C686A 0x3057 0x30 no
+ VT82C686B 0x3057 0x40 yes
+ VT8231 0x8235 no?
+ VT8233 0x3074 yes
+ VT8233A 0x3147 yes?
+ VT8235 0x3177 yes
+ VT8237R 0x3227 yes
+ VT8237A 0x3337 yes
+ VT8237S 0x3372 yes
+ VT8251 0x3287 yes
+ CX700 0x8324 yes
+ VX800/VX820 0x8353 yes
+ VX855/VX875 0x8409 yes
+
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static struct pci_dev *vt596_pdev;
+
+#define SMBBA1 0x90
+#define SMBBA2 0x80
+#define SMBBA3 0xD0
+
+/* SMBus address offsets */
+static unsigned short vt596_smba;
+#define SMBHSTSTS (vt596_smba + 0)
+#define SMBHSTCNT (vt596_smba + 2)
+#define SMBHSTCMD (vt596_smba + 3)
+#define SMBHSTADD (vt596_smba + 4)
+#define SMBHSTDAT0 (vt596_smba + 5)
+#define SMBHSTDAT1 (vt596_smba + 6)
+#define SMBBLKDAT (vt596_smba + 7)
+
+/* PCI Address Constants */
+
+/* SMBus data in configuration space can be found in two places,
+ We try to select the better one */
+
+static unsigned short SMBHSTCFG = 0xD2;
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* VT82C596 constants */
+#define VT596_QUICK 0x00
+#define VT596_BYTE 0x04
+#define VT596_BYTE_DATA 0x08
+#define VT596_WORD_DATA 0x0C
+#define VT596_PROC_CALL 0x10
+#define VT596_BLOCK_DATA 0x14
+#define VT596_I2C_BLOCK_DATA 0x34
+
+
+/* If force is set to anything different from 0, we forcibly enable the
+ VT596. DANGEROUS! */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the VT596 at the given address. VERY DANGEROUS! */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+ "Forcibly enable the SMBus at the given address. "
+ "EXTREMELY DANGEROUS!");
+
+
+static struct pci_driver vt596_driver;
+static struct i2c_adapter vt596_adapter;
+
+#define FEATURE_I2CBLOCK (1<<0)
+static unsigned int vt596_features;
+
+#ifdef DEBUG
+static void vt596_dump_regs(const char *msg, u8 size)
+{
+ dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
+ "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
+
+ if (size == VT596_BLOCK_DATA
+ || size == VT596_I2C_BLOCK_DATA) {
+ int i;
+
+ dev_dbg(&vt596_adapter.dev, "BLK=");
+ for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++)
+ printk("%02x,", inb_p(SMBBLKDAT));
+ printk("\n");
+ dev_dbg(&vt596_adapter.dev, " ");
+ for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++)
+ printk("%02x,", inb_p(SMBBLKDAT));
+ printk("%02x\n", inb_p(SMBBLKDAT));
+ }
+}
+#else
+static inline void vt596_dump_regs(const char *msg, u8 size) { }
+#endif
+
+/* Return -1 on error, 0 on success */
+static int vt596_transaction(u8 size)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ vt596_dump_regs("Transaction (pre)", size);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+ dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
+ "Resetting...\n", temp);
+
+ outb_p(temp, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+ dev_err(&vt596_adapter.dev, "SMBus reset failed! "
+ "(0x%02x)\n", temp);
+ return -EBUSY;
+ }
+ }
+
+ /* Start the transaction by setting bit 6 */
+ outb_p(0x40 | size, SMBHSTCNT);
+
+ /* We will always wait for a fraction of a second */
+ do {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ } while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout == MAX_TIMEOUT) {
+ result = -ETIMEDOUT;
+ dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
+ }
+
+ if (temp & 0x10) {
+ result = -EIO;
+ dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
+ size);
+ }
+
+ if (temp & 0x08) {
+ result = -EIO;
+ dev_err(&vt596_adapter.dev, "SMBus collision!\n");
+ }
+
+ if (temp & 0x04) {
+ result = -ENXIO;
+ dev_dbg(&vt596_adapter.dev, "No response\n");
+ }
+
+ /* Resetting status register */
+ if (temp & 0x1F)
+ outb_p(temp, SMBHSTSTS);
+
+ vt596_dump_regs("Transaction (post)", size);
+
+ return result;
+}
+
+/* Return negative errno on error, 0 on success */
+static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int i;
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ size = VT596_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ size = VT596_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ size = VT596_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = VT596_WORD_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ outb_p(command, SMBHSTCMD);
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ size = VT596_PROC_CALL;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (!(vt596_features & FEATURE_I2CBLOCK))
+ goto exit_unsupported;
+ if (read_write == I2C_SMBUS_READ)
+ outb_p(data->block[0], SMBHSTDAT0);
+ /* Fall through */
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ u8 len = data->block[0];
+ if (len > I2C_SMBUS_BLOCK_MAX)
+ len = I2C_SMBUS_BLOCK_MAX;
+ outb_p(len, SMBHSTDAT0);
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ?
+ VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA;
+ break;
+ default:
+ goto exit_unsupported;
+ }
+
+ outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
+
+ status = vt596_transaction(size);
+ if (status)
+ return status;
+
+ if (size == VT596_PROC_CALL)
+ read_write = I2C_SMBUS_READ;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
+ return 0;
+
+ switch (size) {
+ case VT596_BYTE:
+ case VT596_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case VT596_WORD_DATA:
+ case VT596_PROC_CALL:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case VT596_I2C_BLOCK_DATA:
+ case VT596_BLOCK_DATA:
+ data->block[0] = inb_p(SMBHSTDAT0);
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb_p(SMBBLKDAT);
+ break;
+ }
+ return 0;
+
+exit_unsupported:
+ dev_warn(&vt596_adapter.dev, "Unsupported transaction %d\n",
+ size);
+ return -EOPNOTSUPP;
+}
+
+static u32 vt596_func(struct i2c_adapter *adapter)
+{
+ u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
+
+ if (vt596_features & FEATURE_I2CBLOCK)
+ func |= I2C_FUNC_SMBUS_I2C_BLOCK;
+ return func;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = vt596_access,
+ .functionality = vt596_func,
+};
+
+static struct i2c_adapter vt596_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static int __devinit vt596_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned char temp;
+ int error;
+
+ /* Determine the address of the SMBus areas */
+ if (force_addr) {
+ vt596_smba = force_addr & 0xfff0;
+ force = 0;
+ goto found;
+ }
+
+ if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
+ !(vt596_smba & 0x0001)) {
+ /* try 2nd address and config reg. for 596 */
+ if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
+ !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
+ (vt596_smba & 0x0001)) {
+ SMBHSTCFG = 0x84;
+ } else {
+ /* no matches at all */
+ dev_err(&pdev->dev, "Cannot configure "
+ "SMBus I/O Base address\n");
+ return -ENODEV;
+ }
+ }
+
+ vt596_smba &= 0xfff0;
+ if (vt596_smba == 0) {
+ dev_err(&pdev->dev, "SMBus base address "
+ "uninitialized - upgrade BIOS or use "
+ "force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+
+found:
+ error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
+ if (error)
+ return -ENODEV;
+
+ if (!request_region(vt596_smba, 8, vt596_driver.name)) {
+ dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
+ vt596_smba);
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(pdev, SMBHSTCFG, &temp);
+ /* If force_addr is set, we program the new address here. Just to make
+ sure, we disable the VT596 first. */
+ if (force_addr) {
+ pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
+ pci_write_config_word(pdev, id->driver_data, vt596_smba);
+ pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
+ dev_warn(&pdev->dev, "WARNING: SMBus interface set to new "
+ "address 0x%04x!\n", vt596_smba);
+ } else if (!(temp & 0x01)) {
+ if (force) {
+ /* NOTE: This assumes I/O space and other allocations
+ * WERE done by the Bios! Don't complain if your
+ * hardware does weird things after enabling this.
+ * :') Check for Bios updates before resorting to
+ * this.
+ */
+ pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
+ dev_info(&pdev->dev, "Enabling SMBus device\n");
+ } else {
+ dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
+ "controller not enabled! - upgrade BIOS or "
+ "use force=1\n");
+ error = -ENODEV;
+ goto release_region;
+ }
+ }
+
+ dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_VIA_CX700:
+ case PCI_DEVICE_ID_VIA_VX800:
+ case PCI_DEVICE_ID_VIA_VX855:
+ case PCI_DEVICE_ID_VIA_8251:
+ case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
+ case PCI_DEVICE_ID_VIA_8237S:
+ case PCI_DEVICE_ID_VIA_8235:
+ case PCI_DEVICE_ID_VIA_8233A:
+ case PCI_DEVICE_ID_VIA_8233_0:
+ vt596_features |= FEATURE_I2CBLOCK;
+ break;
+ case PCI_DEVICE_ID_VIA_82C686_4:
+ /* The VT82C686B (rev 0x40) does support I2C block
+ transactions, but the VT82C686A (rev 0x30) doesn't */
+ if (pdev->revision >= 0x40)
+ vt596_features |= FEATURE_I2CBLOCK;
+ break;
+ }
+
+ vt596_adapter.dev.parent = &pdev->dev;
+ snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
+ "SMBus Via Pro adapter at %04x", vt596_smba);
+
+ vt596_pdev = pci_dev_get(pdev);
+ error = i2c_add_adapter(&vt596_adapter);
+ if (error) {
+ pci_dev_put(vt596_pdev);
+ vt596_pdev = NULL;
+ goto release_region;
+ }
+
+ /* Always return failure here. This is to allow other drivers to bind
+ * to this pci device. We don't really want to have control over the
+ * pci device, we only wanted to read as few register values from it.
+ */
+ return -ENODEV;
+
+release_region:
+ release_region(vt596_smba, 8);
+ return error;
+}
+
+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),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
+ .driver_data = SMBBA3 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, vt596_ids);
+
+static struct pci_driver vt596_driver = {
+ .name = "vt596_smbus",
+ .id_table = vt596_ids,
+ .probe = vt596_probe,
+};
+
+static int __init i2c_vt596_init(void)
+{
+ return pci_register_driver(&vt596_driver);
+}
+
+
+static void __exit i2c_vt596_exit(void)
+{
+ pci_unregister_driver(&vt596_driver);
+ if (vt596_pdev != NULL) {
+ i2c_del_adapter(&vt596_adapter);
+ release_region(vt596_smba, 8);
+ pci_dev_put(vt596_pdev);
+ vt596_pdev = NULL;
+ }
+}
+
+MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
+ "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
+ "Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("vt82c596 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_vt596_init);
+module_exit(i2c_vt596_exit);
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
new file mode 100644
index 00000000..4bb68f35
--- /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 committed 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
new file mode 100644
index 00000000..986e5f62
--- /dev/null
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -0,0 +1,618 @@
+/*
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 ACCESS.bus support
+ Also supports the AMD CS5535 and AMD CS5536
+
+ Based on i2c-keywest.c which is:
+ Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x820, 0x840 };
+module_param_array(base, int, NULL, 0);
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define POLL_TIMEOUT (HZ/5)
+
+enum scx200_acb_state {
+ state_idle,
+ state_address,
+ state_command,
+ state_repeat_start,
+ state_quick,
+ state_read,
+ state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+ "idle",
+ "address",
+ "command",
+ "repeat_start",
+ "quick",
+ "read",
+ "write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface {
+ struct scx200_acb_iface *next;
+ struct i2c_adapter adapter;
+ unsigned base;
+ struct mutex mutex;
+
+ /* State machine data */
+ enum scx200_acb_state state;
+ int result;
+ u8 address_byte;
+ u8 command;
+ u8 *ptr;
+ char needs_reset;
+ unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA (iface->base + 0)
+#define ACBST (iface->base + 1)
+#define ACBST_SDAST 0x40 /* SDA Status */
+#define ACBST_BER 0x20
+#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
+#define ACBST_STASTR 0x08 /* Stall After Start */
+#define ACBST_MASTER 0x02
+#define ACBCST (iface->base + 2)
+#define ACBCST_BB 0x02
+#define ACBCTL1 (iface->base + 3)
+#define ACBCTL1_STASTRE 0x80
+#define ACBCTL1_NMINTE 0x40
+#define ACBCTL1_ACK 0x10
+#define ACBCTL1_STOP 0x02
+#define ACBCTL1_START 0x01
+#define ACBADDR (iface->base + 4)
+#define ACBCTL2 (iface->base + 5)
+#define ACBCTL2_ENABLE 0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+ const char *errmsg;
+
+ dev_dbg(&iface->adapter.dev, "state %s, status = 0x%02x\n",
+ scx200_acb_state_name[iface->state], status);
+
+ if (status & ACBST_BER) {
+ errmsg = "bus error";
+ goto error;
+ }
+ if (!(status & ACBST_MASTER)) {
+ errmsg = "not master";
+ goto error;
+ }
+ if (status & ACBST_NEGACK) {
+ dev_dbg(&iface->adapter.dev, "negative ack in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -ENXIO;
+
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+
+ /* Reset the status register */
+ outb(0, ACBST);
+ return;
+ }
+
+ switch (iface->state) {
+ case state_idle:
+ dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
+ break;
+
+ case state_address:
+ /* Do a pointer write first */
+ outb(iface->address_byte & ~1, ACBSDA);
+
+ iface->state = state_command;
+ break;
+
+ case state_command:
+ outb(iface->command, ACBSDA);
+
+ if (iface->address_byte & 1)
+ iface->state = state_repeat_start;
+ else
+ iface->state = state_write;
+ break;
+
+ case state_repeat_start:
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+ /* fallthrough */
+
+ case state_quick:
+ if (iface->address_byte & 1) {
+ if (iface->len == 1)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_read;
+ } else {
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_write;
+ }
+ break;
+
+ case state_read:
+ /* Set ACK if _next_ byte will be the last one */
+ if (iface->len == 2)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+ if (iface->len == 1) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ }
+
+ *iface->ptr++ = inb(ACBSDA);
+ --iface->len;
+
+ break;
+
+ case state_write:
+ if (iface->len == 0) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ break;
+ }
+
+ outb(*iface->ptr++, ACBSDA);
+ --iface->len;
+
+ break;
+ }
+
+ return;
+
+ error:
+ dev_err(&iface->adapter.dev,
+ "%s in state %s (addr=0x%02x, len=%d, status=0x%02x)\n", errmsg,
+ scx200_acb_state_name[iface->state], iface->address_byte,
+ iface->len, status);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+ u8 status;
+ unsigned long timeout;
+
+ timeout = jiffies + POLL_TIMEOUT;
+ while (1) {
+ status = inb(ACBST);
+
+ /* Reset the status register to avoid the hang */
+ outb(0, ACBST);
+
+ if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+ scx200_acb_machine(iface, status);
+ return;
+ }
+ if (time_after(jiffies, timeout))
+ break;
+ cpu_relax();
+ cond_resched();
+ }
+
+ dev_err(&iface->adapter.dev, "timeout in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+ /* Polling mode */
+ outb(0, ACBCTL1);
+ /* Disable slave address */
+ outb(0, ACBADDR);
+ /* Enable the ACCESS.bus device */
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+ /* Free STALL after START */
+ outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+ /* Send a STOP */
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ /* Clear BER, NEGACK and STASTR bits */
+ outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+ /* Clear BB bit */
+ outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+ u16 address, unsigned short flags,
+ char rw, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
+ int len;
+ u8 *buffer;
+ u16 cur_word;
+ int rc;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ len = 0;
+ buffer = NULL;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ len = 1;
+ buffer = rw ? &data->byte : &command;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ len = 1;
+ buffer = &data->byte;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ len = 2;
+ cur_word = cpu_to_le16(data->word);
+ buffer = (u8 *)&cur_word;
+ break;
+
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ buffer = &data->block[1];
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(&adapter->dev,
+ "size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+ size, address, command, len, rw);
+
+ if (!len && rw == I2C_SMBUS_READ) {
+ dev_dbg(&adapter->dev, "zero length read\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&iface->mutex);
+
+ iface->address_byte = (address << 1) | rw;
+ iface->command = command;
+ iface->ptr = buffer;
+ iface->len = len;
+ iface->result = -EINVAL;
+ iface->needs_reset = 0;
+
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+ iface->state = state_quick;
+ else
+ iface->state = state_address;
+
+ while (iface->state != state_idle)
+ scx200_acb_poll(iface);
+
+ if (iface->needs_reset)
+ scx200_acb_reset(iface);
+
+ rc = iface->result;
+
+ mutex_unlock(&iface->mutex);
+
+ if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+ data->word = le16_to_cpu(cur_word);
+
+#ifdef DEBUG
+ dev_dbg(&adapter->dev, "transfer done, result: %d", rc);
+ if (buffer) {
+ int i;
+ printk(" data:");
+ for (i = 0; i < len; ++i)
+ printk(" %02x", buffer[i]);
+ }
+ printk("\n");
+#endif
+
+ return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static const struct i2c_algorithm scx200_acb_algorithm = {
+ .smbus_xfer = scx200_acb_smbus_xfer,
+ .functionality = scx200_acb_func,
+};
+
+static struct scx200_acb_iface *scx200_acb_list;
+static DEFINE_MUTEX(scx200_acb_list_mutex);
+
+static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+ u8 val;
+
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+
+ if (inb(ACBCTL2) != 0x70) {
+ pr_debug(NAME ": ACBCTL2 readback failed\n");
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if (val) {
+ pr_debug(NAME ": disabled, but ACBCTL1=0x%02x\n",
+ val);
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+ pr_debug(NAME ": enabled, but NMINTE won't be set, "
+ "ACBCTL1=0x%02x\n", val);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
+ struct device *dev, int index)
+{
+ struct scx200_acb_iface *iface;
+ struct i2c_adapter *adapter;
+
+ iface = kzalloc(sizeof(*iface), GFP_KERNEL);
+ if (!iface) {
+ printk(KERN_ERR NAME ": can't allocate memory\n");
+ return NULL;
+ }
+
+ adapter = &iface->adapter;
+ i2c_set_adapdata(adapter, iface);
+ snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
+ adapter->owner = THIS_MODULE;
+ adapter->algo = &scx200_acb_algorithm;
+ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adapter->dev.parent = dev;
+
+ mutex_init(&iface->mutex);
+
+ return iface;
+}
+
+static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
+{
+ struct i2c_adapter *adapter;
+ int rc;
+
+ adapter = &iface->adapter;
+
+ rc = scx200_acb_probe(iface);
+ if (rc) {
+ printk(KERN_WARNING NAME ": probe failed\n");
+ return rc;
+ }
+
+ scx200_acb_reset(iface);
+
+ if (i2c_add_adapter(adapter) < 0) {
+ printk(KERN_ERR NAME ": failed to register\n");
+ return -ENODEV;
+ }
+
+ if (!adapter->dev.parent) {
+ /* If there's no dev, we're tracking (ISA) ifaces manually */
+ mutex_lock(&scx200_acb_list_mutex);
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ mutex_unlock(&scx200_acb_list_mutex);
+ }
+
+ return 0;
+}
+
+static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+ unsigned long base, int index, struct device *dev)
+{
+ struct scx200_acb_iface *iface;
+ int rc;
+
+ iface = scx200_create_iface(text, dev, index);
+
+ if (iface == NULL)
+ return NULL;
+
+ if (!request_region(base, 8, iface->adapter.name)) {
+ printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+ base, base + 8 - 1);
+ goto errout_free;
+ }
+
+ iface->base = base;
+ rc = scx200_acb_create(iface);
+
+ if (rc == 0)
+ return iface;
+
+ release_region(base, 8);
+ errout_free:
+ kfree(iface);
+ return NULL;
+}
+
+static int __devinit scx200_probe(struct platform_device *pdev)
+{
+ struct scx200_acb_iface *iface;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -ENODEV;
+ }
+
+ iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+ if (!iface)
+ return -EIO;
+
+ dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+ iface->adapter.name);
+ platform_set_drvdata(pdev, iface);
+
+ return 0;
+}
+
+static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+}
+
+static int __devexit scx200_remove(struct platform_device *pdev)
+{
+ struct scx200_acb_iface *iface;
+
+ iface = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+ scx200_cleanup_iface(iface);
+
+ return 0;
+}
+
+static struct platform_driver scx200_pci_drv = {
+ .driver = {
+ .name = "cs5535-smb",
+ .owner = THIS_MODULE,
+ },
+ .probe = scx200_probe,
+ .remove = __devexit_p(scx200_remove),
+};
+
+static const struct pci_device_id scx200_isa[] __initconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+ { 0, }
+};
+
+static __init void scx200_scan_isa(void)
+{
+ int i;
+
+ if (!pci_dev_present(scx200_isa))
+ return;
+
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] == 0)
+ continue;
+
+ /* XXX: should we care about failures? */
+ scx200_create_dev("SCx200", base[i], i, NULL);
+ }
+}
+
+static int __init scx200_acb_init(void)
+{
+ pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+ /* First scan for ISA-based devices */
+ scx200_scan_isa(); /* XXX: should we care about errors? */
+
+ /* If at least one bus was created, init must succeed */
+ if (scx200_acb_list)
+ return 0;
+
+ /* No ISA devices; register the platform driver for PCI-based devices */
+ return platform_driver_register(&scx200_pci_drv);
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+ struct scx200_acb_iface *iface;
+
+ platform_driver_unregister(&scx200_pci_drv);
+
+ mutex_lock(&scx200_acb_list_mutex);
+ while ((iface = scx200_acb_list) != NULL) {
+ scx200_acb_list = iface->next;
+ mutex_unlock(&scx200_acb_list_mutex);
+
+ scx200_cleanup_iface(iface);
+
+ mutex_lock(&scx200_acb_list_mutex);
+ }
+ mutex_unlock(&scx200_acb_list_mutex);
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
new file mode 100644
index 00000000..7ee0d502
--- /dev/null
+++ b/drivers/i2c/busses/scx200_i2c.c
@@ -0,0 +1,131 @@
+/* linux/drivers/i2c/busses/scx200_i2c.c
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 I2C bus on GPIO pins
+
+ Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+module_param(scl, int, 0);
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+module_param(sda, int, 0);
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+ scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+ scx200_gpio_set(sda, state);
+}
+
+static int scx200_i2c_getscl(void *data)
+{
+ return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+ return scx200_gpio_get(sda);
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+ .setsda = scx200_i2c_setsda,
+ .setscl = scx200_i2c_setscl,
+ .getsda = scx200_i2c_getsda,
+ .getscl = scx200_i2c_getscl,
+ .udelay = 10,
+ .timeout = HZ,
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo_data = &scx200_i2c_data,
+ .name = "NatSemi SCx200 I2C",
+};
+
+static int scx200_i2c_init(void)
+{
+ pr_debug(NAME ": NatSemi SCx200 I2C Driver\n");
+
+ if (!scx200_gpio_present()) {
+ printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+ return -ENODEV;
+ }
+
+ pr_debug(NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", scl, sda);
+
+ if (scl == -1 || sda == -1 || scl == sda) {
+ printk(KERN_ERR NAME ": scl and sda must be specified\n");
+ return -EINVAL;
+ }
+
+ /* Configure GPIOs as open collector outputs */
+ scx200_gpio_configure(scl, ~2, 5);
+ scx200_gpio_configure(sda, ~2, 5);
+
+ if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+ printk(KERN_ERR NAME ": adapter %s registration failed\n",
+ scx200_i2c_ops.name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void scx200_i2c_cleanup(void)
+{
+ i2c_del_adapter(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+ Local variables:
+ compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+ c-basic-offset: 8
+ End:
+*/
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
new file mode 100644
index 00000000..3ca2e012
--- /dev/null
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -0,0 +1,92 @@
+/*
+ * i2c-boardinfo.c - collect pre-declarations of I2C devices
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/rwsem.h>
+
+#include "i2c-core.h"
+
+
+/* These symbols are exported ONLY FOR the i2c core.
+ * No other users will be supported.
+ */
+DECLARE_RWSEM(__i2c_board_lock);
+EXPORT_SYMBOL_GPL(__i2c_board_lock);
+
+LIST_HEAD(__i2c_board_list);
+EXPORT_SYMBOL_GPL(__i2c_board_list);
+
+int __i2c_first_dynamic_bus_num;
+EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
+
+
+/**
+ * i2c_register_board_info - statically declare I2C devices
+ * @busnum: identifies the bus to which these devices belong
+ * @info: vector of i2c device descriptors
+ * @len: how many descriptors in the vector; may be zero to reserve
+ * the specified bus number.
+ *
+ * Systems using the Linux I2C driver stack can declare tables of board info
+ * while they initialize. This should be done in board-specific init code
+ * near arch_initcall() time, or equivalent, before any I2C adapter driver is
+ * registered. For example, mainboard init code could define several devices,
+ * as could the init code for each daughtercard in a board stack.
+ *
+ * The I2C devices will be created later, after the adapter for the relevant
+ * bus has been registered. After that moment, standard driver model tools
+ * are used to bind "new style" I2C drivers to the devices. The bus number
+ * for any device declared using this routine is not available for dynamic
+ * allocation.
+ *
+ * The board info passed can safely be __initdata, but be careful of embedded
+ * pointers (for platform_data, functions, etc) since that won't be copied.
+ */
+int __init
+i2c_register_board_info(int busnum,
+ struct i2c_board_info const *info, unsigned len)
+{
+ int status;
+
+ down_write(&__i2c_board_lock);
+
+ /* dynamic bus numbers will be assigned after the last static one */
+ if (busnum >= __i2c_first_dynamic_bus_num)
+ __i2c_first_dynamic_bus_num = busnum + 1;
+
+ for (status = 0; len; len--, info++) {
+ struct i2c_devinfo *devinfo;
+
+ devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
+ if (!devinfo) {
+ pr_debug("i2c-core: can't register boardinfo!\n");
+ status = -ENOMEM;
+ break;
+ }
+
+ devinfo->busnum = busnum;
+ devinfo->board_info = *info;
+ list_add_tail(&devinfo->list, &__i2c_board_list);
+ }
+
+ up_write(&__i2c_board_lock);
+
+ return status;
+}
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
new file mode 100644
index 00000000..9a58994f
--- /dev/null
+++ b/drivers/i2c/i2c-core.c
@@ -0,0 +1,2124 @@
+/* i2c-core.c - a device driver for the iic-bus interface */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 Simon G. Vogl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
+ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
+ SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
+ Jean Delvare <khali@linux-fr.org>
+ Mux support by Rodolfo Giometti <giometti@enneenne.com> and
+ Michael Lawnick <michael.lawnick.ext@nsn.com> */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/completion.h>
+#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"
+
+
+/* core_lock protects i2c_adapter_idr, and guarantees
+ that device detection, deletion of detected devices, and attach_adapter
+ and detach_adapter calls are serialized */
+static DEFINE_MUTEX(core_lock);
+static DEFINE_IDR(i2c_adapter_idr);
+
+static struct device_type i2c_client_type;
+static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
+
+/* ------------------------------------------------------------------------- */
+
+static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+ const struct i2c_client *client)
+{
+ while (id->name[0]) {
+ if (strcmp(client->name, id->name) == 0)
+ return id;
+ id++;
+ }
+ return NULL;
+}
+
+static int i2c_device_match(struct device *dev, struct device_driver *drv)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_driver *driver;
+
+ if (!client)
+ return 0;
+
+ /* Attempt an OF style match */
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
+ driver = to_i2c_driver(drv);
+ /* match on an id table if there is one */
+ if (driver->id_table)
+ return i2c_match_id(driver->id_table, client) != NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+
+/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (add_uevent_var(env, "MODALIAS=%s%s",
+ I2C_MODULE_PREFIX, client->name))
+ return -ENOMEM;
+ dev_dbg(dev, "uevent\n");
+ return 0;
+}
+
+#else
+#define i2c_device_uevent NULL
+#endif /* CONFIG_HOTPLUG */
+
+static int i2c_device_probe(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_driver *driver;
+ int status;
+
+ if (!client)
+ return 0;
+
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->probe || !driver->id_table)
+ return -ENODEV;
+ client->driver = driver;
+ if (!device_can_wakeup(&client->dev))
+ device_init_wakeup(&client->dev,
+ client->flags & I2C_CLIENT_WAKE);
+ dev_dbg(dev, "probe\n");
+
+ status = driver->probe(client, i2c_match_id(driver->id_table, client));
+ if (status) {
+ client->driver = NULL;
+ i2c_set_clientdata(client, NULL);
+ }
+ return status;
+}
+
+static int i2c_device_remove(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_driver *driver;
+ int status;
+
+ if (!client || !dev->driver)
+ return 0;
+
+ driver = to_i2c_driver(dev->driver);
+ if (driver->remove) {
+ dev_dbg(dev, "remove\n");
+ status = driver->remove(client);
+ } else {
+ dev->driver = NULL;
+ status = 0;
+ }
+ if (status == 0) {
+ client->driver = NULL;
+ i2c_set_clientdata(client, NULL);
+ }
+ return status;
+}
+
+static void i2c_device_shutdown(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_driver *driver;
+
+ if (!client || !dev->driver)
+ return;
+ driver = to_i2c_driver(dev->driver);
+ if (driver->shutdown)
+ driver->shutdown(client);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_driver *driver;
+
+ if (!client || !dev->driver)
+ return 0;
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->suspend)
+ return 0;
+ return driver->suspend(client, mesg);
+}
+
+static int i2c_legacy_resume(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_driver *driver;
+
+ if (!client || !dev->driver)
+ return 0;
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->resume)
+ return 0;
+ return driver->resume(client);
+}
+
+static int i2c_device_pm_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_suspend(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_SUSPEND);
+}
+
+static int i2c_device_pm_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_resume(dev);
+ else
+ return i2c_legacy_resume(dev);
+}
+
+static int i2c_device_pm_freeze(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_freeze(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_FREEZE);
+}
+
+static int i2c_device_pm_thaw(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_thaw(dev);
+ else
+ return i2c_legacy_resume(dev);
+}
+
+static int i2c_device_pm_poweroff(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_poweroff(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int i2c_device_pm_restore(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_restore(dev);
+ else
+ return i2c_legacy_resume(dev);
+}
+#else /* !CONFIG_PM_SLEEP */
+#define i2c_device_pm_suspend NULL
+#define i2c_device_pm_resume NULL
+#define i2c_device_pm_freeze NULL
+#define i2c_device_pm_thaw NULL
+#define i2c_device_pm_poweroff NULL
+#define i2c_device_pm_restore NULL
+#endif /* !CONFIG_PM_SLEEP */
+
+static void i2c_client_dev_release(struct device *dev)
+{
+ kfree(to_i2c_client(dev));
+}
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
+ to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
+}
+
+static ssize_t
+show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+static struct attribute *i2c_dev_attrs[] = {
+ &dev_attr_name.attr,
+ /* modalias helps coldplug: modprobe $(cat .../modalias) */
+ &dev_attr_modalias.attr,
+ NULL
+};
+
+static struct attribute_group i2c_dev_attr_group = {
+ .attrs = i2c_dev_attrs,
+};
+
+static const struct attribute_group *i2c_dev_attr_groups[] = {
+ &i2c_dev_attr_group,
+ NULL
+};
+
+static const struct dev_pm_ops i2c_device_pm_ops = {
+ .suspend = i2c_device_pm_suspend,
+ .resume = i2c_device_pm_resume,
+ .freeze = i2c_device_pm_freeze,
+ .thaw = i2c_device_pm_thaw,
+ .poweroff = i2c_device_pm_poweroff,
+ .restore = i2c_device_pm_restore,
+ SET_RUNTIME_PM_OPS(
+ pm_generic_runtime_suspend,
+ pm_generic_runtime_resume,
+ pm_generic_runtime_idle
+ )
+};
+
+struct bus_type i2c_bus_type = {
+ .name = "i2c",
+ .match = i2c_device_match,
+ .probe = i2c_device_probe,
+ .remove = i2c_device_remove,
+ .shutdown = i2c_device_shutdown,
+ .pm = &i2c_device_pm_ops,
+};
+EXPORT_SYMBOL_GPL(i2c_bus_type);
+
+static struct device_type i2c_client_type = {
+ .groups = i2c_dev_attr_groups,
+ .uevent = i2c_device_uevent,
+ .release = i2c_client_dev_release,
+};
+
+
+/**
+ * i2c_verify_client - return parameter as i2c_client, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find. Use this function to avoid oopses caused
+ * by wrongly treating some non-I2C device as an i2c_client.
+ */
+struct i2c_client *i2c_verify_client(struct device *dev)
+{
+ return (dev->type == &i2c_client_type)
+ ? to_i2c_client(dev)
+ : NULL;
+}
+EXPORT_SYMBOL(i2c_verify_client);
+
+
+/* This is a permissive address validity check, I2C address map constraints
+ * are purposely not enforced, except for the general call address. */
+static int i2c_check_client_addr_validity(const struct i2c_client *client)
+{
+ if (client->flags & I2C_CLIENT_TEN) {
+ /* 10-bit address, all values are valid */
+ if (client->addr > 0x3ff)
+ return -EINVAL;
+ } else {
+ /* 7-bit address, reject the general call address */
+ if (client->addr == 0x00 || client->addr > 0x7f)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* And this is a strict address validity check, used when probing. If a
+ * device uses a reserved address, then it shouldn't be probed. 7-bit
+ * addressing is assumed, 10-bit address devices are rare and should be
+ * explicitly enumerated. */
+static int i2c_check_addr_validity(unsigned short addr)
+{
+ /*
+ * Reserved addresses per I2C specification:
+ * 0x00 General call address / START byte
+ * 0x01 CBUS address
+ * 0x02 Reserved for different bus format
+ * 0x03 Reserved for future purposes
+ * 0x04-0x07 Hs-mode master code
+ * 0x78-0x7b 10-bit slave addressing
+ * 0x7c-0x7f Reserved for future purposes
+ */
+ if (addr < 0x08 || addr > 0x77)
+ return -EINVAL;
+ return 0;
+}
+
+static int __i2c_check_addr_busy(struct device *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ int addr = *(int *)addrp;
+
+ if (client && client->addr == addr)
+ return -EBUSY;
+ return 0;
+}
+
+/* walk up mux tree */
+static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ int result;
+
+ result = device_for_each_child(&adapter->dev, &addr,
+ __i2c_check_addr_busy);
+
+ if (!result && parent)
+ result = i2c_check_mux_parents(parent, addr);
+
+ return result;
+}
+
+/* recurse down mux tree */
+static int i2c_check_mux_children(struct device *dev, void *addrp)
+{
+ int result;
+
+ if (dev->type == &i2c_adapter_type)
+ result = device_for_each_child(dev, addrp,
+ i2c_check_mux_children);
+ else
+ result = __i2c_check_addr_busy(dev, addrp);
+
+ return result;
+}
+
+static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ int result = 0;
+
+ if (parent)
+ result = i2c_check_mux_parents(parent, addr);
+
+ if (!result)
+ result = device_for_each_child(&adapter->dev, &addr,
+ i2c_check_mux_children);
+
+ return result;
+}
+
+/**
+ * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+void i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+ if (parent)
+ i2c_lock_adapter(parent);
+ else
+ rt_mutex_lock(&adapter->bus_lock);
+}
+EXPORT_SYMBOL_GPL(i2c_lock_adapter);
+
+/**
+ * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+ if (parent)
+ return i2c_trylock_adapter(parent);
+ else
+ return rt_mutex_trylock(&adapter->bus_lock);
+}
+
+/**
+ * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+void i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+ if (parent)
+ i2c_unlock_adapter(parent);
+ else
+ rt_mutex_unlock(&adapter->bus_lock);
+}
+EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
+
+/**
+ * i2c_new_device - instantiate an i2c device
+ * @adap: the adapter managing the device
+ * @info: describes one I2C device; bus_num is ignored
+ * Context: can sleep
+ *
+ * Create an i2c device. Binding is handled through driver model
+ * probe()/remove() methods. A driver may be bound to this device when we
+ * return from this function, or any later moment (e.g. maybe hotplugging will
+ * load the driver module). This call is not appropriate for use by mainboard
+ * initialization logic, which usually runs during an arch_initcall() long
+ * before any i2c_adapter could exist.
+ *
+ * This returns the new i2c client, which may be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
+{
+ struct i2c_client *client;
+ int status;
+
+ client = kzalloc(sizeof *client, GFP_KERNEL);
+ if (!client)
+ return NULL;
+
+ client->adapter = adap;
+
+ client->dev.platform_data = info->platform_data;
+
+ if (info->archdata)
+ client->dev.archdata = *info->archdata;
+
+ client->flags = info->flags;
+ client->addr = info->addr;
+ client->irq = info->irq;
+
+ strlcpy(client->name, info->type, sizeof(client->name));
+
+ /* Check for address validity */
+ status = i2c_check_client_addr_validity(client);
+ if (status) {
+ dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
+ client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
+ goto out_err_silent;
+ }
+
+ /* Check for address business */
+ status = i2c_check_addr_busy(adap, client->addr);
+ if (status)
+ goto out_err;
+
+ client->dev.parent = &client->adapter->dev;
+ client->dev.bus = &i2c_bus_type;
+ client->dev.type = &i2c_client_type;
+ client->dev.of_node = info->of_node;
+
+ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
+ client->addr);
+ status = device_register(&client->dev);
+ if (status)
+ goto out_err;
+
+ dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
+ client->name, dev_name(&client->dev));
+
+ return client;
+
+out_err:
+ dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
+ "(%d)\n", client->name, client->addr, status);
+out_err_silent:
+ kfree(client);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(i2c_new_device);
+
+
+/**
+ * i2c_unregister_device - reverse effect of i2c_new_device()
+ * @client: value returned from i2c_new_device()
+ * Context: can sleep
+ */
+void i2c_unregister_device(struct i2c_client *client)
+{
+ device_unregister(&client->dev);
+}
+EXPORT_SYMBOL_GPL(i2c_unregister_device);
+
+
+static const struct i2c_device_id dummy_id[] = {
+ { "dummy", 0 },
+ { },
+};
+
+static int dummy_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return 0;
+}
+
+static int dummy_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static struct i2c_driver dummy_driver = {
+ .driver.name = "dummy",
+ .probe = dummy_probe,
+ .remove = dummy_remove,
+ .id_table = dummy_id,
+};
+
+/**
+ * i2c_new_dummy - return a new i2c device bound to a dummy driver
+ * @adapter: the adapter managing the device
+ * @address: seven bit address to be used
+ * Context: can sleep
+ *
+ * This returns an I2C client bound to the "dummy" driver, intended for use
+ * with devices that consume multiple addresses. Examples of such chips
+ * include various EEPROMS (like 24c04 and 24c08 models).
+ *
+ * These dummy devices have two main uses. First, most I2C and SMBus calls
+ * except i2c_transfer() need a client handle; the dummy will be that handle.
+ * And second, this prevents the specified address from being bound to a
+ * different driver.
+ *
+ * This returns the new i2c client, which should be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
+{
+ struct i2c_board_info info = {
+ I2C_BOARD_INFO("dummy", address),
+ };
+
+ return i2c_new_device(adapter, &info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_dummy);
+
+/* ------------------------------------------------------------------------- */
+
+/* I2C bus adapters -- one roots each I2C or SMBUS segment */
+
+static void i2c_adapter_dev_release(struct device *dev)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
+ complete(&adap->dev_released);
+}
+
+/*
+ * Let users instantiate I2C devices through sysfs. This can be used when
+ * platform initialization code doesn't contain the proper data for
+ * whatever reason. Also useful for drivers that do device detection and
+ * detection fails, either because the device uses an unexpected address,
+ * or this is a compatible device with different ID register values.
+ *
+ * Parameter checking may look overzealous, but we really don't want
+ * the user to provide incorrect parameters.
+ */
+static ssize_t
+i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
+ struct i2c_board_info info;
+ struct i2c_client *client;
+ char *blank, end;
+ int res;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ blank = strchr(buf, ' ');
+ if (!blank) {
+ dev_err(dev, "%s: Missing parameters\n", "new_device");
+ return -EINVAL;
+ }
+ if (blank - buf > I2C_NAME_SIZE - 1) {
+ dev_err(dev, "%s: Invalid device name\n", "new_device");
+ return -EINVAL;
+ }
+ memcpy(info.type, buf, blank - buf);
+
+ /* Parse remaining parameters, reject extra parameters */
+ res = sscanf(++blank, "%hi%c", &info.addr, &end);
+ if (res < 1) {
+ dev_err(dev, "%s: Can't parse I2C address\n", "new_device");
+ return -EINVAL;
+ }
+ if (res > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "new_device");
+ return -EINVAL;
+ }
+
+ client = i2c_new_device(adap, &info);
+ if (!client)
+ return -EINVAL;
+
+ /* Keep track of the added device */
+ mutex_lock(&adap->userspace_clients_lock);
+ list_add_tail(&client->detected, &adap->userspace_clients);
+ mutex_unlock(&adap->userspace_clients_lock);
+ dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
+ info.type, info.addr);
+
+ return count;
+}
+
+/*
+ * And of course let the users delete the devices they instantiated, if
+ * they got it wrong. This interface can only be used to delete devices
+ * instantiated by i2c_sysfs_new_device above. This guarantees that we
+ * don't delete devices to which some kernel code still has references.
+ *
+ * Parameter checking may look overzealous, but we really don't want
+ * the user to delete the wrong device.
+ */
+static ssize_t
+i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
+ struct i2c_client *client, *next;
+ unsigned short addr;
+ char end;
+ int res;
+
+ /* Parse parameters, reject extra parameters */
+ res = sscanf(buf, "%hi%c", &addr, &end);
+ if (res < 1) {
+ dev_err(dev, "%s: Can't parse I2C address\n", "delete_device");
+ return -EINVAL;
+ }
+ if (res > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "delete_device");
+ return -EINVAL;
+ }
+
+ /* Make sure the device was added through sysfs */
+ res = -ENOENT;
+ mutex_lock(&adap->userspace_clients_lock);
+ list_for_each_entry_safe(client, next, &adap->userspace_clients,
+ detected) {
+ if (client->addr == addr) {
+ dev_info(dev, "%s: Deleting device %s at 0x%02hx\n",
+ "delete_device", client->name, client->addr);
+
+ list_del(&client->detected);
+ i2c_unregister_device(client);
+ res = count;
+ break;
+ }
+ }
+ mutex_unlock(&adap->userspace_clients_lock);
+
+ if (res < 0)
+ dev_err(dev, "%s: Can't find device in list\n",
+ "delete_device");
+ return res;
+}
+
+static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
+static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
+
+static struct attribute *i2c_adapter_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_new_device.attr,
+ &dev_attr_delete_device.attr,
+ NULL
+};
+
+static struct attribute_group i2c_adapter_attr_group = {
+ .attrs = i2c_adapter_attrs,
+};
+
+static const struct attribute_group *i2c_adapter_attr_groups[] = {
+ &i2c_adapter_attr_group,
+ NULL
+};
+
+struct device_type i2c_adapter_type = {
+ .groups = i2c_adapter_attr_groups,
+ .release = i2c_adapter_dev_release,
+};
+EXPORT_SYMBOL_GPL(i2c_adapter_type);
+
+#ifdef CONFIG_I2C_COMPAT
+static struct class_compat *i2c_adapter_compat_class;
+#endif
+
+static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
+{
+ struct i2c_devinfo *devinfo;
+
+ down_read(&__i2c_board_lock);
+ list_for_each_entry(devinfo, &__i2c_board_list, list) {
+ if (devinfo->busnum == adapter->nr
+ && !i2c_new_device(adapter,
+ &devinfo->board_info))
+ dev_err(&adapter->dev,
+ "Can't create device at 0x%02x\n",
+ devinfo->board_info.addr);
+ }
+ up_read(&__i2c_board_lock);
+}
+
+static int i2c_do_add_adapter(struct i2c_driver *driver,
+ struct i2c_adapter *adap)
+{
+ /* Detect supported devices on that bus, and instantiate them */
+ i2c_detect(adap, driver);
+
+ /* Let legacy drivers scan this bus for matching devices */
+ if (driver->attach_adapter) {
+ dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
+ driver->driver.name);
+ dev_warn(&adap->dev, "Please use another way to instantiate "
+ "your i2c_client\n");
+ /* We ignore the return code; if it fails, too bad */
+ driver->attach_adapter(adap);
+ }
+ 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;
+
+ /* Can't register until after driver model init */
+ if (unlikely(WARN_ON(!i2c_bus_type.p))) {
+ res = -EAGAIN;
+ goto out_list;
+ }
+
+ /* Sanity checks */
+ if (unlikely(adap->name[0] == '\0')) {
+ pr_err("i2c-core: Attempt to register an adapter with "
+ "no name!\n");
+ return -EINVAL;
+ }
+ if (unlikely(!adap->algo)) {
+ pr_err("i2c-core: Attempt to register adapter '%s' with "
+ "no algo!\n", adap->name);
+ return -EINVAL;
+ }
+
+ rt_mutex_init(&adap->bus_lock);
+ mutex_init(&adap->userspace_clients_lock);
+ INIT_LIST_HEAD(&adap->userspace_clients);
+
+ /* Set default timeout to 1 second if not already set */
+ if (adap->timeout == 0)
+ adap->timeout = HZ;
+
+ dev_set_name(&adap->dev, "i2c-%d", adap->nr);
+ adap->dev.bus = &i2c_bus_type;
+ adap->dev.type = &i2c_adapter_type;
+ res = device_register(&adap->dev);
+ if (res)
+ goto out_list;
+
+ dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
+#ifdef CONFIG_I2C_COMPAT
+ res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
+ adap->dev.parent);
+ if (res)
+ dev_warn(&adap->dev,
+ "Failed to create compatibility class link\n");
+#endif
+
+ /* create pre-declared device nodes */
+ if (adap->nr < __i2c_first_dynamic_bus_num)
+ i2c_scan_static_board_info(adap);
+
+ /* Notify drivers */
+ mutex_lock(&core_lock);
+ bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
+ mutex_unlock(&core_lock);
+
+ return 0;
+
+out_list:
+ mutex_lock(&core_lock);
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ mutex_unlock(&core_lock);
+ return res;
+}
+
+/**
+ * i2c_add_adapter - declare i2c adapter, use dynamic bus number
+ * @adapter: the adapter to add
+ * Context: can sleep
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * doesn't matter. Examples: for I2C adapters dynamically added by
+ * USB links or PCI plugin cards.
+ *
+ * When this returns zero, a new bus number was allocated and stored
+ * in adap->nr, and the specified adapter became available for clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int i2c_add_adapter(struct i2c_adapter *adapter)
+{
+ int id, res = 0;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ mutex_lock(&core_lock);
+ /* "above" here means "above or equal to", sigh */
+ res = idr_get_new_above(&i2c_adapter_idr, adapter,
+ __i2c_first_dynamic_bus_num, &id);
+ mutex_unlock(&core_lock);
+
+ if (res < 0) {
+ if (res == -EAGAIN)
+ goto retry;
+ return res;
+ }
+
+ adapter->nr = id;
+ return i2c_register_adapter(adapter);
+}
+EXPORT_SYMBOL(i2c_add_adapter);
+
+/**
+ * i2c_add_numbered_adapter - declare i2c adapter, use static bus number
+ * @adap: the adapter to register (with adap->nr initialized)
+ * Context: can sleep
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * matters. For example, use it for I2C adapters from system-on-chip CPUs,
+ * or otherwise built in to the system's mainboard, and where i2c_board_info
+ * is used to properly configure I2C devices.
+ *
+ * If no devices have pre-been declared for this bus, then be sure to
+ * register the adapter before any dynamically allocated ones. Otherwise
+ * the required bus ID may not be available.
+ *
+ * When this returns zero, the specified adapter became available for
+ * clients using the bus number provided in adap->nr. Also, the table
+ * of I2C devices pre-declared using i2c_register_board_info() is scanned,
+ * and the appropriate driver model device nodes are created. Otherwise, a
+ * negative errno value is returned.
+ */
+int i2c_add_numbered_adapter(struct i2c_adapter *adap)
+{
+ int id;
+ int status;
+
+ if (adap->nr & ~MAX_ID_MASK)
+ return -EINVAL;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ mutex_lock(&core_lock);
+ /* "above" here means "above or equal to", sigh;
+ * we need the "equal to" result to force the result
+ */
+ status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
+ if (status == 0 && id != adap->nr) {
+ status = -EBUSY;
+ idr_remove(&i2c_adapter_idr, id);
+ }
+ mutex_unlock(&core_lock);
+ if (status == -EAGAIN)
+ goto retry;
+
+ if (status == 0)
+ status = i2c_register_adapter(adap);
+ return status;
+}
+EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
+
+static int i2c_do_del_adapter(struct i2c_driver *driver,
+ struct i2c_adapter *adapter)
+{
+ struct i2c_client *client, *_n;
+ int res;
+
+ /* 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) {
+ if (client->adapter == adapter) {
+ 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)
+ return 0;
+ dev_warn(&adapter->dev, "%s: detach_adapter method is deprecated\n",
+ driver->driver.name);
+ res = driver->detach_adapter(adapter);
+ if (res)
+ dev_err(&adapter->dev, "detach_adapter failed (%d) "
+ "for driver [%s]\n", res, driver->driver.name);
+ return res;
+}
+
+static int __unregister_client(struct device *dev, void *dummy)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ if (client && strcmp(client->name, "dummy"))
+ i2c_unregister_device(client);
+ return 0;
+}
+
+static int __unregister_dummy(struct device *dev, void *dummy)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ if (client)
+ i2c_unregister_device(client);
+ 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
+ * Context: can sleep
+ *
+ * This unregisters an I2C adapter which was previously registered
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ */
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+ int res = 0;
+ struct i2c_adapter *found;
+ struct i2c_client *client, *next;
+
+ /* First make sure that this adapter was ever added */
+ mutex_lock(&core_lock);
+ found = idr_find(&i2c_adapter_idr, adap->nr);
+ mutex_unlock(&core_lock);
+ if (found != adap) {
+ pr_debug("i2c-core: attempting to delete unregistered "
+ "adapter [%s]\n", adap->name);
+ return -EINVAL;
+ }
+
+ /* Tell drivers about this removal */
+ mutex_lock(&core_lock);
+ res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+ __process_removed_adapter);
+ mutex_unlock(&core_lock);
+ if (res)
+ return res;
+
+ /* Remove devices instantiated from sysfs */
+ mutex_lock(&adap->userspace_clients_lock);
+ list_for_each_entry_safe(client, next, &adap->userspace_clients,
+ detected) {
+ dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
+ client->addr);
+ list_del(&client->detected);
+ i2c_unregister_device(client);
+ }
+ mutex_unlock(&adap->userspace_clients_lock);
+
+ /* Detach any active clients. This can't fail, thus we do not
+ * check the returned value. This is a two-pass process, because
+ * we can't remove the dummy devices during the first pass: they
+ * could have been instantiated by real devices wishing to clean
+ * them up properly, so we give them a chance to do that first. */
+ res = device_for_each_child(&adap->dev, NULL, __unregister_client);
+ res = device_for_each_child(&adap->dev, NULL, __unregister_dummy);
+
+#ifdef CONFIG_I2C_COMPAT
+ class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
+ 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);
+
+ /* wait for sysfs to drop all references */
+ wait_for_completion(&adap->dev_released);
+
+ /* free bus id */
+ mutex_lock(&core_lock);
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ mutex_unlock(&core_lock);
+
+ /* Clear the device structure in case this adapter is ever going to be
+ added again */
+ memset(&adap->dev, 0, sizeof(adap->dev));
+
+ return 0;
+}
+EXPORT_SYMBOL(i2c_del_adapter);
+
+
+/* ------------------------------------------------------------------------- */
+
+int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
+{
+ int res;
+
+ mutex_lock(&core_lock);
+ res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);
+ mutex_unlock(&core_lock);
+
+ return res;
+}
+EXPORT_SYMBOL_GPL(i2c_for_each_dev);
+
+static int __process_new_driver(struct device *dev, void *data)
+{
+ if (dev->type != &i2c_adapter_type)
+ return 0;
+ return i2c_do_add_adapter(data, to_i2c_adapter(dev));
+}
+
+/*
+ * An i2c_driver is used with one or more i2c_client (device) nodes to access
+ * i2c slave chips, on a bus instance associated with some i2c_adapter.
+ */
+
+int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
+{
+ int res;
+
+ /* Can't register until after driver model init */
+ if (unlikely(WARN_ON(!i2c_bus_type.p)))
+ return -EAGAIN;
+
+ /* add the driver to the list of i2c drivers in the driver core */
+ driver->driver.owner = owner;
+ driver->driver.bus = &i2c_bus_type;
+
+ /* When registration returns, the driver core
+ * will have called probe() for all matching-but-unbound devices.
+ */
+ res = driver_register(&driver->driver);
+ if (res)
+ return res;
+
+ /* Drivers should switch to dev_pm_ops instead. */
+ if (driver->suspend)
+ pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
+ driver->driver.name);
+ if (driver->resume)
+ pr_warn("i2c-core: driver [%s] using legacy resume method\n",
+ driver->driver.name);
+
+ pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
+
+ INIT_LIST_HEAD(&driver->clients);
+ /* Walk the adapters that are already present */
+ i2c_for_each_dev(driver, __process_new_driver);
+
+ return 0;
+}
+EXPORT_SYMBOL(i2c_register_driver);
+
+static int __process_removed_driver(struct device *dev, void *data)
+{
+ if (dev->type != &i2c_adapter_type)
+ return 0;
+ return i2c_do_del_adapter(data, to_i2c_adapter(dev));
+}
+
+/**
+ * i2c_del_driver - unregister I2C driver
+ * @driver: the driver being unregistered
+ * Context: can sleep
+ */
+void i2c_del_driver(struct i2c_driver *driver)
+{
+ i2c_for_each_dev(driver, __process_removed_driver);
+
+ driver_unregister(&driver->driver);
+ pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL(i2c_del_driver);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * i2c_use_client - increments the reference count of the i2c client structure
+ * @client: the client being referenced
+ *
+ * Each live reference to a client should be refcounted. The driver model does
+ * that automatically as part of driver binding, so that most drivers don't
+ * need to do this explicitly: they hold a reference until they're unbound
+ * from the device.
+ *
+ * A pointer to the client with the incremented reference counter is returned.
+ */
+struct i2c_client *i2c_use_client(struct i2c_client *client)
+{
+ if (client && get_device(&client->dev))
+ return client;
+ return NULL;
+}
+EXPORT_SYMBOL(i2c_use_client);
+
+/**
+ * i2c_release_client - release a use of the i2c client structure
+ * @client: the client being no longer referenced
+ *
+ * Must be called when a user of a client is finished with it.
+ */
+void i2c_release_client(struct i2c_client *client)
+{
+ if (client)
+ put_device(&client->dev);
+}
+EXPORT_SYMBOL(i2c_release_client);
+
+struct i2c_cmd_arg {
+ unsigned cmd;
+ void *arg;
+};
+
+static int i2c_cmd(struct device *dev, void *_arg)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_cmd_arg *arg = _arg;
+
+ if (client && client->driver && client->driver->command)
+ client->driver->command(client, arg->cmd, arg->arg);
+ return 0;
+}
+
+void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
+{
+ struct i2c_cmd_arg cmd_arg;
+
+ cmd_arg.cmd = cmd;
+ cmd_arg.arg = arg;
+ device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
+}
+EXPORT_SYMBOL(i2c_clients_command);
+
+static int __init i2c_init(void)
+{
+ int retval;
+
+ retval = bus_register(&i2c_bus_type);
+ if (retval)
+ return retval;
+#ifdef CONFIG_I2C_COMPAT
+ i2c_adapter_compat_class = class_compat_register("i2c-adapter");
+ if (!i2c_adapter_compat_class) {
+ retval = -ENOMEM;
+ goto bus_err;
+ }
+#endif
+ retval = i2c_add_driver(&dummy_driver);
+ if (retval)
+ goto class_err;
+ return 0;
+
+class_err:
+#ifdef CONFIG_I2C_COMPAT
+ class_compat_unregister(i2c_adapter_compat_class);
+bus_err:
+#endif
+ bus_unregister(&i2c_bus_type);
+ return retval;
+}
+
+static void __exit i2c_exit(void)
+{
+ i2c_del_driver(&dummy_driver);
+#ifdef CONFIG_I2C_COMPAT
+ class_compat_unregister(i2c_adapter_compat_class);
+#endif
+ bus_unregister(&i2c_bus_type);
+}
+
+/* We must initialize early, because some subsystems register i2c drivers
+ * in subsys_initcall() code, but are linked (and initialized) before i2c.
+ */
+postcore_initcall(i2c_init);
+module_exit(i2c_exit);
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+/**
+ * i2c_transfer - execute a single or combined I2C message
+ * @adap: Handle to I2C bus
+ * @msgs: One or more messages to execute before STOP is issued to
+ * terminate the operation; each message begins with a START.
+ * @num: Number of messages to be executed.
+ *
+ * Returns negative errno, else the number of messages executed.
+ *
+ * Note that there is no requirement that each message be sent to
+ * the same slave address, although that is the most common model.
+ */
+int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ unsigned long orig_jiffies;
+ int ret, try;
+
+ /* REVISIT the fault reporting model here is weak:
+ *
+ * - When we get an error after receiving N bytes from a slave,
+ * there is no way to report "N".
+ *
+ * - When we get a NAK after transmitting N bytes to a slave,
+ * there is no way to report "N" ... or to let the master
+ * continue executing the rest of this combined message, if
+ * that's the appropriate response.
+ *
+ * - When for example "num" is two and we successfully complete
+ * the first message but get an error part way through the
+ * second, it's unclear whether that should be reported as
+ * one (discarding status on the second message) or errno
+ * (discarding status on the first one).
+ */
+
+ if (adap->algo->master_xfer) {
+#ifdef DEBUG
+ for (ret = 0; ret < num; ret++) {
+ dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+ "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
+ ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+ (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+ }
+#endif
+
+ if (in_atomic() || irqs_disabled()) {
+ ret = i2c_trylock_adapter(adap);
+ if (!ret)
+ /* I2C activity is ongoing. */
+ return -EAGAIN;
+ } else {
+ i2c_lock_adapter(adap);
+ }
+
+ /* Retry automatically on arbitration loss */
+ orig_jiffies = jiffies;
+ for (ret = 0, try = 0; try <= adap->retries; try++) {
+ ret = adap->algo->master_xfer(adap, msgs, num);
+ if (ret != -EAGAIN)
+ break;
+ if (time_after(jiffies, orig_jiffies + adap->timeout))
+ break;
+ }
+ i2c_unlock_adapter(adap);
+
+ return ret;
+ } else {
+ dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+ return -EOPNOTSUPP;
+ }
+}
+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, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes written.
+ */
+int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
+{
+ int ret;
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ msg.buf = (char *)buf;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
+}
+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, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes read.
+ */
+int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+ int ret;
+
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_recv);
+
+/* ----------------------------------------------------
+ * the i2c address scanning function
+ * Will not work for 10-bit addresses!
+ * ----------------------------------------------------
+ */
+
+/*
+ * Legacy default probe function, mostly relevant for SMBus. The default
+ * probe method is a quick write, but it is known to corrupt the 24RF08
+ * EEPROMs due to a state machine bug, and could also irreversibly
+ * write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f,
+ * we use a short byte read instead. Also, some bus drivers don't implement
+ * quick write, so we fallback to a byte read in that case too.
+ * On x86, there is another special case for FSC hardware monitoring chips,
+ * which want regular byte reads (address 0x73.) Fortunately, these are the
+ * only known chips using this I2C address on PC hardware.
+ * Returns 1 if probe succeeded, 0 if not.
+ */
+static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr)
+{
+ int err;
+ union i2c_smbus_data dummy;
+
+#ifdef CONFIG_X86
+ if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON)
+ && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &dummy);
+ else
+#endif
+ if (!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50)
+ && i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
+ err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
+ I2C_SMBUS_QUICK, NULL);
+ else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE))
+ err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE, &dummy);
+ else {
+ dev_warn(&adap->dev, "No suitable probing method supported\n");
+ err = -EOPNOTSUPP;
+ }
+
+ return err >= 0;
+}
+
+static int i2c_detect_address(struct i2c_client *temp_client,
+ struct i2c_driver *driver)
+{
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter = temp_client->adapter;
+ int addr = temp_client->addr;
+ int err;
+
+ /* Make sure the address is valid */
+ err = i2c_check_addr_validity(addr);
+ if (err) {
+ dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
+ addr);
+ return err;
+ }
+
+ /* Skip if already in use */
+ if (i2c_check_addr_busy(adapter, addr))
+ return 0;
+
+ /* Make sure there is something at this address */
+ if (!i2c_default_probe(adapter, addr))
+ return 0;
+
+ /* Finally call the custom detection function */
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = addr;
+ 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. */
+ return err == -ENODEV ? 0 : err;
+ }
+
+ /* Consistency check */
+ if (info.type[0] == '\0') {
+ dev_err(&adapter->dev, "%s detection function provided "
+ "no name for 0x%x\n", driver->driver.name,
+ addr);
+ } else {
+ struct i2c_client *client;
+
+ /* Detection succeeded, instantiate the device */
+ dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
+ info.type, info.addr);
+ client = i2c_new_device(adapter, &info);
+ if (client)
+ list_add_tail(&client->detected, &driver->clients);
+ else
+ dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
+ info.type, info.addr);
+ }
+ return 0;
+}
+
+static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
+{
+ const unsigned short *address_list;
+ struct i2c_client *temp_client;
+ int i, err = 0;
+ int adap_id = i2c_adapter_id(adapter);
+
+ address_list = driver->address_list;
+ if (!driver->detect || !address_list)
+ return 0;
+
+ /* Stop here if the classes do not match */
+ if (!(adapter->class & driver->class))
+ return 0;
+
+ /* Set up a temporary client to help detect callback */
+ temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!temp_client)
+ return -ENOMEM;
+ temp_client->adapter = adapter;
+
+ 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_list[i]);
+ temp_client->addr = address_list[i];
+ err = i2c_detect_address(temp_client, driver);
+ if (unlikely(err))
+ break;
+ }
+
+ kfree(temp_client);
+ return err;
+}
+
+int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr)
+{
+ return i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_QUICK, NULL) >= 0;
+}
+EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);
+
+struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+ struct i2c_board_info *info,
+ unsigned short const *addr_list,
+ int (*probe)(struct i2c_adapter *, unsigned short addr))
+{
+ int i;
+
+ if (!probe)
+ probe = i2c_default_probe;
+
+ for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
+ /* Check address validity */
+ if (i2c_check_addr_validity(addr_list[i]) < 0) {
+ dev_warn(&adap->dev, "Invalid 7-bit address "
+ "0x%02x\n", addr_list[i]);
+ continue;
+ }
+
+ /* Check address availability */
+ if (i2c_check_addr_busy(adap, addr_list[i])) {
+ dev_dbg(&adap->dev, "Address 0x%02x already in "
+ "use, not probing\n", addr_list[i]);
+ continue;
+ }
+
+ /* Test address responsiveness */
+ if (probe(adap, addr_list[i]))
+ break;
+ }
+
+ if (addr_list[i] == I2C_CLIENT_END) {
+ dev_dbg(&adap->dev, "Probing failed, no device found\n");
+ return NULL;
+ }
+
+ info->addr = addr_list[i];
+ return i2c_new_device(adap, info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_probed_device);
+
+struct i2c_adapter *i2c_get_adapter(int nr)
+{
+ struct i2c_adapter *adapter;
+
+ mutex_lock(&core_lock);
+ adapter = idr_find(&i2c_adapter_idr, nr);
+ if (adapter && !try_module_get(adapter->owner))
+ adapter = NULL;
+
+ mutex_unlock(&core_lock);
+ return adapter;
+}
+EXPORT_SYMBOL(i2c_get_adapter);
+
+void i2c_put_adapter(struct i2c_adapter *adap)
+{
+ module_put(adap->owner);
+}
+EXPORT_SYMBOL(i2c_put_adapter);
+
+/* The SMBus parts */
+
+#define POLY (0x1070U << 3)
+static u8 crc8(u16 data)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (data & 0x8000)
+ data = data ^ POLY;
+ data = data << 1;
+ }
+ return (u8)(data >> 8);
+}
+
+/* Incremental CRC8 over count bytes in the array pointed to by p */
+static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ crc = crc8((crc ^ p[i]) << 8);
+ return crc;
+}
+
+/* Assume a 7-bit address, which is reasonable for SMBus */
+static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
+{
+ /* The address will be sent first */
+ u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
+ pec = i2c_smbus_pec(pec, &addr, 1);
+
+ /* The data buffer follows */
+ return i2c_smbus_pec(pec, msg->buf, msg->len);
+}
+
+/* Used for write only transactions */
+static inline void i2c_smbus_add_pec(struct i2c_msg *msg)
+{
+ msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg);
+ msg->len++;
+}
+
+/* Return <0 on CRC error
+ If there was a write before this read (most cases) we need to take the
+ partial CRC from the write part into account.
+ Note that this function does modify the message (we need to decrease the
+ message length to hide the CRC byte from the caller). */
+static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
+{
+ u8 rpec = msg->buf[--msg->len];
+ cpec = i2c_smbus_msg_pec(cpec, msg);
+
+ if (rpec != cpec) {
+ pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
+ rpec, cpec);
+ return -EBADMSG;
+ }
+ return 0;
+}
+
+/**
+ * i2c_smbus_read_byte - SMBus "receive byte" protocol
+ * @client: Handle to slave device
+ *
+ * This executes the SMBus "receive byte" protocol, returning negative errno
+ * else the byte received from the device.
+ */
+s32 i2c_smbus_read_byte(const struct i2c_client *client)
+{
+ union i2c_smbus_data data;
+ int status;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE, &data);
+ return (status < 0) ? status : data.byte;
+}
+EXPORT_SYMBOL(i2c_smbus_read_byte);
+
+/**
+ * i2c_smbus_write_byte - SMBus "send byte" protocol
+ * @client: Handle to slave device
+ * @value: Byte to be sent
+ *
+ * This executes the SMBus "send byte" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value)
+{
+ return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
+}
+EXPORT_SYMBOL(i2c_smbus_write_byte);
+
+/**
+ * i2c_smbus_read_byte_data - SMBus "read byte" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ *
+ * This executes the SMBus "read byte" protocol, returning negative errno
+ * else a data byte received from the device.
+ */
+s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
+{
+ union i2c_smbus_data data;
+ int status;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, command,
+ I2C_SMBUS_BYTE_DATA, &data);
+ return (status < 0) ? status : data.byte;
+}
+EXPORT_SYMBOL(i2c_smbus_read_byte_data);
+
+/**
+ * i2c_smbus_write_byte_data - SMBus "write byte" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: Byte being written
+ *
+ * This executes the SMBus "write byte" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command,
+ u8 value)
+{
+ union i2c_smbus_data data;
+ data.byte = value;
+ return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_BYTE_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_byte_data);
+
+/**
+ * i2c_smbus_read_word_data - SMBus "read word" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ *
+ * This executes the SMBus "read word" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
+{
+ union i2c_smbus_data data;
+ int status;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, command,
+ I2C_SMBUS_WORD_DATA, &data);
+ return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
+
+/**
+ * i2c_smbus_write_word_data - SMBus "write word" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "write word" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,
+ u16 value)
+{
+ union i2c_smbus_data data;
+ data.word = value;
+ return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_WORD_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_word_data);
+
+/**
+ * i2c_smbus_process_call - SMBus "process call" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "process call" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_process_call(const struct i2c_client *client, u8 command,
+ u16 value)
+{
+ union i2c_smbus_data data;
+ int status;
+ data.word = value;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_PROC_CALL, &data);
+ return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_process_call);
+
+/**
+ * i2c_smbus_read_block_data - SMBus "block read" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @values: Byte array into which data will be read; big enough to hold
+ * the data returned by the slave. SMBus allows at most 32 bytes.
+ *
+ * This executes the SMBus "block read" protocol, returning negative errno
+ * else the number of data bytes in the slave's response.
+ *
+ * Note that using this function requires that the client's adapter support
+ * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers
+ * support this; its emulation through I2C messaging relies on a specific
+ * mechanism (I2C_M_RECV_LEN) which may not be implemented.
+ */
+s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command,
+ u8 *values)
+{
+ union i2c_smbus_data data;
+ int status;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, command,
+ I2C_SMBUS_BLOCK_DATA, &data);
+ if (status)
+ return status;
+
+ memcpy(values, &data.block[1], data.block[0]);
+ return data.block[0];
+}
+EXPORT_SYMBOL(i2c_smbus_read_block_data);
+
+/**
+ * i2c_smbus_write_block_data - SMBus "block write" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @length: Size of data block; SMBus allows at most 32 bytes
+ * @values: Byte array which will be written.
+ *
+ * This executes the SMBus "block write" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command,
+ u8 length, const u8 *values)
+{
+ union i2c_smbus_data data;
+
+ if (length > I2C_SMBUS_BLOCK_MAX)
+ length = I2C_SMBUS_BLOCK_MAX;
+ data.block[0] = length;
+ memcpy(&data.block[1], values, length);
+ return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_BLOCK_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_block_data);
+
+/* Returns the number of read bytes */
+s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command,
+ u8 length, u8 *values)
+{
+ union i2c_smbus_data data;
+ int status;
+
+ if (length > I2C_SMBUS_BLOCK_MAX)
+ length = I2C_SMBUS_BLOCK_MAX;
+ data.block[0] = length;
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, command,
+ I2C_SMBUS_I2C_BLOCK_DATA, &data);
+ if (status < 0)
+ return status;
+
+ memcpy(values, &data.block[1], data.block[0]);
+ return data.block[0];
+}
+EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
+
+s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command,
+ u8 length, const u8 *values)
+{
+ union i2c_smbus_data data;
+
+ if (length > I2C_SMBUS_BLOCK_MAX)
+ length = I2C_SMBUS_BLOCK_MAX;
+ data.block[0] = length;
+ memcpy(data.block + 1, values, length);
+ return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_I2C_BLOCK_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
+
+/* Simulate a SMBus command using the i2c protocol
+ No checking of parameters is done! */
+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* So we need to generate a series of msgs. In the case of writing, we
+ need to use only one message; when reading, we need two. We initialize
+ most things with sane defaults, to keep the code below somewhat
+ simpler. */
+ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
+ unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
+ int num = read_write == I2C_SMBUS_READ ? 2 : 1;
+ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
+ { addr, flags | I2C_M_RD, 0, msgbuf1 }
+ };
+ int i;
+ u8 partial_pec = 0;
+ int status;
+
+ msgbuf0[0] = command;
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ msg[0].len = 0;
+ /* Special case: The read/write field is used as data */
+ msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
+ I2C_M_RD : 0);
+ num = 1;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ /* Special case: only a read! */
+ msg[0].flags = I2C_M_RD | flags;
+ num = 1;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ msg[1].len = 1;
+ else {
+ msg[0].len = 2;
+ msgbuf0[1] = data->byte;
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ)
+ msg[1].len = 2;
+ else {
+ msg[0].len = 3;
+ msgbuf0[1] = data->word & 0xff;
+ msgbuf0[2] = data->word >> 8;
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ num = 2; /* Special case */
+ read_write = I2C_SMBUS_READ;
+ msg[0].len = 3;
+ msg[1].len = 2;
+ msgbuf0[1] = data->word & 0xff;
+ msgbuf0[2] = data->word >> 8;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ msg[1].flags |= I2C_M_RECV_LEN;
+ msg[1].len = 1; /* block length will be added by
+ the underlying bus driver */
+ } else {
+ msg[0].len = data->block[0] + 2;
+ if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
+ dev_err(&adapter->dev,
+ "Invalid block write size %d\n",
+ data->block[0]);
+ return -EINVAL;
+ }
+ for (i = 1; i < msg[0].len; i++)
+ msgbuf0[i] = data->block[i-1];
+ }
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ num = 2; /* Another special case */
+ read_write = I2C_SMBUS_READ;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&adapter->dev,
+ "Invalid block write size %d\n",
+ data->block[0]);
+ return -EINVAL;
+ }
+ msg[0].len = data->block[0] + 2;
+ for (i = 1; i < msg[0].len; i++)
+ msgbuf0[i] = data->block[i-1];
+ msg[1].flags |= I2C_M_RECV_LEN;
+ msg[1].len = 1; /* block length will be added by
+ the underlying bus driver */
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ msg[1].len = data->block[0];
+ } else {
+ msg[0].len = data->block[0] + 1;
+ if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
+ dev_err(&adapter->dev,
+ "Invalid block write size %d\n",
+ data->block[0]);
+ return -EINVAL;
+ }
+ for (i = 1; i <= data->block[0]; i++)
+ msgbuf0[i] = data->block[i];
+ }
+ break;
+ default:
+ dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
+ && size != I2C_SMBUS_I2C_BLOCK_DATA);
+ if (i) {
+ /* Compute PEC if first message is a write */
+ if (!(msg[0].flags & I2C_M_RD)) {
+ if (num == 1) /* Write only */
+ i2c_smbus_add_pec(&msg[0]);
+ else /* Write followed by read */
+ partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
+ }
+ /* Ask for PEC if last message is a read */
+ if (msg[num-1].flags & I2C_M_RD)
+ msg[num-1].len++;
+ }
+
+ status = i2c_transfer(adapter, msg, num);
+ if (status < 0)
+ return status;
+
+ /* Check PEC if last message is a read */
+ if (i && (msg[num-1].flags & I2C_M_RD)) {
+ status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
+ if (status < 0)
+ return status;
+ }
+
+ if (read_write == I2C_SMBUS_READ)
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ data->byte = msgbuf0[0];
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = msgbuf1[0];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = msgbuf1[0] | (msgbuf1[1] << 8);
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ for (i = 0; i < data->block[0]; i++)
+ data->block[i+1] = msgbuf1[i];
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ for (i = 0; i < msgbuf1[0] + 1; i++)
+ data->block[i] = msgbuf1[i];
+ break;
+ }
+ return 0;
+}
+
+/**
+ * i2c_smbus_xfer - execute SMBus protocol operations
+ * @adapter: Handle to I2C bus
+ * @addr: Address of SMBus slave on that bus
+ * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
+ * @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE
+ * @command: Byte interpreted by slave, for protocols which use such bytes
+ * @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL
+ * @data: Data to be read or written
+ *
+ * This executes an SMBus protocol operation, and returns a negative
+ * errno code else zero on success.
+ */
+s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
+ char read_write, u8 command, int protocol,
+ union i2c_smbus_data *data)
+{
+ unsigned long orig_jiffies;
+ int try;
+ s32 res;
+
+ flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+
+ if (adapter->algo->smbus_xfer) {
+ i2c_lock_adapter(adapter);
+
+ /* Retry automatically on arbitration loss */
+ orig_jiffies = jiffies;
+ for (res = 0, try = 0; try <= adapter->retries; try++) {
+ res = adapter->algo->smbus_xfer(adapter, addr, flags,
+ read_write, command,
+ protocol, data);
+ if (res != -EAGAIN)
+ break;
+ if (time_after(jiffies,
+ orig_jiffies + adapter->timeout))
+ break;
+ }
+ i2c_unlock_adapter(adapter);
+ } else
+ res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
+ command, protocol, data);
+
+ return res;
+}
+EXPORT_SYMBOL(i2c_smbus_xfer);
+
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus main module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
new file mode 100644
index 00000000..9f9c57ff
--- /dev/null
+++ b/drivers/i2c/i2c-core.h
@@ -0,0 +1,33 @@
+/*
+ * i2c-core.h - interfaces internal to the I2C framework
+ *
+ * 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/rwsem.h>
+
+struct i2c_devinfo {
+ struct list_head list;
+ int busnum;
+ struct i2c_board_info board_info;
+};
+
+/* board_lock protects board_list and first_dynamic_bus_num.
+ * only i2c core components are allowed to use these symbols.
+ */
+extern struct rw_semaphore __i2c_board_lock;
+extern struct list_head __i2c_board_list;
+extern int __i2c_first_dynamic_bus_num;
+
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
new file mode 100644
index 00000000..c90ce50b
--- /dev/null
+++ b/drivers/i2c/i2c-dev.c
@@ -0,0 +1,656 @@
+/*
+ i2c-dev.c - i2c-bus driver, char device interface
+
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+ But I have used so much of his original code and ideas that it seems
+ only fair to recognize him as co-author -- Frodo */
+
+/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+
+/*
+ * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
+ * slave (i2c_client) with which messages will be exchanged. It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ * The list of i2c_dev structures is parallel to the i2c_adapter lists
+ * maintained by the driver model, and is updated using bus notifications.
+ */
+struct i2c_dev {
+ struct list_head list;
+ struct i2c_adapter *adap;
+ struct device *dev;
+};
+
+#define I2C_MINORS 256
+static LIST_HEAD(i2c_dev_list);
+static DEFINE_SPINLOCK(i2c_dev_list_lock);
+
+static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+{
+ struct i2c_dev *i2c_dev;
+
+ spin_lock(&i2c_dev_list_lock);
+ list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
+ if (i2c_dev->adap->nr == index)
+ goto found;
+ }
+ i2c_dev = NULL;
+found:
+ spin_unlock(&i2c_dev_list_lock);
+ return i2c_dev;
+}
+
+static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+{
+ struct i2c_dev *i2c_dev;
+
+ if (adap->nr >= I2C_MINORS) {
+ printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
+ adap->nr);
+ return ERR_PTR(-ENODEV);
+ }
+
+ i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+ return ERR_PTR(-ENOMEM);
+ i2c_dev->adap = adap;
+
+ spin_lock(&i2c_dev_list_lock);
+ list_add_tail(&i2c_dev->list, &i2c_dev_list);
+ spin_unlock(&i2c_dev_list_lock);
+ return i2c_dev;
+}
+
+static void return_i2c_dev(struct i2c_dev *i2c_dev)
+{
+ spin_lock(&i2c_dev_list_lock);
+ list_del(&i2c_dev->list);
+ spin_unlock(&i2c_dev_list_lock);
+ kfree(i2c_dev);
+}
+
+static ssize_t show_adapter_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt));
+
+ if (!i2c_dev)
+ return -ENODEV;
+ return sprintf(buf, "%s\n", i2c_dev->adap->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * After opening an instance of this character special file, a file
+ * descriptor starts out associated only with an i2c_adapter (and bus).
+ *
+ * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
+ * traffic to any devices on the bus used by that adapter. That's because
+ * the i2c_msg vectors embed all the addressing information they need, and
+ * are submitted directly to an i2c_adapter. However, SMBus-only adapters
+ * don't support that interface.
+ *
+ * To use read()/write() system calls on that file descriptor, or to use
+ * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
+ * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl. That configures an anonymous
+ * (never registered) i2c_client so it holds the addressing information
+ * needed by those system calls and by this SMBus interface.
+ */
+
+static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
+ loff_t *offset)
+{
+ char *tmp;
+ int ret;
+
+ struct i2c_client *client = file->private_data;
+
+ if (count > 8192)
+ count = 8192;
+
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (tmp == NULL)
+ return -ENOMEM;
+
+ pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
+ iminor(file->f_path.dentry->d_inode), count);
+
+ ret = i2c_master_recv(client, tmp, count);
+ if (ret >= 0)
+ ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
+ kfree(tmp);
+ return ret;
+}
+
+static ssize_t i2cdev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ int ret;
+ char *tmp;
+ struct i2c_client *client = file->private_data;
+
+ if (count > 8192)
+ count = 8192;
+
+ tmp = memdup_user(buf, count);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
+
+ pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
+ iminor(file->f_path.dentry->d_inode), count);
+
+ ret = i2c_master_send(client, tmp, count);
+ kfree(tmp);
+ return ret;
+}
+
+static int i2cdev_check(struct device *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+
+ if (!client || client->addr != *(unsigned int *)addrp)
+ return 0;
+
+ return dev->driver ? -EBUSY : 0;
+}
+
+/* walk up mux tree */
+static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ int result;
+
+ result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
+ if (!result && parent)
+ result = i2cdev_check_mux_parents(parent, addr);
+
+ return result;
+}
+
+/* recurse down mux tree */
+static int i2cdev_check_mux_children(struct device *dev, void *addrp)
+{
+ int result;
+
+ if (dev->type == &i2c_adapter_type)
+ result = device_for_each_child(dev, addrp,
+ i2cdev_check_mux_children);
+ else
+ result = i2cdev_check(dev, addrp);
+
+ return result;
+}
+
+/* This address checking function differs from the one in i2c-core
+ in that it considers an address with a registered device, but no
+ driver bound to it, as NOT busy. */
+static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ int result = 0;
+
+ if (parent)
+ result = i2cdev_check_mux_parents(parent, addr);
+
+ if (!result)
+ result = device_for_each_child(&adapter->dev, &addr,
+ i2cdev_check_mux_children);
+
+ return result;
+}
+
+static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+ unsigned long arg)
+{
+ struct i2c_rdwr_ioctl_data rdwr_arg;
+ struct i2c_msg *rdwr_pa;
+ u8 __user **data_ptrs;
+ int i, res;
+
+ if (copy_from_user(&rdwr_arg,
+ (struct i2c_rdwr_ioctl_data __user *)arg,
+ sizeof(rdwr_arg)))
+ return -EFAULT;
+
+ /* Put an arbitrary limit on the number of messages that can
+ * be sent at once */
+ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+ return -EINVAL;
+
+ rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
+ if (!rdwr_pa)
+ return -ENOMEM;
+
+ if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
+ rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
+ kfree(rdwr_pa);
+ return -EFAULT;
+ }
+
+ data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
+ if (data_ptrs == NULL) {
+ kfree(rdwr_pa);
+ return -ENOMEM;
+ }
+
+ res = 0;
+ for (i = 0; i < rdwr_arg.nmsgs; i++) {
+ /* Limit the size of the message to a sane amount;
+ * and don't let length change either. */
+ if ((rdwr_pa[i].len > 8192) ||
+ (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
+ res = -EINVAL;
+ break;
+ }
+ data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
+ rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
+ if (IS_ERR(rdwr_pa[i].buf)) {
+ res = PTR_ERR(rdwr_pa[i].buf);
+ break;
+ }
+ }
+ if (res < 0) {
+ int j;
+ for (j = 0; j < i; ++j)
+ kfree(rdwr_pa[j].buf);
+ kfree(data_ptrs);
+ kfree(rdwr_pa);
+ return res;
+ }
+
+ res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+ while (i-- > 0) {
+ if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
+ if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
+ rdwr_pa[i].len))
+ res = -EFAULT;
+ }
+ kfree(rdwr_pa[i].buf);
+ }
+ kfree(data_ptrs);
+ kfree(rdwr_pa);
+ return res;
+}
+
+static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
+ unsigned long arg)
+{
+ struct i2c_smbus_ioctl_data data_arg;
+ union i2c_smbus_data temp;
+ int datasize, res;
+
+ if (copy_from_user(&data_arg,
+ (struct i2c_smbus_ioctl_data __user *) arg,
+ sizeof(struct i2c_smbus_ioctl_data)))
+ return -EFAULT;
+ if ((data_arg.size != I2C_SMBUS_BYTE) &&
+ (data_arg.size != I2C_SMBUS_QUICK) &&
+ (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+ (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+ (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+ (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
+ (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
+ (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+ (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
+ dev_dbg(&client->adapter->dev,
+ "size out of range (%x) in ioctl I2C_SMBUS.\n",
+ data_arg.size);
+ return -EINVAL;
+ }
+ /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+ so the check is valid if size==I2C_SMBUS_QUICK too. */
+ if ((data_arg.read_write != I2C_SMBUS_READ) &&
+ (data_arg.read_write != I2C_SMBUS_WRITE)) {
+ dev_dbg(&client->adapter->dev,
+ "read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+ data_arg.read_write);
+ return -EINVAL;
+ }
+
+ /* Note that command values are always valid! */
+
+ if ((data_arg.size == I2C_SMBUS_QUICK) ||
+ ((data_arg.size == I2C_SMBUS_BYTE) &&
+ (data_arg.read_write == I2C_SMBUS_WRITE)))
+ /* These are special: we do not use data */
+ return i2c_smbus_xfer(client->adapter, client->addr,
+ client->flags, data_arg.read_write,
+ data_arg.command, data_arg.size, NULL);
+
+ if (data_arg.data == NULL) {
+ dev_dbg(&client->adapter->dev,
+ "data is NULL pointer in ioctl I2C_SMBUS.\n");
+ return -EINVAL;
+ }
+
+ if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
+ (data_arg.size == I2C_SMBUS_BYTE))
+ datasize = sizeof(data_arg.data->byte);
+ else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+ (data_arg.size == I2C_SMBUS_PROC_CALL))
+ datasize = sizeof(data_arg.data->word);
+ else /* size == smbus block, i2c block, or block proc. call */
+ datasize = sizeof(data_arg.data->block);
+
+ if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
+ (data_arg.read_write == I2C_SMBUS_WRITE)) {
+ if (copy_from_user(&temp, data_arg.data, datasize))
+ return -EFAULT;
+ }
+ if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
+ /* Convert old I2C block commands to the new
+ convention. This preserves binary compatibility. */
+ data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
+ if (data_arg.read_write == I2C_SMBUS_READ)
+ temp.block[0] = I2C_SMBUS_BLOCK_MAX;
+ }
+ res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ data_arg.read_write, data_arg.command, data_arg.size, &temp);
+ if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ (data_arg.read_write == I2C_SMBUS_READ))) {
+ if (copy_to_user(data_arg.data, &temp, datasize))
+ return -EFAULT;
+ }
+ return res;
+}
+
+static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = file->private_data;
+ unsigned long funcs;
+
+ dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
+ cmd, arg);
+
+ switch (cmd) {
+ case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
+ /* NOTE: devices set up to work with "new style" drivers
+ * can't use I2C_SLAVE, even when the device node is not
+ * bound to a driver. Only I2C_SLAVE_FORCE will work.
+ *
+ * Setting the PEC flag here won't affect kernel drivers,
+ * which will be using the i2c_client node registered with
+ * the driver model core. Likewise, when that client has
+ * the PEC flag already set, the i2c-dev driver won't see
+ * (or use) this setting.
+ */
+ if ((arg > 0x3ff) ||
+ (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+ return -EINVAL;
+ if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
+ return -EBUSY;
+ /* REVISIT: address could become busy later */
+ client->addr = arg;
+ return 0;
+ case I2C_TENBIT:
+ if (arg)
+ client->flags |= I2C_M_TEN;
+ else
+ client->flags &= ~I2C_M_TEN;
+ return 0;
+ case I2C_PEC:
+ if (arg)
+ client->flags |= I2C_CLIENT_PEC;
+ else
+ client->flags &= ~I2C_CLIENT_PEC;
+ return 0;
+ case I2C_FUNCS:
+ funcs = i2c_get_functionality(client->adapter);
+ return put_user(funcs, (unsigned long __user *)arg);
+
+ case I2C_RDWR:
+ return i2cdev_ioctl_rdrw(client, arg);
+
+ case I2C_SMBUS:
+ return i2cdev_ioctl_smbus(client, arg);
+
+ case I2C_RETRIES:
+ client->adapter->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ /* For historical reasons, user-space sets the timeout
+ * value in units of 10 ms.
+ */
+ client->adapter->timeout = msecs_to_jiffies(arg * 10);
+ break;
+ default:
+ /* NOTE: returning a fault code here could cause trouble
+ * in buggy userspace code. Some old kernel bugs returned
+ * zero in this case, and userspace code might accidentally
+ * have depended on that bug.
+ */
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int i2cdev_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = iminor(inode);
+ struct i2c_client *client;
+ struct i2c_adapter *adap;
+ struct i2c_dev *i2c_dev;
+
+ i2c_dev = i2c_dev_get_by_minor(minor);
+ if (!i2c_dev)
+ return -ENODEV;
+
+ adap = i2c_get_adapter(i2c_dev->adap->nr);
+ 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.
+ *
+ * This client is ** NEVER REGISTERED ** with the driver model
+ * or I2C core code!! It just holds private copies of addressing
+ * information and maybe a PEC flag.
+ */
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client) {
+ i2c_put_adapter(adap);
+ return -ENOMEM;
+ }
+ snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
+
+ client->adapter = adap;
+ file->private_data = client;
+
+ return 0;
+}
+
+static int i2cdev_release(struct inode *inode, struct file *file)
+{
+ struct i2c_client *client = file->private_data;
+
+ i2c_put_adapter(client->adapter);
+ kfree(client);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations i2cdev_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = i2cdev_read,
+ .write = i2cdev_write,
+ .unlocked_ioctl = i2cdev_ioctl,
+ .open = i2cdev_open,
+ .release = i2cdev_release,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct class *i2c_dev_class;
+
+static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+{
+ struct i2c_adapter *adap;
+ struct i2c_dev *i2c_dev;
+ int res;
+
+ if (dev->type != &i2c_adapter_type)
+ return 0;
+ adap = to_i2c_adapter(dev);
+
+ i2c_dev = get_free_i2c_dev(adap);
+ if (IS_ERR(i2c_dev))
+ return PTR_ERR(i2c_dev);
+
+ /* register this i2c device with the driver core */
+ i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
+ MKDEV(I2C_MAJOR, adap->nr), NULL,
+ "i2c-%d", adap->nr);
+ if (IS_ERR(i2c_dev->dev)) {
+ res = PTR_ERR(i2c_dev->dev);
+ goto error;
+ }
+ res = device_create_file(i2c_dev->dev, &dev_attr_name);
+ if (res)
+ goto error_destroy;
+
+ pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+ adap->name, adap->nr);
+ return 0;
+error_destroy:
+ device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+error:
+ return_i2c_dev(i2c_dev);
+ return res;
+}
+
+static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+{
+ struct i2c_adapter *adap;
+ struct i2c_dev *i2c_dev;
+
+ if (dev->type != &i2c_adapter_type)
+ return 0;
+ adap = to_i2c_adapter(dev);
+
+ i2c_dev = i2c_dev_get_by_minor(adap->nr);
+ if (!i2c_dev) /* attach_adapter must have failed */
+ return 0;
+
+ device_remove_file(i2c_dev->dev, &dev_attr_name);
+ return_i2c_dev(i2c_dev);
+ device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+
+ pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
+ return 0;
+}
+
+int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ return i2cdev_attach_adapter(dev, NULL);
+ case BUS_NOTIFY_DEL_DEVICE:
+ return i2cdev_detach_adapter(dev, NULL);
+ }
+
+ return 0;
+}
+
+static struct notifier_block i2cdev_notifier = {
+ .notifier_call = i2cdev_notifier_call,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * module load/unload record keeping
+ */
+
+static int __init i2c_dev_init(void)
+{
+ int res;
+
+ printk(KERN_INFO "i2c /dev entries driver\n");
+
+ res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
+ if (res)
+ goto out;
+
+ i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
+ if (IS_ERR(i2c_dev_class)) {
+ res = PTR_ERR(i2c_dev_class);
+ goto out_unreg_chrdev;
+ }
+
+ /* Keep track of adapters which will be added or removed later */
+ res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
+ if (res)
+ goto out_unreg_class;
+
+ /* Bind to already existing adapters right away */
+ i2c_for_each_dev(NULL, i2cdev_attach_adapter);
+
+ return 0;
+
+out_unreg_class:
+ class_destroy(i2c_dev_class);
+out_unreg_chrdev:
+ unregister_chrdev(I2C_MAJOR, "i2c");
+out:
+ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
+ return res;
+}
+
+static void __exit i2c_dev_exit(void)
+{
+ bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
+ i2c_for_each_dev(NULL, i2cdev_detach_adapter);
+ class_destroy(i2c_dev_class);
+ unregister_chrdev(I2C_MAJOR, "i2c");
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+ "Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C /dev entries driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_dev_init);
+module_exit(i2c_dev_exit);
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
new file mode 100644
index 00000000..d7a4833b
--- /dev/null
+++ b/drivers/i2c/i2c-mux.c
@@ -0,0 +1,164 @@
+/*
+ * Multiplexed I2C bus driver.
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (c) 2009-2010 NSN GmbH & Co KG <michael.lawnick.ext@nsn.com>
+ *
+ * Simplifies access to complex multiplexed I2C bus topologies, by presenting
+ * each multiplexed bus segment as an additional I2C adapter.
+ * Supports multi-level mux'ing (mux behind a mux).
+ *
+ * Based on:
+ * i2c-virt.c from Kumar Gala <galak@kernel.crashing.org>
+ * i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc.
+ * i2c-virtual.c from Brian Kuschak <bkuschak@yahoo.com>
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+/* multiplexer per channel data */
+struct i2c_mux_priv {
+ struct i2c_adapter adap;
+ struct i2c_algorithm algo;
+
+ struct i2c_adapter *parent;
+ void *mux_dev; /* the mux chip/device */
+ u32 chan_id; /* the channel id */
+
+ int (*select)(struct i2c_adapter *, void *mux_dev, u32 chan_id);
+ int (*deselect)(struct i2c_adapter *, void *mux_dev, u32 chan_id);
+};
+
+static int i2c_mux_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_adapter *parent = priv->parent;
+ int ret;
+
+ /* Switch to the right mux port and perform the transfer. */
+
+ ret = priv->select(parent, priv->mux_dev, priv->chan_id);
+ if (ret >= 0)
+ ret = parent->algo->master_xfer(parent, msgs, num);
+ if (priv->deselect)
+ priv->deselect(parent, priv->mux_dev, priv->chan_id);
+
+ return ret;
+}
+
+static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+ u16 addr, unsigned short flags,
+ char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_adapter *parent = priv->parent;
+ int ret;
+
+ /* Select the right mux port and perform the transfer. */
+
+ ret = priv->select(parent, priv->mux_dev, priv->chan_id);
+ if (ret >= 0)
+ ret = parent->algo->smbus_xfer(parent, addr, flags,
+ read_write, command, size, data);
+ if (priv->deselect)
+ priv->deselect(parent, priv->mux_dev, priv->chan_id);
+
+ return ret;
+}
+
+/* Return the parent's functionality */
+static u32 i2c_mux_functionality(struct i2c_adapter *adap)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_adapter *parent = priv->parent;
+
+ return parent->algo->functionality(parent);
+}
+
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+ void *mux_dev, u32 force_nr, u32 chan_id,
+ int (*select) (struct i2c_adapter *,
+ void *, u32),
+ int (*deselect) (struct i2c_adapter *,
+ void *, u32))
+{
+ struct i2c_mux_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ /* Set up private adapter data */
+ priv->parent = parent;
+ priv->mux_dev = mux_dev;
+ priv->chan_id = chan_id;
+ priv->select = select;
+ priv->deselect = deselect;
+
+ /* Need to do algo dynamically because we don't know ahead
+ * of time what sort of physical adapter we'll be dealing with.
+ */
+ if (parent->algo->master_xfer)
+ priv->algo.master_xfer = i2c_mux_master_xfer;
+ if (parent->algo->smbus_xfer)
+ priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+ priv->algo.functionality = i2c_mux_functionality;
+
+ /* Now fill out new adapter structure */
+ snprintf(priv->adap.name, sizeof(priv->adap.name),
+ "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo = &priv->algo;
+ priv->adap.algo_data = priv;
+ priv->adap.dev.parent = &parent->dev;
+
+ if (force_nr) {
+ priv->adap.nr = force_nr;
+ ret = i2c_add_numbered_adapter(&priv->adap);
+ } else {
+ ret = i2c_add_adapter(&priv->adap);
+ }
+ if (ret < 0) {
+ dev_err(&parent->dev,
+ "failed to add mux-adapter (error=%d)\n",
+ ret);
+ kfree(priv);
+ return NULL;
+ }
+
+ dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
+ i2c_adapter_id(&priv->adap));
+
+ return &priv->adap;
+}
+EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
+
+int i2c_del_mux_adapter(struct i2c_adapter *adap)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ int ret;
+
+ ret = i2c_del_adapter(adap);
+ if (ret < 0)
+ return ret;
+ kfree(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
new file mode 100644
index 00000000..f61ccc1e
--- /dev/null
+++ b/drivers/i2c/i2c-smbus.c
@@ -0,0 +1,262 @@
+/*
+ * 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);
+
+ 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");
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
new file mode 100644
index 00000000..90b7a016
--- /dev/null
+++ b/drivers/i2c/muxes/Kconfig
@@ -0,0 +1,40 @@
+#
+# Multiplexer I2C chip drivers configuration
+#
+
+menu "Multiplexer I2C Chip support"
+ depends on I2C_MUX
+
+config I2C_MUX_GPIO
+ tristate "GPIO-based I2C multiplexer"
+ depends on GENERIC_GPIO
+ help
+ If you say yes to this option, support will be included for a
+ GPIO based I2C multiplexer. This driver provides access to
+ I2C busses connected through a MUX, which is controlled
+ through GPIO pins.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-i2cmux.
+
+config I2C_MUX_PCA9541
+ tristate "NXP PCA9541 I2C Master Selector"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for the NXP PCA9541
+ I2C Master Selector.
+
+ This driver can also be built as a module. If so, the module
+ will be called pca9541.
+
+config I2C_MUX_PCA954x
+ tristate "Philips PCA954x I2C Mux/switches"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for the Philips PCA954x
+ I2C mux/switch devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called pca954x.
+
+endmenu
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
new file mode 100644
index 00000000..4640436e
--- /dev/null
+++ b/drivers/i2c/muxes/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for multiplexer I2C chip drivers.
+
+obj-$(CONFIG_I2C_MUX_GPIO) += gpio-i2cmux.o
+obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o
+obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
+
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/gpio-i2cmux.c b/drivers/i2c/muxes/gpio-i2cmux.c
new file mode 100644
index 00000000..7b6ce624
--- /dev/null
+++ b/drivers/i2c/muxes/gpio-i2cmux.c
@@ -0,0 +1,184 @@
+/*
+ * I2C multiplexer using GPIO API
+ *
+ * Peter Korsgaard <peter.korsgaard@barco.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/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/gpio-i2cmux.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+struct gpiomux {
+ struct i2c_adapter *parent;
+ struct i2c_adapter **adap; /* child busses */
+ struct gpio_i2cmux_platform_data data;
+};
+
+static void gpiomux_set(const struct gpiomux *mux, unsigned val)
+{
+ int i;
+
+ for (i = 0; i < mux->data.n_gpios; i++)
+ gpio_set_value(mux->data.gpios[i], val & (1 << i));
+}
+
+static int gpiomux_select(struct i2c_adapter *adap, void *data, u32 chan)
+{
+ struct gpiomux *mux = data;
+
+ gpiomux_set(mux, mux->data.values[chan]);
+
+ return 0;
+}
+
+static int gpiomux_deselect(struct i2c_adapter *adap, void *data, u32 chan)
+{
+ struct gpiomux *mux = data;
+
+ gpiomux_set(mux, mux->data.idle);
+
+ return 0;
+}
+
+static int __devinit gpiomux_probe(struct platform_device *pdev)
+{
+ struct gpiomux *mux;
+ struct gpio_i2cmux_platform_data *pdata;
+ struct i2c_adapter *parent;
+ int (*deselect) (struct i2c_adapter *, void *, u32);
+ unsigned initial_state;
+ int i, ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -ENODEV;
+ }
+
+ parent = i2c_get_adapter(pdata->parent);
+ if (!parent) {
+ dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
+ pdata->parent);
+ return -ENODEV;
+ }
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ mux->parent = parent;
+ mux->data = *pdata;
+ mux->adap = kzalloc(sizeof(struct i2c_adapter *) * pdata->n_values,
+ GFP_KERNEL);
+ if (!mux->adap) {
+ ret = -ENOMEM;
+ goto alloc_failed2;
+ }
+
+ if (pdata->idle != GPIO_I2CMUX_NO_IDLE) {
+ initial_state = pdata->idle;
+ deselect = gpiomux_deselect;
+ } else {
+ initial_state = pdata->values[0];
+ deselect = NULL;
+ }
+
+ for (i = 0; i < pdata->n_gpios; i++) {
+ ret = gpio_request(pdata->gpios[i], "gpio-i2cmux");
+ if (ret)
+ goto err_request_gpio;
+ gpio_direction_output(pdata->gpios[i],
+ initial_state & (1 << i));
+ }
+
+ for (i = 0; i < pdata->n_values; i++) {
+ u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0;
+
+ mux->adap[i] = i2c_add_mux_adapter(parent, mux, nr, i,
+ gpiomux_select, deselect);
+ if (!mux->adap[i]) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
+ goto add_adapter_failed;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d port mux on %s adapter\n",
+ pdata->n_values, parent->name);
+
+ platform_set_drvdata(pdev, mux);
+
+ return 0;
+
+add_adapter_failed:
+ for (; i > 0; i--)
+ i2c_del_mux_adapter(mux->adap[i - 1]);
+ i = pdata->n_gpios;
+err_request_gpio:
+ for (; i > 0; i--)
+ gpio_free(pdata->gpios[i - 1]);
+ kfree(mux->adap);
+alloc_failed2:
+ kfree(mux);
+alloc_failed:
+ i2c_put_adapter(parent);
+
+ return ret;
+}
+
+static int __devexit gpiomux_remove(struct platform_device *pdev)
+{
+ struct gpiomux *mux = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < mux->data.n_values; i++)
+ i2c_del_mux_adapter(mux->adap[i]);
+
+ for (i = 0; i < mux->data.n_gpios; i++)
+ gpio_free(mux->data.gpios[i]);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_put_adapter(mux->parent);
+ kfree(mux->adap);
+ kfree(mux);
+
+ return 0;
+}
+
+static struct platform_driver gpiomux_driver = {
+ .probe = gpiomux_probe,
+ .remove = __devexit_p(gpiomux_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "gpio-i2cmux",
+ },
+};
+
+static int __init gpiomux_init(void)
+{
+ return platform_driver_register(&gpiomux_driver);
+}
+
+static void __exit gpiomux_exit(void)
+{
+ platform_driver_unregister(&gpiomux_driver);
+}
+
+module_init(gpiomux_init);
+module_exit(gpiomux_exit);
+
+MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
+MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-i2cmux");
diff --git a/drivers/i2c/muxes/pca9541.c b/drivers/i2c/muxes/pca9541.c
new file mode 100644
index 00000000..ed699c5a
--- /dev/null
+++ b/drivers/i2c/muxes/pca9541.c
@@ -0,0 +1,411 @@
+/*
+ * I2C multiplexer driver for PCA9541 bus master selector
+ *
+ * Copyright (c) 2010 Ericsson AB.
+ *
+ * Author: Guenter Roeck <guenter.roeck@ericsson.com>
+ *
+ * Derived from:
+ * pca954x.c
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+/*
+ * The PCA9541 is a bus master selector. It supports two I2C masters connected
+ * to a single slave bus.
+ *
+ * Before each bus transaction, a master has to acquire bus ownership. After the
+ * transaction is complete, bus ownership has to be released. This fits well
+ * into the I2C multiplexer framework, which provides select and release
+ * functions for this purpose. For this reason, this driver is modeled as
+ * single-channel I2C bus multiplexer.
+ *
+ * This driver assumes that the two bus masters are controlled by two different
+ * hosts. If a single host controls both masters, platform code has to ensure
+ * that only one of the masters is instantiated at any given time.
+ */
+
+#define PCA9541_CONTROL 0x01
+#define PCA9541_ISTAT 0x02
+
+#define PCA9541_CTL_MYBUS (1 << 0)
+#define PCA9541_CTL_NMYBUS (1 << 1)
+#define PCA9541_CTL_BUSON (1 << 2)
+#define PCA9541_CTL_NBUSON (1 << 3)
+#define PCA9541_CTL_BUSINIT (1 << 4)
+#define PCA9541_CTL_TESTON (1 << 6)
+#define PCA9541_CTL_NTESTON (1 << 7)
+
+#define PCA9541_ISTAT_INTIN (1 << 0)
+#define PCA9541_ISTAT_BUSINIT (1 << 1)
+#define PCA9541_ISTAT_BUSOK (1 << 2)
+#define PCA9541_ISTAT_BUSLOST (1 << 3)
+#define PCA9541_ISTAT_MYTEST (1 << 6)
+#define PCA9541_ISTAT_NMYTEST (1 << 7)
+
+#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
+#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
+#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS)
+#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON)
+
+/* arbitration timeouts, in jiffies */
+#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */
+#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */
+
+/* arbitration retry delays, in us */
+#define SELECT_DELAY_SHORT 50
+#define SELECT_DELAY_LONG 1000
+
+struct pca9541 {
+ struct i2c_adapter *mux_adap;
+ unsigned long select_timeout;
+ unsigned long arb_timeout;
+};
+
+static const struct i2c_device_id pca9541_id[] = {
+ {"pca9541", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pca9541_id);
+
+/*
+ * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock the adapter a second time.
+ */
+static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int ret;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg;
+ char buf[2];
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ buf[0] = command;
+ buf[1] = val;
+ msg.buf = buf;
+ ret = adap->algo->master_xfer(adap, &msg, 1);
+ } else {
+ union i2c_smbus_data data;
+
+ data.byte = val;
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_WRITE,
+ command,
+ I2C_SMBUS_BYTE_DATA, &data);
+ }
+
+ return ret;
+}
+
+/*
+ * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock adapter a second time.
+ */
+static int pca9541_reg_read(struct i2c_client *client, u8 command)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int ret;
+ u8 val;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &command
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &val
+ }
+ };
+ ret = adap->algo->master_xfer(adap, msg, 2);
+ if (ret == 2)
+ ret = val;
+ else if (ret >= 0)
+ ret = -EIO;
+ } else {
+ union i2c_smbus_data data;
+
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_READ,
+ command,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (!ret)
+ ret = data.byte;
+ }
+ return ret;
+}
+
+/*
+ * Arbitration management functions
+ */
+
+/* Release bus. Also reset NTESTON and BUSINIT if it was set. */
+static void pca9541_release_bus(struct i2c_client *client)
+{
+ int reg;
+
+ reg = pca9541_reg_read(client, PCA9541_CONTROL);
+ if (reg >= 0 && !busoff(reg) && mybus(reg))
+ pca9541_reg_write(client, PCA9541_CONTROL,
+ (reg & PCA9541_CTL_NBUSON) >> 1);
+}
+
+/*
+ * Arbitration is defined as a two-step process. A bus master can only activate
+ * the slave bus if it owns it; otherwise it has to request ownership first.
+ * This multi-step process ensures that access contention is resolved
+ * gracefully.
+ *
+ * Bus Ownership Other master Action
+ * state requested access
+ * ----------------------------------------------------
+ * off - yes wait for arbitration timeout or
+ * for other master to drop request
+ * off no no take ownership
+ * off yes no turn on bus
+ * on yes - done
+ * on no - wait for arbitration timeout or
+ * for other master to release bus
+ *
+ * The main contention point occurs if the slave bus is off and both masters
+ * request ownership at the same time. In this case, one master will turn on
+ * the slave bus, believing that it owns it. The other master will request
+ * bus ownership. Result is that the bus is turned on, and master which did
+ * _not_ own the slave bus before ends up owning it.
+ */
+
+/* Control commands per PCA9541 datasheet */
+static const u8 pca9541_control[16] = {
+ 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1
+};
+
+/*
+ * Channel arbitration
+ *
+ * Return values:
+ * <0: error
+ * 0 : bus not acquired
+ * 1 : bus acquired
+ */
+static int pca9541_arbitrate(struct i2c_client *client)
+{
+ struct pca9541 *data = i2c_get_clientdata(client);
+ int reg;
+
+ reg = pca9541_reg_read(client, PCA9541_CONTROL);
+ if (reg < 0)
+ return reg;
+
+ if (busoff(reg)) {
+ int istat;
+ /*
+ * Bus is off. Request ownership or turn it on unless
+ * other master requested ownership.
+ */
+ istat = pca9541_reg_read(client, PCA9541_ISTAT);
+ if (!(istat & PCA9541_ISTAT_NMYTEST)
+ || time_is_before_eq_jiffies(data->arb_timeout)) {
+ /*
+ * Other master did not request ownership,
+ * or arbitration timeout expired. Take the bus.
+ */
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ pca9541_control[reg & 0x0f]
+ | PCA9541_CTL_NTESTON);
+ data->select_timeout = SELECT_DELAY_SHORT;
+ } else {
+ /*
+ * Other master requested ownership.
+ * Set extra long timeout to give it time to acquire it.
+ */
+ data->select_timeout = SELECT_DELAY_LONG * 2;
+ }
+ } else if (mybus(reg)) {
+ /*
+ * Bus is on, and we own it. We are done with acquisition.
+ * Reset NTESTON and BUSINIT, then return success.
+ */
+ if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT))
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ reg & ~(PCA9541_CTL_NTESTON
+ | PCA9541_CTL_BUSINIT));
+ return 1;
+ } else {
+ /*
+ * Other master owns the bus.
+ * If arbitration timeout has expired, force ownership.
+ * Otherwise request it.
+ */
+ data->select_timeout = SELECT_DELAY_LONG;
+ if (time_is_before_eq_jiffies(data->arb_timeout)) {
+ /* Time is up, take the bus and reset it. */
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ pca9541_control[reg & 0x0f]
+ | PCA9541_CTL_BUSINIT
+ | PCA9541_CTL_NTESTON);
+ } else {
+ /* Request bus ownership if needed */
+ if (!(reg & PCA9541_CTL_NTESTON))
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ reg | PCA9541_CTL_NTESTON);
+ }
+ }
+ return 0;
+}
+
+static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+{
+ struct pca9541 *data = i2c_get_clientdata(client);
+ int ret;
+ unsigned long timeout = jiffies + ARB2_TIMEOUT;
+ /* give up after this time */
+
+ data->arb_timeout = jiffies + ARB_TIMEOUT;
+ /* force bus ownership after this time */
+
+ do {
+ ret = pca9541_arbitrate(client);
+ if (ret)
+ return ret < 0 ? ret : 0;
+
+ if (data->select_timeout == SELECT_DELAY_SHORT)
+ udelay(data->select_timeout);
+ else
+ msleep(data->select_timeout / 1000);
+ } while (time_is_after_eq_jiffies(timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int pca9541_release_chan(struct i2c_adapter *adap,
+ void *client, u32 chan)
+{
+ pca9541_release_bus(client);
+ return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int pca9541_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct pca954x_platform_data *pdata = client->dev.platform_data;
+ struct pca9541 *data;
+ int force;
+ int ret = -ENODEV;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto err;
+
+ data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ i2c_set_clientdata(client, data);
+
+ /*
+ * I2C accesses are unprotected here.
+ * We have to lock the adapter before releasing the bus.
+ */
+ i2c_lock_adapter(adap);
+ pca9541_release_bus(client);
+ i2c_unlock_adapter(adap);
+
+ /* Create mux adapter */
+
+ force = 0;
+ if (pdata)
+ force = pdata->modes[0].adap_id;
+ data->mux_adap = i2c_add_mux_adapter(adap, client, force, 0,
+ pca9541_select_chan,
+ pca9541_release_chan);
+
+ if (data->mux_adap == NULL) {
+ dev_err(&client->dev, "failed to register master selector\n");
+ goto exit_free;
+ }
+
+ dev_info(&client->dev, "registered master selector for I2C %s\n",
+ client->name);
+
+ return 0;
+
+exit_free:
+ kfree(data);
+err:
+ return ret;
+}
+
+static int pca9541_remove(struct i2c_client *client)
+{
+ struct pca9541 *data = i2c_get_clientdata(client);
+
+ i2c_del_mux_adapter(data->mux_adap);
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver pca9541_driver = {
+ .driver = {
+ .name = "pca9541",
+ .owner = THIS_MODULE,
+ },
+ .probe = pca9541_probe,
+ .remove = pca9541_remove,
+ .id_table = pca9541_id,
+};
+
+static int __init pca9541_init(void)
+{
+ return i2c_add_driver(&pca9541_driver);
+}
+
+static void __exit pca9541_exit(void)
+{
+ i2c_del_driver(&pca9541_driver);
+}
+
+module_init(pca9541_init);
+module_exit(pca9541_exit);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
new file mode 100644
index 00000000..6f895366
--- /dev/null
+++ b/drivers/i2c/muxes/pca954x.c
@@ -0,0 +1,302 @@
+/*
+ * I2C multiplexer
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This module supports the PCA954x series of I2C multiplexer/switch chips
+ * made by Philips Semiconductors.
+ * This includes the:
+ * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
+ * and PCA9548.
+ *
+ * These chips are all controlled via the I2C bus itself, and all have a
+ * single 8-bit register. The upstream "parent" bus fans out to two,
+ * four, or eight downstream busses or channels; which of these
+ * are selected is determined by the chip type and register contents. A
+ * mux can select only one sub-bus at a time; a switch can select any
+ * combination simultaneously.
+ *
+ * Based on:
+ * pca954x.c from Kumar Gala <galak@kernel.crashing.org>
+ * Copyright (C) 2006
+ *
+ * Based on:
+ * pca954x.c from Ken Harrenstien
+ * Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
+ *
+ * Based on:
+ * i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
+ * and
+ * pca9540.c from Jean Delvare <khali@linux-fr.org>.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+#define PCA954X_MAX_NCHANS 8
+
+enum pca_type {
+ pca_9540,
+ pca_9542,
+ pca_9543,
+ pca_9544,
+ pca_9545,
+ pca_9546,
+ pca_9547,
+ pca_9548,
+};
+
+struct pca954x {
+ enum pca_type type;
+ struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
+
+ u8 last_chan; /* last register value */
+};
+
+struct chip_desc {
+ u8 nchans;
+ u8 enable; /* used for muxes only */
+ enum muxtype {
+ pca954x_ismux = 0,
+ pca954x_isswi
+ } muxtype;
+};
+
+/* Provide specs for the PCA954x types we know about */
+static const struct chip_desc chips[] = {
+ [pca_9540] = {
+ .nchans = 2,
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9543] = {
+ .nchans = 2,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9544] = {
+ .nchans = 4,
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9545] = {
+ .nchans = 4,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9547] = {
+ .nchans = 8,
+ .enable = 0x8,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9548] = {
+ .nchans = 8,
+ .muxtype = pca954x_isswi,
+ },
+};
+
+static const struct i2c_device_id pca954x_id[] = {
+ { "pca9540", pca_9540 },
+ { "pca9542", pca_9540 },
+ { "pca9543", pca_9543 },
+ { "pca9544", pca_9544 },
+ { "pca9545", pca_9545 },
+ { "pca9546", pca_9545 },
+ { "pca9547", pca_9547 },
+ { "pca9548", pca_9548 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pca954x_id);
+
+/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ for this as they will try to lock adapter a second time */
+static int pca954x_reg_write(struct i2c_adapter *adap,
+ struct i2c_client *client, u8 val)
+{
+ int ret = -ENODEV;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg;
+ char buf[1];
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 1;
+ buf[0] = val;
+ msg.buf = buf;
+ ret = adap->algo->master_xfer(adap, &msg, 1);
+ } else {
+ union i2c_smbus_data data;
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_WRITE,
+ val, I2C_SMBUS_BYTE, &data);
+ }
+
+ return ret;
+}
+
+static int pca954x_select_chan(struct i2c_adapter *adap,
+ void *client, u32 chan)
+{
+ struct pca954x *data = i2c_get_clientdata(client);
+ const struct chip_desc *chip = &chips[data->type];
+ u8 regval;
+ int ret = 0;
+
+ /* we make switches look like muxes, not sure how to be smarter */
+ if (chip->muxtype == pca954x_ismux)
+ regval = chan | chip->enable;
+ else
+ regval = 1 << chan;
+
+ /* Only select the channel if its different from the last channel */
+ if (data->last_chan != regval) {
+ ret = pca954x_reg_write(adap, client, regval);
+ data->last_chan = regval;
+ }
+
+ return ret;
+}
+
+static int pca954x_deselect_mux(struct i2c_adapter *adap,
+ void *client, u32 chan)
+{
+ struct pca954x *data = i2c_get_clientdata(client);
+
+ /* Deselect active channel */
+ data->last_chan = 0;
+ return pca954x_reg_write(adap, client, data->last_chan);
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int pca954x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ struct pca954x_platform_data *pdata = client->dev.platform_data;
+ int num, force;
+ struct pca954x *data;
+ int ret = -ENODEV;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
+ goto err;
+
+ data = kzalloc(sizeof(struct pca954x), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ i2c_set_clientdata(client, data);
+
+ /* Write the mux register at addr to verify
+ * that the mux is in fact present. This also
+ * initializes the mux to disconnected state.
+ */
+ if (i2c_smbus_write_byte(client, 0) < 0) {
+ dev_warn(&client->dev, "probe failed\n");
+ goto exit_free;
+ }
+
+ data->type = id->driver_data;
+ data->last_chan = 0; /* force the first selection */
+
+ /* Now create an adapter for each channel */
+ for (num = 0; num < chips[data->type].nchans; num++) {
+ force = 0; /* dynamic adap number */
+ if (pdata) {
+ if (num < pdata->num_modes)
+ /* force static number */
+ force = pdata->modes[num].adap_id;
+ else
+ /* discard unconfigured channels */
+ break;
+ }
+
+ data->virt_adaps[num] =
+ i2c_add_mux_adapter(adap, client,
+ force, num, pca954x_select_chan,
+ (pdata && pdata->modes[num].deselect_on_exit)
+ ? pca954x_deselect_mux : NULL);
+
+ if (data->virt_adaps[num] == NULL) {
+ ret = -ENODEV;
+ dev_err(&client->dev,
+ "failed to register multiplexed adapter"
+ " %d as bus %d\n", num, force);
+ goto virt_reg_failed;
+ }
+ }
+
+ dev_info(&client->dev,
+ "registered %d multiplexed busses for I2C %s %s\n",
+ num, chips[data->type].muxtype == pca954x_ismux
+ ? "mux" : "switch", client->name);
+
+ return 0;
+
+virt_reg_failed:
+ for (num--; num >= 0; num--)
+ i2c_del_mux_adapter(data->virt_adaps[num]);
+exit_free:
+ kfree(data);
+err:
+ return ret;
+}
+
+static int pca954x_remove(struct i2c_client *client)
+{
+ struct pca954x *data = i2c_get_clientdata(client);
+ const struct chip_desc *chip = &chips[data->type];
+ int i, err;
+
+ for (i = 0; i < chip->nchans; ++i)
+ if (data->virt_adaps[i]) {
+ err = i2c_del_mux_adapter(data->virt_adaps[i]);
+ if (err)
+ return err;
+ data->virt_adaps[i] = NULL;
+ }
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver pca954x_driver = {
+ .driver = {
+ .name = "pca954x",
+ .owner = THIS_MODULE,
+ },
+ .probe = pca954x_probe,
+ .remove = pca954x_remove,
+ .id_table = pca954x_id,
+};
+
+static int __init pca954x_init(void)
+{
+ return i2c_add_driver(&pca954x_driver);
+}
+
+static void __exit pca954x_exit(void)
+{
+ i2c_del_driver(&pca954x_driver);
+}
+
+module_init(pca954x_init);
+module_exit(pca954x_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
+MODULE_LICENSE("GPL v2");