summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/i2c
diff options
context:
space:
mode:
authorKevin2014-11-15 10:00:36 +0800
committerKevin2014-11-15 10:00:36 +0800
commit9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch)
treede942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/i2c
parent392e8802486cb573b916e746010e141a75f507e6 (diff)
downloadFOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.gz
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.bz2
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.zip
add via modify part source code for wm8880 4.4 kitkat
Diffstat (limited to 'ANDROID_3.4.5/drivers/i2c')
-rw-r--r--ANDROID_3.4.5/drivers/i2c/Kconfig8
-rw-r--r--ANDROID_3.4.5/drivers/i2c/Makefile1
-rw-r--r--ANDROID_3.4.5/drivers/i2c/algos/Kconfig8
-rw-r--r--ANDROID_3.4.5/drivers/i2c/algos/Makefile1
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/algos/wmt-i2c-algo.c308
-rw-r--r--ANDROID_3.4.5/drivers/i2c/busses/Kconfig21
-rw-r--r--ANDROID_3.4.5/drivers/i2c/busses/Makefile2
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-1.c1294
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-2.c1253
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-3.c1256
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-4.c1274
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus.c1254
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus-1.c661
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.c662
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.h24
-rwxr-xr-xANDROID_3.4.5/drivers/i2c/i2c-api.c216
16 files changed, 8243 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/i2c/Kconfig b/ANDROID_3.4.5/drivers/i2c/Kconfig
index 5f13c62e..dd2ba673 100644
--- a/ANDROID_3.4.5/drivers/i2c/Kconfig
+++ b/ANDROID_3.4.5/drivers/i2c/Kconfig
@@ -46,6 +46,14 @@ config I2C_CHARDEV
This support is also available as a module. If so, the module
will be called i2c-dev.
+
+config I2C_API
+ tristate "I2C API support"
+ help
+ Say Y here if you want to use i2c interface simply in other modules.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-api.
config I2C_MUX
tristate "I2C bus multiplexing support"
diff --git a/ANDROID_3.4.5/drivers/i2c/Makefile b/ANDROID_3.4.5/drivers/i2c/Makefile
index beee6b2d..38b383c4 100644
--- a/ANDROID_3.4.5/drivers/i2c/Makefile
+++ b/ANDROID_3.4.5/drivers/i2c/Makefile
@@ -7,6 +7,7 @@ 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-$(CONFIG_I2C_API) += i2c-api.o
obj-y += algos/ busses/ muxes/
ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/Kconfig b/ANDROID_3.4.5/drivers/i2c/algos/Kconfig
index f1cfe7e5..39b0ade7 100644
--- a/ANDROID_3.4.5/drivers/i2c/algos/Kconfig
+++ b/ANDROID_3.4.5/drivers/i2c/algos/Kconfig
@@ -14,4 +14,12 @@ config I2C_ALGOPCF
config I2C_ALGOPCA
tristate "I2C PCA 9564 interfaces"
+config I2C_ALGOWMT
+ tristate "WMT I2C Algorithm"
+ depends on ARCH_WMT && I2C
+ help
+ This supports the use of the WMT I2C interface found on WMT
+ processors. Say Y if you have one of these. You should also say Y
+ for the WMT I2C peripheral driver support below.
+
endmenu
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/Makefile b/ANDROID_3.4.5/drivers/i2c/algos/Makefile
index 215303f6..d26856d2 100644
--- a/ANDROID_3.4.5/drivers/i2c/algos/Makefile
+++ b/ANDROID_3.4.5/drivers/i2c/algos/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
+obj-$(CONFIG_I2C_WMT) += wmt-i2c-algo.o
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/wmt-i2c-algo.c b/ANDROID_3.4.5/drivers/i2c/algos/wmt-i2c-algo.c
new file mode 100755
index 00000000..3be850d2
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/wmt-i2c-algo.c
@@ -0,0 +1,308 @@
+/*++
+ drivers/i2c/algos/wmt_i2c_algo.c
+
+ Copyright (c) 2008 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#define WMT_I2C_ALGO_C
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+/*
+#include <linux/i2c-id.h>
+*/
+
+#include <mach/hardware.h>
+#include <mach/wmt-i2c-bus.h>
+
+#ifdef __KERNEL__
+
+#ifdef DEBUG
+ #define DPRINTK printk
+#else
+ #define DPRINTK(x...)
+#endif
+
+#else
+#define DPRINTK printf
+
+#endif
+
+static struct i2c_adapter *wmt_i2c_adap[5];
+
+/*!*************************************************************************
+* wmt_i2c_valid_messages()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief verify the input message
+*
+* \retval 1 if success
+*/
+static int wmt_i2c_valid_messages(
+ struct i2c_msg msgs[], /*!<; //[IN] transfer data */
+ int num /*!<; //[IN] transfer data length */
+)
+{
+ int i;
+ if (num < 1 || num > MAX_MESSAGES) {
+ DPRINTK(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n", MAX_MESSAGES, num);
+ return -EINVAL;
+ }
+
+ /* check consistency of our messages */
+ for (i = 0; i < num; i++) {
+ if (&msgs[i] == NULL) {
+ DPRINTK(KERN_INFO "Msgs is NULL\n");
+ return -EINVAL;
+ } else {
+ if (msgs[i].buf == NULL) {
+ DPRINTK(KERN_INFO "Length is less than zero\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 1;
+}
+/*!*************************************************************************
+* wmt_i2c_do_xfer()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief
+*
+* \retval 0 if success
+*/
+static int wmt_i2c_do_xfer(
+ struct i2c_adapter *i2c_adap, /*!<; //[IN] a pointer point to struct inode */
+ struct i2c_msg msgs[], /*!<; //[IN] transfer data */
+ int num /*!<; //[IN] transfer data length */
+)
+{
+ int i;
+ struct i2c_algo_wmt_data *adap;
+ int ret = 0 ;
+
+ adap = i2c_adap->algo_data;
+
+ /*ret = adap->wait_bus_not_busy();*/
+ for (i = 0 ; i < 10; ++i)
+ ;
+ if (ret < 0)
+ return ret ;
+
+ ret = adap->send_request(msgs, num, 0, 0, 0);
+
+ return ret;
+
+}
+
+/*!*************************************************************************
+* wmt_i2c_xfer()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief Transfer (read/write) data to i2c bus, wmt_i2c_do_xfer will be called to transfer
+*
+* \retval 0 if success
+*/
+static int wmt_i2c_xfer(
+ struct i2c_adapter *i2c_adap, /*!<; //[IN] a pointer point to struct inode */
+ struct i2c_msg msgs[], /*!<; //[IN] transfer data */
+ int num /*!<; //[IN] transfer data length */
+)
+{
+ int ret ;
+ int i ;
+
+ ret = wmt_i2c_valid_messages(msgs, num);
+ if (ret < 0)
+ return ret ;
+
+ for (i = i2c_adap->retries ; i >= 0; i--) {
+
+ ret = wmt_i2c_do_xfer(i2c_adap, msgs, num);
+ if (ret > 0)
+ return ret ;
+ DPRINTK(KERN_INFO"Retrying transmission \n");
+ udelay(100);
+ }
+
+ DPRINTK(KERN_INFO"Retried %i times\n", i2c_adap->retries);
+ return ret;
+
+}
+/*!*************************************************************************
+* wmt_i2c_functionality()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief
+*
+* \retval smbus functionality
+*/
+static u32 wmt_i2c_functionality(
+ struct i2c_adapter *adapter /*!<; //[IN] a pointer point to struct inode */
+)
+{
+ /* Emulate the SMBUS functions*/
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+/*
+ * send i2c_msg into fifo of i2c bus
+ * msg: transfer data content
+ * msg_num:number of transferring msg
+ * bus_id :used to indicate which bus do device want to access
+ */
+int wmt_i2c_transfer(struct i2c_msg* msgs, int msg_num, int bus_id, void (*callback)(void *data), void *data)
+{
+ struct i2c_algo_wmt_data *adap;
+ int ret = 0 ;
+
+ adap = wmt_i2c_adap[bus_id]->algo_data;
+ ret = adap->send_request(msgs, msg_num, 1, callback, data);
+ return ret;
+}
+
+#if 0
+/*!*************************************************************************
+* wmt_i2c_control()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief To set i2c transfer mode
+*
+* \retval 0 if success
+*/
+static int wmt_i2c_control(
+ struct i2c_adapter *i2c_adap, /*!<; //[IN] a pointer point to struct inode */
+ unsigned int cmd, /*!<; //[IN] standard or fast mode */
+ unsigned long arg /*!<; //Not in used, but can't delete */
+)
+{
+ int ret ;
+ struct i2c_algo_wmt_data *adap = i2c_adap->algo_data;
+
+ ret = 0 ;
+ DPRINTK("wmt_i2c_control: cmd = 0x%8.8x \n", cmd);
+
+ switch (cmd) {
+ case I2C_SET_STANDARD_MODE:
+ adap->set_mode(I2C_STANDARD_MODE);
+ break ;
+ case I2C_SET_FAST_MODE:
+ adap->set_mode(I2C_FAST_MODE);
+ break ;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+
+struct i2c_algorithm wmt_i2c_algorithm = {
+ .master_xfer = wmt_i2c_xfer,
+ .functionality = wmt_i2c_functionality,
+};
+/*!*************************************************************************
+* wmt_i2c_add_bus()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief
+*
+* \retval NULL
+*/
+int wmt_i2c_add_bus(struct i2c_adapter *i2c_adap)
+{
+ printk(KERN_INFO"i2c: adding %s.\n", i2c_adap->name);
+
+ i2c_adap->algo = &wmt_i2c_algorithm;
+ wmt_i2c_adap[i2c_adap->nr] = i2c_adap;
+
+ /* register new adapter to i2c module... */
+ /*
+ i2c_add_adapter(i2c_adap);
+ */
+ i2c_add_numbered_adapter(i2c_adap);
+
+ /* adap->reset();*/
+
+ return 0;
+}
+/*!*************************************************************************
+* wmt_i2c_del_bus()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief
+*
+* \retval NULL
+*/
+int wmt_i2c_del_bus(struct i2c_adapter *i2c_adap)
+{
+ int res;
+ res = i2c_del_adapter(i2c_adap);
+ if (res < 0)
+ return res;
+
+ printk(KERN_INFO "i2c: removing %s.\n", i2c_adap->name);
+
+ return 0;
+}
+/*!*************************************************************************
+* wmt_i2c_algo_init()
+*
+* Private Function by Paul Kwong, 2007/1/12
+*/
+/*!
+* \brief
+*
+* \retval NULL
+*/
+static int __init wmt_i2c_algo_init(void)
+{
+ printk(KERN_INFO "i2c: wmt algorithm module loaded.\n");
+ return 0;
+}
+
+EXPORT_SYMBOL(wmt_i2c_add_bus);
+EXPORT_SYMBOL(wmt_i2c_del_bus);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT I2C ALGO Driver");
+MODULE_LICENSE("GPL");
+
+module_init(wmt_i2c_algo_init);
+
+#undef WMT_I2C_ALGO_C
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/Kconfig b/ANDROID_3.4.5/drivers/i2c/busses/Kconfig
index d2c5095d..1bfed463 100644
--- a/ANDROID_3.4.5/drivers/i2c/busses/Kconfig
+++ b/ANDROID_3.4.5/drivers/i2c/busses/Kconfig
@@ -907,4 +907,25 @@ config SCx200_ACB
This support is also available as a module. If so, the module
will be called scx200_acb.
+config I2C_WMT
+ tristate "WonderMedia I2C Interface"
+ depends on ARCH_WMT && I2C && I2C_ALGOWMT
+ help
+ This supports the use of the WMT I2C interface found on the WMT
+ Say Y if you have one of these. You should also say Y for the WMT
+ I2C peripheral driver support below.
+
+ To compile this driver as a module, say M here: the
+ modules will be called i2c-wmt and i2c-algo-wmt.
+config I2C1_WMT
+ bool
+ depends on ARCH_WMT && I2C && I2C_ALGOWMT
+ default y
+config I2C_SLAVE_WMT
+ bool "WonderMedia I2C-SLAVE Interface"
+ depends on ARCH_WMT && I2C_WMT
+ help
+ This supports the use of the WMT I2C SLAVE interface found on the WMT
+ Say Y if you have one of these. You should also say Y for the WMT
+ I2C peripheral driver support below.
endmenu
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/Makefile b/ANDROID_3.4.5/drivers/i2c/busses/Makefile
index 569567b0..20082f63 100644
--- a/ANDROID_3.4.5/drivers/i2c/busses/Makefile
+++ b/ANDROID_3.4.5/drivers/i2c/busses/Makefile
@@ -88,4 +88,6 @@ obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_I2C_WMT) += wmt-i2c-bus.o wmt-i2c-bus-1.o wmt-i2c-bus-2.o wmt-i2c-bus-3.o wmt-i2c-bus-4.o
+obj-$(CONFIG_I2C_SLAVE_WMT) += wmt-i2c-slave-bus.o wmt-i2c-slave-bus-1.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-1.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-1.c
new file mode 100755
index 00000000..3fd0f5a3
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-1.c
@@ -0,0 +1,1294 @@
+/*++
+ drivers/i2c/busses/wmt_i2c_bus-1.c
+
+ Copyright (c) 2013 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+/* Include your headers here*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+/*
+#include <linux/i2c-id.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 <mach/hardware.h>
+#include <asm/irq.h>
+#include <mach/irqs.h>
+#include <mach/wmt-i2c-bus.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/syscore_ops.h>
+
+#ifdef __KERNEL__
+
+#ifdef DEBUG
+ #define DPRINTK printk
+#else
+ #define DPRINTK(x...)
+#endif
+
+#else
+ #define DPRINTK printf
+
+#endif
+
+
+#define MAX_BUS_READY_CNT 50 /* jiffy*/
+#define MAX_TX_TIMEOUT 500 /* ms*/
+#define MAX_RX_TIMEOUT 500 /* ms*/
+#define CTRL_GPIO GPIO_CTRL_GP17_I2C_BYTE_ADDR
+#define PU_EN_GPIO PULL_EN_GP17_I2C_BYTE_ADDR
+#define PU_CTRL_GPIO PULL_CTRL_GP17_I2C_BYTE_ADDR
+
+#define USE_UBOOT_PARA
+
+struct wmt_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int volatile isr_nack ;
+ int volatile isr_byte_end ;
+ int volatile isr_timeout ;
+ int volatile isr_int_pending ;
+};
+
+static int i2c_wmt_wait_bus_not_busy(void);
+static int i2c_wmt_wait_bus_release(void);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int speed_mode = 0;
+unsigned int wmt_i2c1_speed_mode = 0;
+static unsigned int is_master = 1;/*master:1, slave:0*/
+unsigned int wmt_i2c1_is_master = 1;
+static unsigned int wmt_i2c1_power_state = 0;/*0:power on, 1:suspend, 2:shutdown*/
+EXPORT_SYMBOL(wmt_i2c1_is_master);
+
+/**/
+/* variable*/
+/*-------------------------------------------------*/
+static volatile struct wmt_i2c_s i2c ;
+
+DECLARE_WAIT_QUEUE_HEAD(i2c_wait);
+/*
+spinlock_t i2c_wmt_irqlock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_wmt_irqlock);
+static struct list_head wmt_i2c_fifohead;
+/*
+static spinlock_t i2c_fifolock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_fifolock);
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+
+static void i2c_wmt_set_mode(enum i2c_mode_e mode /*!<; //[IN] mode */)
+{
+ if (is_master == 0)
+ return;
+ i2c.i2c_mode = mode ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ DPRINTK("I2C: set standard mode \n");
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ DPRINTK("I2C: set fast mode \n");
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+ }
+}
+
+
+static int i2c_send_request(
+ struct i2c_msg *msg,
+ int msg_num,
+ int non_block,
+ void (*callback)(void *data),
+ void *data
+)
+{
+ struct wmt_i2cbusfifo *i2c_fifo_head;
+ struct i2c_msg *pmsg = NULL;
+ int ret = 0;
+ int restart = 0;
+ int last = 0;
+ unsigned long flags;
+ int slave_addr = msg[0].addr;
+
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (wmt_i2c1_power_state == 2) {
+ printk("I2C1 has been shutdown\n");
+ return -EIO;
+ }
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ if (non_block == 0)
+ i2c.isr_int_pending = 0;
+
+ i2c_fifo_head = kzalloc(sizeof(struct wmt_i2cbusfifo), GFP_ATOMIC);
+ if (!i2c_fifo_head) {
+ pr_err("%s: kzalloc fail\n", __func__);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&i2c_fifo_head->busfifohead);
+
+ pmsg = &msg[0];
+ i2c_fifo_head->msg = pmsg;
+ i2c_fifo_head->msg_num = msg_num;
+
+ if (list_empty(&wmt_i2c_fifohead)) {
+ if (i2c_wmt_wait_bus_release()) {
+ kfree(i2c_fifo_head);
+ printk("i2c1 bus has been pull down by slave\n");
+ return -EIO;
+ }
+ }
+
+ spin_lock_irqsave(&i2c_fifolock, flags);
+ if (list_empty(&wmt_i2c_fifohead)) {
+ i2c_wmt_wait_bus_not_busy();
+ pmsg = &msg[0];
+ i2c_fifo_head->xfer_length = 1;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ if (pmsg->flags & I2C_M_RD) {
+ i2c_fifo_head->xfer_length = 1;
+ ret = i2c_wmt_read_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ } else {
+ i2c_fifo_head->xfer_length = 1;
+ if (pmsg->flags & I2C_M_NOSTART)
+ i2c_fifo_head->restart = 1;
+ else
+ i2c_fifo_head->restart = 0;
+ ret = i2c_wmt_write_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ }
+
+ } else {
+ i2c_fifo_head->xfer_length = 0;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ }
+ spin_unlock_irqrestore(&i2c_fifolock, flags);
+ if (non_block == 0) {
+ wait_event(i2c_wait, i2c.isr_int_pending);
+#if 0
+ if(wait_event_timeout(i2c_wait, i2c.isr_int_pending, HZ) == 0) {
+ fifo_head = list_first_entry(&wmt_i2c_fifohead, struct wmt_i2cbusfifo, busfifohead);
+ if( fifo_head ){
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ fifo_head = NULL;
+ }
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->cr_reg |= I2C_CR_ENABLE ;
+ return -ETIMEDOUT;
+ }
+#endif
+ ret = msg_num;
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ }
+
+ }
+
+ return ret;
+
+
+}
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value;
+ int ret = 0;
+
+ DPRINTK("[%s]:length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ tcr_value = 0 ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+ return ret;
+}
+
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int ret = 0 ;
+
+ DPRINTK("[%s]length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ ret = 0 ;
+ return ret;
+
+}
+static int i2c_wmt_read_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete read */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result = 0 ;
+
+ if (is_master == 0)
+ return -ENXIO;
+ if (length <= 0)
+ return -1 ;
+ xfer_length = 0 ;
+
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ ret = 0 ;
+ for (; ;) {
+ is_timeout = 0 ;
+ wait_event_result = wait_event_interruptible_timeout(i2c_wait, i2c.isr_int_pending ,
+ (MAX_RX_TIMEOUT * HZ / 1000)) ;
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (rx) \n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (rx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err: write software timeout error (rx) \n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ buf[xfer_length] = (i2c.regs->cdr_reg >> 8) ;
+ ++xfer_length ;
+ DPRINTK("i2c_test: received BYTE_END\n\r");
+ }
+ i2c.isr_int_pending = 0;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+ if (length > xfer_length) {
+ if ((length - 1) == xfer_length) { /* next read is the last one*/
+ i2c.regs->cr_reg |= (I2C_CR_TX_NEXT_NO_ACK | I2C_CR_CPU_RDY);
+ DPRINTK("i2c_test: set CPU_RDY & TX_ACK. next data is last.\r\n");
+ } else {
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ DPRINTK("i2c_test: more data to read. only set CPU_RDY. \r\n");
+ }
+ } else if (length == xfer_length) { /* end rx xfer*/
+ if (last == 1) { /* stop case*/
+ DPRINTK("i2c_test: read completed \r\n");
+ break ;
+ } else { /* restart case*/
+ /* ??? how to handle the restart after read ?*/
+ DPRINTK("i2c_test: RX ReStart Case \r\n") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : read known error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ }
+
+ DPRINTK("i2c_test: read sequence completed\n\r");
+ return ret ;
+}
+
+static int i2c_wmt_write_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete write */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result ;
+
+ DPRINTK("length = %d , slave_addr = %x\n", length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+
+ ret = 0 ;
+ for (; ;) {
+
+ is_timeout = 0 ;
+ /**/
+ /* I2C: Wait for interrupt. if ( i2c.isr_int_pending == 1 ) ==> an interrupt exsits.*/
+ /**/
+ wait_event_result = wait_event_interruptible_timeout(i2c_wait, i2c.isr_int_pending , (MAX_TX_TIMEOUT * HZ / 1000)) ;
+
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (tx)\n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (tx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (tx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (tx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err : write software timeout error (tx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ DPRINTK("i2c: isr end byte (tx)\n\r") ;
+ ++xfer_length ;
+ }
+ i2c.isr_int_pending = 0 ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+
+ if ((i2c.regs->csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK) {
+ DPRINTK("i2c_err : write RCV NACK error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0) {
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ break ;
+ }
+ if (length > xfer_length) {
+ i2c.regs->cdr_reg = (unsigned short) (buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+ i2c.regs->cr_reg = (I2C_CR_CPU_RDY | I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: write register data \n\r") ;
+ } else if (length == xfer_length) { /* end tx xfer*/
+ if (last == 1) { /* stop case*/
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: finish write \n\r") ;
+ break ;
+ } else { /* restart case*/
+ /* handle the restart for first write then the next is read*/
+ i2c.regs->cr_reg = (I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: tx restart Case \n\r") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : write unknown error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ } ;
+
+ DPRINTK("i2c_test: write sequence completed\n\r");
+
+ return ret ;
+}
+
+static int i2c_wmt_wait_bus_not_busy(void)
+{
+ int ret ;
+ int cnt ;
+
+ ret = 0 ;
+ cnt = 0 ;
+ while (1) {
+ if ((REG16_VAL(I2C1_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY) {
+ ret = 0;
+ break ;
+ }
+ cnt++ ;
+
+ if (cnt > MAX_BUS_READY_CNT) {
+ ret = (-EBUSY) ;
+ printk("i2c_err : wait but not ready time-out\n\r") ;
+ cnt = 0;
+ break;
+ }
+ }
+ return ret ;
+}
+
+static int i2c_wmt_wait_bus_release(void)
+{
+ int val, cnt = 0;
+ while(1) {
+ val = REG8_VAL(__GPIO_BASE + 0x0011);
+ if (0x0c == (val & 0x0c))
+ return 0;
+ udelay(1);
+ cnt ++;
+ if (cnt > 5000) {
+ return -ETIMEDOUT;
+ }
+ }
+ }
+
+static void i2c_wmt_reset(void)
+{
+ unsigned short tmp ;
+ if (is_master == 0)
+ return;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C1_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C1 ;
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* hardware initial*/
+ /**/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+
+ DPRINTK("Resetting I2C Controller Unit\n");
+
+ return ;
+}
+static int wmt_i2c_transfer_msg(struct wmt_i2cbusfifo *fifo_head)
+{
+ int xfer_length = fifo_head->xfer_length;
+ int xfer_msgnum = fifo_head->xfer_msgnum;
+ struct i2c_msg *pmsg = &fifo_head->msg[xfer_msgnum];
+ int restart = fifo_head->restart;
+ unsigned short tcr_value;
+ unsigned short slave_addr = pmsg->addr;
+ int length = pmsg->len;
+ int ret = 0;
+
+ if (pmsg->flags & I2C_M_RD) {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ } else {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(pmsg->buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ }
+ return ret;
+}
+
+static irqreturn_t i2c_wmt_handler(
+ int this_irq, /*!<; //[IN] IRQ number */
+ void *dev_id /*!<; //[IN] Pointer to device ID */
+)
+{
+ int wakeup ;
+ unsigned short isr_status ;
+ unsigned short tmp ;
+ unsigned long flags;
+ struct wmt_i2cbusfifo *fifo_head;
+ int xfer_length = 0;
+ int xfer_msgnum = 0;
+ struct i2c_msg *pmsg;
+ volatile unsigned short csr_reg;
+
+ spin_lock_irqsave(&i2c_wmt_irqlock, flags);
+ isr_status = i2c.regs->isr_reg ;
+ csr_reg = i2c.regs->csr_reg;
+ wakeup = 0 ;
+ fifo_head = list_first_entry(&wmt_i2c_fifohead, struct wmt_i2cbusfifo, busfifohead);
+
+ if (isr_status & I2C_ISR_NACK_ADDR) {
+ DPRINTK("[%s]:i2c NACK\n", __func__);
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_NACK_ADDR_WRITE_CLEAR ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ }
+
+ if ((isr_status & I2C_ISR_BYTE_END && ((csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK))) {
+ /*
+ printk("data rcv nack\n");
+ */
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ } else if (isr_status & I2C_ISR_BYTE_END) {
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_byte_end = 1 ;
+ xfer_length = fifo_head->xfer_length;
+ xfer_msgnum = fifo_head->xfer_msgnum;
+ pmsg = &fifo_head->msg[xfer_msgnum];
+
+ /*read case*/
+ if (pmsg->flags & I2C_M_RD) {
+ pmsg->buf[xfer_length - 1] = (i2c.regs->cdr_reg >> 8) ;
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len - 1) {
+ /*last msg of the current request?*/
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_TX_NEXT_NO_ACK);
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ } else if (xfer_length == pmsg->len) {/*next msg*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else { /*data of this msg has been transfered*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*next request exist?*/
+ if (list_empty(&wmt_i2c_fifohead)) {/*no more reqeust*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ } else { /*more request*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ fifo_head->xfer_length = 0;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("2 : non callback\n");
+ wakeup = 1;
+ } else {
+ printk("2 :callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ }
+
+ } else { /*write case*/
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len) {
+ /*last msg of the current request?*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ }
+ /*access next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else {/*this request finish*/
+ /*spin_lock(&i2c_fifolock);*/
+ /*next request exist?*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ if (list_empty(&wmt_i2c_fifohead)) {
+ /*kfree(fifo_head);*/
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+
+ } else {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ /*next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("4:non callback\n");
+ wakeup = 1;
+ } else {
+ printk("4:callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ i2c.regs->cdr_reg = (unsigned short) (pmsg->buf[fifo_head->xfer_length] & I2C_CDR_DATA_WRITE_MASK);
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_ENABLE);
+ }
+ }
+ }
+
+ if (isr_status & I2C_ISR_SCL_TIME_OUT) {
+ printk("[%s]I2C1 SCL timeout\n", __func__);
+#if 0
+ i2c.regs->cr_reg |= BIT7;/*reset status*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR | I2C_ISR_BYTE_END_WRITE_CLEAR;
+ i2c.isr_timeout = 1 ;
+ wakeup = 1;
+#endif
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR ;
+ }
+
+
+ if (wakeup) {
+ /*spin_lock_irqsave(&i2c_wmt_irqlock, flags);*/
+ i2c.isr_int_pending = 1;
+ /*spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);*/
+ wake_up(&i2c_wait);
+ } else
+ DPRINTK("i2c_err : unknown I2C ISR Handle 0x%4.4X" , isr_status) ;
+ spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);
+ return IRQ_HANDLED;
+}
+
+static int i2c_wmt_resource_init(void)
+{
+ if (is_master == 0)
+ return 0;
+ if (request_irq(i2c.irq_no , &i2c_wmt_handler, IRQF_DISABLED, "i2c", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C: Failed to register I2C irq %i\n", i2c.irq_no);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void i2c_wmt_resource_release(void)
+{
+ if (is_master == 0)
+ return;
+ free_irq(i2c.irq_no, 0);
+}
+
+static struct i2c_algo_wmt_data i2c_wmt_data = {
+ write_msg: i2c_wmt_write_msg,
+ read_msg: i2c_wmt_read_msg,
+ send_request: i2c_send_request,
+ wait_bus_not_busy: i2c_wmt_wait_bus_not_busy,
+ reset: i2c_wmt_reset,
+ set_mode: i2c_wmt_set_mode,
+ udelay: I2C_ALGO_UDELAY,
+ timeout: I2C_ALGO_TIMEOUT,
+};
+
+static struct i2c_adapter i2c_wmt_ops = {
+ .owner = THIS_MODULE,
+ /*
+ .id = I2C_ALGO_WMT,
+ */
+ .algo_data = &i2c_wmt_data,
+ .name = "wmt_i2c_adapter1",
+ .retries = I2C_ADAPTER_RETRIES,
+ .nr = 1,
+};
+
+#ifdef CONFIG_PM
+static struct i2c_regs_s wmt_i2c_reg ;
+static void i2c_shutdown(void)
+{
+ printk("i2c1 shutdown\n");
+ wmt_i2c1_power_state = 2;
+ while (!list_empty(&wmt_i2c_fifohead))
+ msleep(1);
+ while (1) {/*wait busy clear*/
+ if ((REG16_VAL(I2C1_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY)
+ break ;
+ msleep(1);
+ }
+ return;
+}
+static int i2c_suspend(void)
+{
+ printk("i2c1 suspend\n");
+ wmt_i2c_reg.imr_reg = i2c.regs->imr_reg;
+ wmt_i2c_reg.tr_reg = i2c.regs->tr_reg;
+ wmt_i2c_reg.div_reg = i2c.regs->div_reg;
+ return 0;
+}
+static void i2c_resume(void)
+{
+ printk("i2c1 resume\n");
+ GPIO_CTRL_GP17_I2C_BYTE_VAL &= ~(BIT2 | BIT3);
+ PULL_EN_GP17_I2C_BYTE_VAL |= (BIT2 | BIT3);
+ PULL_CTRL_GP17_I2C_BYTE_VAL |= (BIT2 | BIT3);
+ auto_pll_divisor(DEV_I2C1, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_I2C1, SET_DIV, 2, 20);/*20M Hz*/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = wmt_i2c_reg.div_reg;
+ i2c.regs->imr_reg = wmt_i2c_reg.imr_reg;
+ i2c.regs->tr_reg = wmt_i2c_reg.tr_reg ;
+ i2c.regs->cr_reg = 0x001 ;
+}
+#else
+#define i2c_suspend NULL
+#define i2c_resume NULL
+#define i2c_shutdown NULL
+#endif
+extern int wmt_i2c_add_bus(struct i2c_adapter *);
+extern int wmt_i2c_del_bus(struct i2c_adapter *);
+
+#ifdef CONFIG_PM
+static struct syscore_ops wmt_i2c_syscore_ops =
+{
+ .suspend = i2c_suspend,
+ .resume = i2c_resume,
+ .shutdown = i2c_shutdown,
+};
+#endif
+
+static int __init i2c_adap_wmt_init(void)
+{
+ unsigned short tmp ;
+ char varname[] = "wmt.i2c.param";
+#ifdef CONFIG_I2C_SLAVE_WMT
+ char varname1[] = "wmt.bus.i2c.slave_port";
+#endif
+ unsigned char buf[80];
+ int ret;
+ unsigned int port_num;
+ int idx = 0;
+ int varlen = 80;
+ unsigned int pllb_freq = 0;
+ unsigned int tr_val = 0;
+
+#ifdef CONFIG_I2C_SLAVE_WMT
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname1, buf, &varlen);
+#else
+ ret = 1;
+#endif
+ is_master = 1;
+ if (ret == 0) {
+ ret = sscanf(buf, "%x", &port_num);
+ while (ret) {
+ if (port_num != 1)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret;
+ ret = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+#endif
+ wmt_i2c1_is_master = is_master;
+ if (is_master == 1) {
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname, buf, &varlen);
+#else
+ ret = 1;
+#endif
+
+ if (ret == 0) {
+ ret = sscanf(buf, "%x:%x", &port_num, &speed_mode);
+ idx += 3;
+ while (ret) {
+ if (ret < 2)
+ speed_mode = 0;
+ else {
+ if (port_num != 1)
+ speed_mode = 0;
+ else
+ break;
+ }
+ ret = sscanf(buf + idx, ",%x:%x", &port_num, &speed_mode);
+ idx += 4;
+ }
+ }
+ if (speed_mode > 1)
+ speed_mode = 0;
+ wmt_i2c1_speed_mode = speed_mode;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C1_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C1 ;
+ printk("PORT 1 speed_mode = %d\n", speed_mode);
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else if (speed_mode == 1)
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+ /**/
+ /* hardware initial*/
+ /**/
+ auto_pll_divisor(DEV_I2C1, CLK_ENABLE, 0, 0);
+ pllb_freq = auto_pll_divisor(DEV_I2C1, SET_DIV, 2, 20);/*20M Hz*/
+ if ((pllb_freq%(1000*2*100)) != 0)
+ tr_val = pllb_freq/(1000*2*100) + 1;
+ else
+ tr_val = pllb_freq/(1000*2*100);
+ *(volatile unsigned char *)CTRL_GPIO &= ~(BIT2 | BIT3);
+ *(volatile unsigned char *)PU_EN_GPIO |= (BIT2 | BIT3);
+ *(volatile unsigned char *)PU_CTRL_GPIO |= (BIT2 | BIT3);
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = 0xff00|tr_val;
+ else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tr_val /= 4;
+ i2c.regs->tr_reg = 0xff00|tr_val ;
+ }
+ }
+
+
+ if (i2c_wmt_resource_init() == 0) {
+ if (wmt_i2c_add_bus(&i2c_wmt_ops) < 0) {
+ i2c_wmt_resource_release();
+ printk(KERN_INFO "i2c: Failed to add bus\n");
+ return -ENODEV;
+ }
+ } else
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&wmt_i2c_fifohead);
+
+#ifdef CONFIG_PM
+ register_syscore_ops(&wmt_i2c_syscore_ops);
+#endif
+
+ wmt_i2c1_power_state = 0;
+ printk(KERN_INFO "i2c: successfully added bus\n");
+
+#ifdef I2C_REG_TEST
+ printk("i2c.regs->cr_reg= 0x%08x\n\r", i2c.regs->cr_reg);
+ printk("i2c.regs->tcr_reg= 0x%08x\n\r", i2c.regs->tcr_reg);
+ printk("i2c.regs->csr_reg= 0x%08x\n\r", i2c.regs->csr_reg);
+ printk("i2c.regs->isr_reg= 0x%08x\n\r", i2c.regs->isr_reg);
+ printk("i2c.regs->imr_reg= 0x%08x\n\r", i2c.regs->imr_reg);
+ printk("i2c.regs->cdr_reg= 0x%08x\n\r", i2c.regs->cdr_reg);
+ printk("i2c.regs->tr_reg= 0x%08x\n\r", i2c.regs->tr_reg);
+ printk("i2c.regs->div_reg= 0x%08x\n\r", i2c.regs->div_reg);
+#endif
+
+ return 0;
+}
+subsys_initcall(i2c_adap_wmt_init);
+
+static void i2c_adap_wmt_exit(void)
+{
+ wmt_i2c_del_bus(&i2c_wmt_ops);
+ i2c_wmt_resource_release();
+
+ printk(KERN_INFO "i2c: successfully removed bus\n");
+}
+
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT I2C Adapter Driver");
+MODULE_LICENSE("GPL");
+
+module_exit(i2c_adap_wmt_exit);
+
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-2.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-2.c
new file mode 100755
index 00000000..64f5646c
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-2.c
@@ -0,0 +1,1253 @@
+/*++
+ drivers/i2c/busses/wmt-i2c-bus-2.c
+
+ Copyright (c) 2013 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+/* Include your headers here*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+/*
+#include <linux/i2c-id.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 <mach/hardware.h>
+#include <asm/irq.h>
+#include <mach/irqs.h>
+#include <mach/wmt-i2c-bus.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/syscore_ops.h>
+
+#ifdef __KERNEL__
+
+#ifdef DEBUG
+ #define DPRINTK printk
+#else
+ #define DPRINTK(x...)
+#endif
+
+#else
+ #define DPRINTK printf
+
+#endif
+
+
+#define MAX_BUS_READY_CNT 50 /* jiffy*/
+#define MAX_TX_TIMEOUT 500 /* ms*/
+#define MAX_RX_TIMEOUT 500 /* ms*/
+#define CTRL_GPIO GPIO_CTRL_GP17_I2C_BYTE_ADDR
+#define PU_EN_GPIO PULL_EN_GP17_I2C_BYTE_ADDR
+#define PU_CTRL_GPIO PULL_CTRL_GP17_I2C_BYTE_ADDR
+
+#define USE_UBOOT_PARA
+
+struct wmt_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int volatile isr_nack ;
+ int volatile isr_byte_end ;
+ int volatile isr_timeout ;
+ int volatile isr_int_pending ;
+};
+
+static int i2c_wmt_wait_bus_not_busy(void);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int speed_mode = 1;
+static unsigned int is_master = 1;/*master:1, slave:0*/
+unsigned int wmt_i2c2_is_master = 1;
+unsigned int wmt_i2c2_speed_mode = 0;
+static unsigned int wmt_i2c2_power_state = 0;/*0:power on, 1:suspend, 2:shutdown*/
+EXPORT_SYMBOL(wmt_i2c2_is_master);
+
+/**/
+/* variable*/
+/*-------------------------------------------------*/
+static volatile struct wmt_i2c_s i2c ;
+
+DECLARE_WAIT_QUEUE_HEAD(i2c2_wait);
+/*
+spinlock_t i2c2_wmt_irqlock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c2_wmt_irqlock);
+static struct list_head wmt_i2c_fifohead;
+/*
+static spinlock_t i2c_fifolock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_fifolock);
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+
+static void i2c_wmt_set_mode(enum i2c_mode_e mode /*!<; //[IN] mode */)
+{
+ if (is_master == 0)
+ return;
+ i2c.i2c_mode = mode ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ DPRINTK("I2C: set standard mode \n");
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ DPRINTK("I2C: set fast mode \n");
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+ }
+}
+
+
+static int i2c_send_request(
+ struct i2c_msg *msg,
+ int msg_num,
+ int non_block,
+ void (*callback)(void *data),
+ void *data
+)
+{
+ struct wmt_i2cbusfifo *i2c_fifo_head;
+ struct i2c_msg *pmsg = NULL;
+ int ret = 0;
+ int restart = 0;
+ int last = 0;
+ unsigned long flags;
+ int slave_addr = msg[0].addr;
+
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+ if (wmt_i2c2_power_state == 2) {
+ printk("I2C2 has been shutdown\n");
+ return -EIO;
+ }
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c_fifo_head = kzalloc(sizeof(struct wmt_i2cbusfifo), GFP_ATOMIC);
+ INIT_LIST_HEAD(&i2c_fifo_head->busfifohead);
+
+ pmsg = &msg[0];
+ i2c_fifo_head->msg = pmsg;
+ i2c_fifo_head->msg_num = msg_num;
+
+ spin_lock_irqsave(&i2c_fifolock, flags);
+ if (list_empty(&wmt_i2c_fifohead)) {
+ i2c_wmt_wait_bus_not_busy();
+ pmsg = &msg[0];
+ i2c_fifo_head->xfer_length = 1;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ if (pmsg->flags & I2C_M_RD) {
+ i2c_fifo_head->xfer_length = 1;
+ ret = i2c_wmt_read_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ } else {
+ i2c_fifo_head->xfer_length = 1;
+ if (pmsg->flags & I2C_M_NOSTART)
+ i2c_fifo_head->restart = 1;
+ else
+ i2c_fifo_head->restart = 0;
+ ret = i2c_wmt_write_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ }
+
+ } else {
+ i2c_fifo_head->xfer_length = 0;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ }
+ spin_unlock_irqrestore(&i2c_fifolock, flags);
+ if (non_block == 0) {
+ wait_event(i2c2_wait, i2c.isr_int_pending);
+ ret = msg_num;
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ }
+
+ }
+
+ return ret;
+
+
+}
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value;
+ int ret = 0;
+
+ DPRINTK("[%s]:length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ tcr_value = 0 ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+ return ret;
+}
+
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int ret = 0 ;
+
+ DPRINTK("[%s]length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ ret = 0 ;
+ return ret;
+
+}
+static int i2c_wmt_read_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete read */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result = 0 ;
+
+ if (is_master == 0)
+ return -ENXIO;
+ if (length <= 0)
+ return -1 ;
+ xfer_length = 0 ;
+
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ ret = 0 ;
+ for (; ;) {
+ is_timeout = 0 ;
+ wait_event_result = wait_event_interruptible_timeout(i2c2_wait, i2c.isr_int_pending ,
+ (MAX_RX_TIMEOUT * HZ / 1000)) ;
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (rx) \n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (rx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err: write software timeout error (rx) \n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ buf[xfer_length] = (i2c.regs->cdr_reg >> 8) ;
+ ++xfer_length ;
+ DPRINTK("i2c_test: received BYTE_END\n\r");
+ }
+ i2c.isr_int_pending = 0;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+ if (length > xfer_length) {
+ if ((length - 1) == xfer_length) { /* next read is the last one*/
+ i2c.regs->cr_reg |= (I2C_CR_TX_NEXT_NO_ACK | I2C_CR_CPU_RDY);
+ DPRINTK("i2c_test: set CPU_RDY & TX_ACK. next data is last.\r\n");
+ } else {
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ DPRINTK("i2c_test: more data to read. only set CPU_RDY. \r\n");
+ }
+ } else if (length == xfer_length) { /* end rx xfer*/
+ if (last == 1) { /* stop case*/
+ DPRINTK("i2c_test: read completed \r\n");
+ break ;
+ } else { /* restart case*/
+ /* ??? how to handle the restart after read ?*/
+ DPRINTK("i2c_test: RX ReStart Case \r\n") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : read known error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ }
+
+ DPRINTK("i2c_test: read sequence completed\n\r");
+ return ret ;
+}
+
+static int i2c_wmt_write_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete write */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result ;
+
+ DPRINTK("length = %d , slave_addr = %x\n", length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+
+ ret = 0 ;
+ for (; ;) {
+
+ is_timeout = 0 ;
+ /**/
+ /* I2C: Wait for interrupt. if ( i2c.isr_int_pending == 1 ) ==> an interrupt exsits.*/
+ /**/
+ wait_event_result = wait_event_interruptible_timeout(i2c2_wait, i2c.isr_int_pending , (MAX_TX_TIMEOUT * HZ / 1000)) ;
+
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (tx)\n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (tx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (tx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (tx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err : write software timeout error (tx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ DPRINTK("i2c: isr end byte (tx)\n\r") ;
+ ++xfer_length ;
+ }
+ i2c.isr_int_pending = 0 ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+
+ if ((i2c.regs->csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK) {
+ DPRINTK("i2c_err : write RCV NACK error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0) {
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ break ;
+ }
+ if (length > xfer_length) {
+ i2c.regs->cdr_reg = (unsigned short) (buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+ i2c.regs->cr_reg = (I2C_CR_CPU_RDY | I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: write register data \n\r") ;
+ } else if (length == xfer_length) { /* end tx xfer*/
+ if (last == 1) { /* stop case*/
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: finish write \n\r") ;
+ break ;
+ } else { /* restart case*/
+ /* handle the restart for first write then the next is read*/
+ i2c.regs->cr_reg = (I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: tx restart Case \n\r") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : write unknown error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ } ;
+
+ DPRINTK("i2c_test: write sequence completed\n\r");
+
+ return ret ;
+}
+
+static int i2c_wmt_wait_bus_not_busy(void)
+{
+ int ret ;
+ int cnt ;
+
+ ret = 0 ;
+ cnt = 0 ;
+ while (1) {
+ if ((REG16_VAL(I2C2_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY) {
+ ret = 0;
+ break ;
+ }
+ cnt++ ;
+
+ if (cnt > MAX_BUS_READY_CNT) {
+ ret = (-EBUSY) ;
+ printk("i2c_err 2: wait but not ready time-out\n\r") ;
+ cnt = 0;
+ break;
+ }
+ }
+ return ret ;
+}
+
+static void i2c_wmt_reset(void)
+{
+ unsigned short tmp ;
+ if (is_master == 0)
+ return;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C2_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C2 ;
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* hardware initial*/
+ /**/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+
+ DPRINTK("Resetting I2C Controller Unit\n");
+
+ return ;
+}
+static int wmt_i2c_transfer_msg(struct wmt_i2cbusfifo *fifo_head)
+{
+ int xfer_length = fifo_head->xfer_length;
+ int xfer_msgnum = fifo_head->xfer_msgnum;
+ struct i2c_msg *pmsg = &fifo_head->msg[xfer_msgnum];
+ int restart = fifo_head->restart;
+ unsigned short tcr_value;
+ unsigned short slave_addr = pmsg->addr;
+ int length = pmsg->len;
+ int ret = 0;
+
+ if (pmsg->flags & I2C_M_RD) {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ } else {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(pmsg->buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ }
+ return ret;
+}
+
+static irqreturn_t i2c_wmt_handler(
+ int this_irq, /*!<; //[IN] IRQ number */
+ void *dev_id /*!<; //[IN] Pointer to device ID */
+)
+{
+ int wakeup ;
+ unsigned short isr_status ;
+ unsigned short tmp ;
+ unsigned long flags;
+ struct wmt_i2cbusfifo *fifo_head;
+ int xfer_length = 0;
+ int xfer_msgnum = 0;
+ struct i2c_msg *pmsg;
+ volatile unsigned short csr_reg;
+
+ spin_lock_irqsave(&i2c2_wmt_irqlock, flags);
+ isr_status = i2c.regs->isr_reg ;
+ csr_reg = i2c.regs->csr_reg;
+ wakeup = 0 ;
+ fifo_head = list_first_entry(&wmt_i2c_fifohead, struct wmt_i2cbusfifo, busfifohead);
+
+ if (isr_status & I2C_ISR_NACK_ADDR) {
+ DPRINTK("[%s]:i2c NACK\n", __func__);
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_NACK_ADDR_WRITE_CLEAR ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ }
+
+ if ((isr_status & I2C_ISR_BYTE_END && ((csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK))) {
+ /*
+ printk("data rcv nack\n");
+ */
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ } else if (isr_status & I2C_ISR_BYTE_END) {
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_byte_end = 1 ;
+ xfer_length = fifo_head->xfer_length;
+ xfer_msgnum = fifo_head->xfer_msgnum;
+ pmsg = &fifo_head->msg[xfer_msgnum];
+
+ /*read case*/
+ if (pmsg->flags & I2C_M_RD) {
+ pmsg->buf[xfer_length - 1] = (i2c.regs->cdr_reg >> 8) ;
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len - 1) {
+ /*last msg of the current request?*/
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_TX_NEXT_NO_ACK);
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ } else if (xfer_length == pmsg->len) {/*next msg*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else { /*data of this msg has been transfered*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*next request exist?*/
+ if (list_empty(&wmt_i2c_fifohead)) {/*no more reqeust*/
+ /*kfree(fifo_head);*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ } else { /*more request*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ fifo_head->xfer_length = 0;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("2 : non callback\n");
+ wakeup = 1;
+ } else {
+ printk("2 :callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ }
+
+ } else { /*write case*/
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len) {
+ /*last msg of the current request?*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ }
+ /*access next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else {/*this request finish*/
+ /*spin_lock(&i2c_fifolock);*/
+ /*next request exist?*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ if (list_empty(&wmt_i2c_fifohead)) {
+ /*kfree(fifo_head);*/
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+
+ } else {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ /*next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("4:non callback\n");
+ wakeup = 1;
+ } else {
+ printk("4:callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ i2c.regs->cdr_reg = (unsigned short) (pmsg->buf[fifo_head->xfer_length] & I2C_CDR_DATA_WRITE_MASK);
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_ENABLE);
+ }
+ }
+ }
+
+ if (isr_status & I2C_ISR_SCL_TIME_OUT) {
+ DPRINTK("[%s]SCL timeout\n", __func__);
+#if 0
+ i2c.regs->cr_reg |= BIT7;/*reset status*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR | I2C_ISR_BYTE_END_WRITE_CLEAR;
+ i2c.isr_timeout = 1 ;
+ wakeup = 1;
+#endif
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR ;
+ }
+
+
+ if (wakeup) {
+ /*spin_lock_irqsave(&i2c_wmt_irqlock, flags);*/
+ i2c.isr_int_pending = 1;
+ /*spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);*/
+ wake_up(&i2c2_wait);
+ } else
+ DPRINTK("i2c_err : unknown I2C ISR Handle 0x%4.4X" , isr_status) ;
+ spin_unlock_irqrestore(&i2c2_wmt_irqlock, flags);
+ return IRQ_HANDLED;
+}
+
+static int i2c_wmt_resource_init(void)
+{
+ if (is_master == 0)
+ return 0;
+ if (request_irq(i2c.irq_no , &i2c_wmt_handler, IRQF_DISABLED, "i2c", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C: Failed to register I2C irq %i\n", i2c.irq_no);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void i2c_wmt_resource_release(void)
+{
+ if (is_master == 0)
+ return;
+ free_irq(i2c.irq_no, 0);
+}
+
+static struct i2c_algo_wmt_data i2c_wmt_data = {
+ write_msg: i2c_wmt_write_msg,
+ read_msg: i2c_wmt_read_msg,
+ send_request: i2c_send_request,
+ wait_bus_not_busy: i2c_wmt_wait_bus_not_busy,
+ reset: i2c_wmt_reset,
+ set_mode: i2c_wmt_set_mode,
+ udelay: I2C_ALGO_UDELAY,
+ timeout: I2C_ALGO_TIMEOUT,
+};
+
+static struct i2c_adapter i2c_wmt_ops = {
+ .owner = THIS_MODULE,
+ /*
+ .id = I2C_ALGO_WMT,
+ */
+ .algo_data = &i2c_wmt_data,
+ .name = "wmt_i2c2_adapter",
+ .retries = I2C_ADAPTER_RETRIES,
+ .nr = 2,
+};
+
+#ifdef CONFIG_PM
+static struct i2c_regs_s wmt_i2c_reg ;
+static void i2c_shutdown(void)
+{
+ printk("i2c2 shutdown\n");
+ wmt_i2c2_power_state = 2;
+ while (!list_empty(&wmt_i2c_fifohead))
+ msleep(1);
+ while (1) {/*wait busy clear*/
+ if ((REG16_VAL(I2C2_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY)
+ break ;
+ msleep(1);
+ }
+ return;
+}
+static int i2c_suspend(void)
+{
+ printk("i2c2 suspend\n");
+ wmt_i2c_reg.imr_reg = i2c.regs->imr_reg;
+ wmt_i2c_reg.tr_reg = i2c.regs->tr_reg;
+ wmt_i2c_reg.div_reg = i2c.regs->div_reg;
+ return 0;
+}
+static void i2c_resume(void)
+{
+ printk("i2c2 resume\n");
+ GPIO_CTRL_GP17_I2C_BYTE_VAL &= ~(BIT4 | BIT5);
+ PULL_EN_GP17_I2C_BYTE_VAL |= (BIT4 | BIT5);
+ PULL_CTRL_GP17_I2C_BYTE_VAL |= (BIT4 | BIT5);
+ auto_pll_divisor(DEV_I2C2, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_I2C2, SET_DIV, 2, 20);/*20M Hz*/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = wmt_i2c_reg.div_reg;
+ i2c.regs->imr_reg = wmt_i2c_reg.imr_reg;
+ i2c.regs->tr_reg = wmt_i2c_reg.tr_reg ;
+ i2c.regs->cr_reg = 0x001 ;
+}
+#else
+#define i2c_suspend NULL
+#define i2c_resume NULL
+#define i2c_shutdown NULL
+#endif
+extern int wmt_i2c_add_bus(struct i2c_adapter *);
+extern int wmt_i2c_del_bus(struct i2c_adapter *);
+
+#ifdef CONFIG_PM
+static struct syscore_ops wmt_i2c_syscore_ops = {
+ .suspend = i2c_suspend,
+ .resume = i2c_resume,
+ .shutdown = i2c_shutdown,
+};
+#endif
+
+static int __init i2c_adap_wmt_init(void)
+{
+ unsigned short tmp ;
+ char varname[] = "wmt.i2c.param";
+#ifdef CONFIG_I2C_SLAVE_WMT
+ char varname1[] = "wmt.bus.i2c.slave_port";
+#endif
+ unsigned char buf[80];
+ int ret;
+ unsigned int port_num;
+ int idx = 0;
+ int varlen = 80;
+ unsigned int pllb_freq = 0;
+ unsigned int tr_val = 0;
+
+#ifdef CONFIG_I2C_SLAVE_WMT
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname1, buf, &varlen);
+#else
+ ret = 1;
+#endif
+ is_master = 1;
+ if (ret == 0) {
+ ret = sscanf(buf, "%x", &port_num);
+ while (ret) {
+ if (port_num != 0)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret;
+ ret = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+#endif
+ wmt_i2c2_is_master = is_master;
+ if (is_master == 1) {
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname, buf, &varlen);
+#else
+ ret = 1;
+#endif
+
+ if (ret == 0) {
+ ret = sscanf(buf, "%x:%x", &port_num, &speed_mode);
+ idx += 3;
+ while (ret) {
+ if (ret < 2)
+ speed_mode = 0;
+ else {
+ if (port_num != 2)
+ speed_mode = 0;
+ else
+ break;
+ }
+ ret = sscanf(buf + idx, ",%x:%x", &port_num, &speed_mode);
+ idx += 4;
+ }
+ }
+ if (speed_mode > 1)
+ speed_mode = 0;
+ wmt_i2c2_speed_mode = speed_mode;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C2_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C2 ;
+
+ printk("PORT 2 speed_mode = %d\n", speed_mode);
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else if (speed_mode == 1)
+ i2c.i2c_mode = I2C_FAST_MODE ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+ /**/
+ /* hardware initial*/
+ /**/
+ auto_pll_divisor(DEV_I2C2, CLK_ENABLE, 0, 0);
+ pllb_freq = auto_pll_divisor(DEV_I2C2, SET_DIV, 2, 20);/*20M Hz*/
+ if ((pllb_freq%(1000*2*100)) != 0)
+ tr_val = pllb_freq/(1000*2*100) + 1;
+ else
+ tr_val = pllb_freq/(1000*2*100);
+ *(volatile unsigned char *)CTRL_GPIO &= ~(BIT4 | BIT5);
+ *(volatile unsigned char *)PU_EN_GPIO |= (BIT4 | BIT5);
+ *(volatile unsigned char *)PU_CTRL_GPIO |= (BIT4 | BIT5);
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = 0xff00|tr_val;
+ else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tr_val /= 4;
+ i2c.regs->tr_reg = 0xff00|tr_val ;
+ }
+ }
+
+
+ if (i2c_wmt_resource_init() == 0) {
+ if (wmt_i2c_add_bus(&i2c_wmt_ops) < 0) {
+ i2c_wmt_resource_release();
+ printk(KERN_INFO "i2c: Failed to add bus\n");
+ return -ENODEV;
+ }
+ } else
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&wmt_i2c_fifohead);
+
+#ifdef CONFIG_PM
+ register_syscore_ops(&wmt_i2c_syscore_ops);
+#endif
+
+ printk(KERN_INFO "i2c: successfully added bus\n");
+
+#ifdef I2C_REG_TEST
+ printk("i2c.regs->cr_reg= 0x%08x\n\r", i2c.regs->cr_reg);
+ printk("i2c.regs->tcr_reg= 0x%08x\n\r", i2c.regs->tcr_reg);
+ printk("i2c.regs->csr_reg= 0x%08x\n\r", i2c.regs->csr_reg);
+ printk("i2c.regs->isr_reg= 0x%08x\n\r", i2c.regs->isr_reg);
+ printk("i2c.regs->imr_reg= 0x%08x\n\r", i2c.regs->imr_reg);
+ printk("i2c.regs->cdr_reg= 0x%08x\n\r", i2c.regs->cdr_reg);
+ printk("i2c.regs->tr_reg= 0x%08x\n\r", i2c.regs->tr_reg);
+ printk("i2c.regs->div_reg= 0x%08x\n\r", i2c.regs->div_reg);
+#endif
+
+ return 0;
+}
+subsys_initcall(i2c_adap_wmt_init);
+
+static void i2c_adap_wmt_exit(void)
+{
+ wmt_i2c_del_bus(&i2c_wmt_ops);
+ i2c_wmt_resource_release();
+
+ printk(KERN_INFO "i2c: successfully removed bus\n");
+}
+
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT I2C Adapter Driver");
+MODULE_LICENSE("GPL");
+
+module_exit(i2c_adap_wmt_exit);
+
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-3.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-3.c
new file mode 100755
index 00000000..b362a156
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-3.c
@@ -0,0 +1,1256 @@
+/*++
+ drivers/i2c/busses/wmt-i2c-bus-3.c
+
+ Copyright (c) 2013 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+/* Include your headers here*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+/*
+#include <linux/i2c-id.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 <mach/hardware.h>
+#include <asm/irq.h>
+#include <mach/irqs.h>
+#include <mach/wmt-i2c-bus.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/syscore_ops.h>
+
+#ifdef __KERNEL__
+
+#ifdef DEBUG
+ #define DPRINTK printk
+#else
+ #define DPRINTK(x...)
+#endif
+
+#else
+ #define DPRINTK printf
+
+#endif
+
+
+#define MAX_BUS_READY_CNT 50 /* jiffy*/
+#define MAX_TX_TIMEOUT 500 /* ms*/
+#define MAX_RX_TIMEOUT 500 /* ms*/
+#define CTRL_GPIO GPIO_CTRL_GP23_I2C3_BYTE_ADDR
+#define PU_EN_GPIO PULL_EN_GP23_I2C3_BYTE_ADDR
+#define PU_CTRL_GPIO PULL_CTRL_GP23_I2C3_BYTE_ADDR
+
+#define USE_UBOOT_PARA
+
+struct wmt_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int volatile isr_nack ;
+ int volatile isr_byte_end ;
+ int volatile isr_timeout ;
+ int volatile isr_int_pending ;
+};
+
+static int i2c_wmt_wait_bus_not_busy(void);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int speed_mode = 1;
+static unsigned int is_master = 1;/*master:1, slave:0*/
+unsigned int wmt_i2c3_is_master = 1;
+unsigned int wmt_i2c3_speed_mode = 0;
+static unsigned int wmt_i2c3_power_state = 0;/*0:power on, 1:suspend, 2:shutdown*/
+EXPORT_SYMBOL(wmt_i2c3_is_master);
+
+/**/
+/* variable*/
+/*-------------------------------------------------*/
+static volatile struct wmt_i2c_s i2c ;
+
+DECLARE_WAIT_QUEUE_HEAD(i2c3_wait);
+/*
+spinlock_t i2c3_wmt_irqlock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c3_wmt_irqlock);
+static struct list_head wmt_i2c_fifohead;
+/*
+static spinlock_t i2c_fifolock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_fifolock);
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+
+static void i2c_wmt_set_mode(enum i2c_mode_e mode /*!<; //[IN] mode */)
+{
+ if (is_master == 0)
+ return;
+ i2c.i2c_mode = mode ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ DPRINTK("I2C: set standard mode \n");
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ DPRINTK("I2C: set fast mode \n");
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+ }
+}
+
+
+static int i2c_send_request(
+ struct i2c_msg *msg,
+ int msg_num,
+ int non_block,
+ void (*callback)(void *data),
+ void *data
+)
+{
+ struct wmt_i2cbusfifo *i2c_fifo_head;
+ struct i2c_msg *pmsg = NULL;
+ int ret = 0;
+ int restart = 0;
+ int last = 0;
+ unsigned long flags;
+ int slave_addr = msg[0].addr;
+
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+ if (wmt_i2c3_power_state == 2) {
+ printk("I2C3 has been shutdown\n");
+ return -EIO;
+ }
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c_fifo_head = kzalloc(sizeof(struct wmt_i2cbusfifo), GFP_ATOMIC);
+ INIT_LIST_HEAD(&i2c_fifo_head->busfifohead);
+
+ pmsg = &msg[0];
+ i2c_fifo_head->msg = pmsg;
+ i2c_fifo_head->msg_num = msg_num;
+
+ spin_lock_irqsave(&i2c_fifolock, flags);
+ if (list_empty(&wmt_i2c_fifohead)) {
+ i2c_wmt_wait_bus_not_busy();
+ pmsg = &msg[0];
+ i2c_fifo_head->xfer_length = 1;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ if (pmsg->flags & I2C_M_RD) {
+ i2c_fifo_head->xfer_length = 1;
+ ret = i2c_wmt_read_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ } else {
+ i2c_fifo_head->xfer_length = 1;
+ if (pmsg->flags & I2C_M_NOSTART)
+ i2c_fifo_head->restart = 1;
+ else
+ i2c_fifo_head->restart = 0;
+ ret = i2c_wmt_write_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ }
+
+ } else {
+ i2c_fifo_head->xfer_length = 0;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ }
+ spin_unlock_irqrestore(&i2c_fifolock, flags);
+ if (non_block == 0) {
+ wait_event(i2c3_wait, i2c.isr_int_pending);
+ ret = msg_num;
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ }
+
+ }
+
+ return ret;
+
+
+}
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value;
+ int ret = 0;
+
+ DPRINTK("[%s]:length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ tcr_value = 0 ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+ return ret;
+}
+
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int ret = 0 ;
+
+ DPRINTK("[%s]length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ ret = 0 ;
+ return ret;
+
+}
+static int i2c_wmt_read_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete read */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result = 0 ;
+
+ if (is_master == 0)
+ return -ENXIO;
+ if (length <= 0)
+ return -1 ;
+ xfer_length = 0 ;
+
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ ret = 0 ;
+ for (; ;) {
+ is_timeout = 0 ;
+ wait_event_result = wait_event_interruptible_timeout(i2c3_wait, i2c.isr_int_pending ,
+ (MAX_RX_TIMEOUT * HZ / 1000)) ;
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (rx) \n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (rx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err: write software timeout error (rx) \n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ buf[xfer_length] = (i2c.regs->cdr_reg >> 8) ;
+ ++xfer_length ;
+ DPRINTK("i2c_test: received BYTE_END\n\r");
+ }
+ i2c.isr_int_pending = 0;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+ if (length > xfer_length) {
+ if ((length - 1) == xfer_length) { /* next read is the last one*/
+ i2c.regs->cr_reg |= (I2C_CR_TX_NEXT_NO_ACK | I2C_CR_CPU_RDY);
+ DPRINTK("i2c_test: set CPU_RDY & TX_ACK. next data is last.\r\n");
+ } else {
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ DPRINTK("i2c_test: more data to read. only set CPU_RDY. \r\n");
+ }
+ } else if (length == xfer_length) { /* end rx xfer*/
+ if (last == 1) { /* stop case*/
+ DPRINTK("i2c_test: read completed \r\n");
+ break ;
+ } else { /* restart case*/
+ /* ??? how to handle the restart after read ?*/
+ DPRINTK("i2c_test: RX ReStart Case \r\n") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : read known error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ }
+
+ DPRINTK("i2c_test: read sequence completed\n\r");
+ return ret ;
+}
+
+static int i2c_wmt_write_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete write */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result ;
+
+ DPRINTK("length = %d , slave_addr = %x\n", length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+
+ ret = 0 ;
+ for (; ;) {
+
+ is_timeout = 0 ;
+ /**/
+ /* I2C: Wait for interrupt. if ( i2c.isr_int_pending == 1 ) ==> an interrupt exsits.*/
+ /**/
+ wait_event_result = wait_event_interruptible_timeout(i2c3_wait, i2c.isr_int_pending , (MAX_TX_TIMEOUT * HZ / 1000)) ;
+
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (tx)\n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (tx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (tx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (tx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err : write software timeout error (tx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ DPRINTK("i2c: isr end byte (tx)\n\r") ;
+ ++xfer_length ;
+ }
+ i2c.isr_int_pending = 0 ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+
+ if ((i2c.regs->csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK) {
+ DPRINTK("i2c_err : write RCV NACK error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0) {
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ break ;
+ }
+ if (length > xfer_length) {
+ i2c.regs->cdr_reg = (unsigned short) (buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+ i2c.regs->cr_reg = (I2C_CR_CPU_RDY | I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: write register data \n\r") ;
+ } else if (length == xfer_length) { /* end tx xfer*/
+ if (last == 1) { /* stop case*/
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: finish write \n\r") ;
+ break ;
+ } else { /* restart case*/
+ /* handle the restart for first write then the next is read*/
+ i2c.regs->cr_reg = (I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: tx restart Case \n\r") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : write unknown error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ } ;
+
+ DPRINTK("i2c_test: write sequence completed\n\r");
+
+ return ret ;
+}
+
+static int i2c_wmt_wait_bus_not_busy(void)
+{
+ int ret ;
+ int cnt ;
+
+ ret = 0 ;
+ cnt = 0 ;
+ while (1) {
+ if ((REG16_VAL(I2C3_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY) {
+ ret = 0;
+ break ;
+ }
+ cnt++ ;
+
+ if (cnt > MAX_BUS_READY_CNT) {
+ ret = (-EBUSY) ;
+ printk("i2c_err 3: wait but not ready time-out\n\r") ;
+ cnt = 0;
+ break;
+ }
+ }
+ return ret ;
+}
+
+static void i2c_wmt_reset(void)
+{
+ unsigned short tmp ;
+ if (is_master == 0)
+ return;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C3_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C3 ;
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* hardware initial*/
+ /**/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+
+ DPRINTK("Resetting I2C Controller Unit\n");
+
+ return ;
+}
+static int wmt_i2c_transfer_msg(struct wmt_i2cbusfifo *fifo_head)
+{
+ int xfer_length = fifo_head->xfer_length;
+ int xfer_msgnum = fifo_head->xfer_msgnum;
+ struct i2c_msg *pmsg = &fifo_head->msg[xfer_msgnum];
+ int restart = fifo_head->restart;
+ unsigned short tcr_value;
+ unsigned short slave_addr = pmsg->addr;
+ int length = pmsg->len;
+ int ret = 0;
+
+ if (pmsg->flags & I2C_M_RD) {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ } else {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(pmsg->buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ }
+ return ret;
+}
+
+static irqreturn_t i2c_wmt_handler(
+ int this_irq, /*!<; //[IN] IRQ number */
+ void *dev_id /*!<; //[IN] Pointer to device ID */
+)
+{
+ int wakeup ;
+ unsigned short isr_status ;
+ unsigned short tmp ;
+ unsigned long flags;
+ struct wmt_i2cbusfifo *fifo_head;
+ int xfer_length = 0;
+ int xfer_msgnum = 0;
+ struct i2c_msg *pmsg;
+ volatile unsigned short csr_reg;
+
+ spin_lock_irqsave(&i2c3_wmt_irqlock, flags);
+ isr_status = i2c.regs->isr_reg ;
+ csr_reg = i2c.regs->csr_reg;
+ wakeup = 0 ;
+ fifo_head = list_first_entry(&wmt_i2c_fifohead, struct wmt_i2cbusfifo, busfifohead);
+
+ if (isr_status & I2C_ISR_NACK_ADDR) {
+ DPRINTK("[%s]:i2c NACK\n", __func__);
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_NACK_ADDR_WRITE_CLEAR ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ }
+
+ if ((isr_status & I2C_ISR_BYTE_END && ((csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK))) {
+ /*
+ printk("data rcv nack\n");
+ */
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ } else if (isr_status & I2C_ISR_BYTE_END) {
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_byte_end = 1 ;
+ xfer_length = fifo_head->xfer_length;
+ xfer_msgnum = fifo_head->xfer_msgnum;
+ pmsg = &fifo_head->msg[xfer_msgnum];
+
+ /*read case*/
+ if (pmsg->flags & I2C_M_RD) {
+ pmsg->buf[xfer_length - 1] = (i2c.regs->cdr_reg >> 8) ;
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len - 1) {
+ /*last msg of the current request?*/
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_TX_NEXT_NO_ACK);
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ } else if (xfer_length == pmsg->len) {/*next msg*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else { /*data of this msg has been transfered*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*next request exist?*/
+ if (list_empty(&wmt_i2c_fifohead)) {/*no more reqeust*/
+ /*kfree(fifo_head);*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ } else { /*more request*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ fifo_head->xfer_length = 0;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("2 : non callback\n");
+ wakeup = 1;
+ } else {
+ printk("2 :callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ }
+
+ } else { /*write case*/
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len) {
+ /*last msg of the current request?*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ }
+ /*access next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else {/*this request finish*/
+ /*spin_lock(&i2c_fifolock);*/
+ /*next request exist?*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ if (list_empty(&wmt_i2c_fifohead)) {
+ /*kfree(fifo_head);*/
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+
+ } else {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ /*next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("4:non callback\n");
+ wakeup = 1;
+ } else {
+ printk("4:callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ i2c.regs->cdr_reg = (unsigned short) (pmsg->buf[fifo_head->xfer_length] & I2C_CDR_DATA_WRITE_MASK);
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_ENABLE);
+ }
+ }
+ }
+
+ if (isr_status & I2C_ISR_SCL_TIME_OUT) {
+ DPRINTK("[%s]SCL timeout\n", __func__);
+#if 0
+ i2c.regs->cr_reg |= BIT7;/*reset status*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR | I2C_ISR_BYTE_END_WRITE_CLEAR;
+ i2c.isr_timeout = 1 ;
+ wakeup = 1;
+#endif
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR ;
+ }
+
+
+ if (wakeup) {
+ /*spin_lock_irqsave(&i2c_wmt_irqlock, flags);*/
+ i2c.isr_int_pending = 1;
+ /*spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);*/
+ wake_up(&i2c3_wait);
+ } else
+ DPRINTK("i2c_err : unknown I2C ISR Handle 0x%4.4X" , isr_status) ;
+ spin_unlock_irqrestore(&i2c3_wmt_irqlock, flags);
+ return IRQ_HANDLED;
+}
+
+static int i2c_wmt_resource_init(void)
+{
+ if (is_master == 0)
+ return 0;
+ if (request_irq(i2c.irq_no , &i2c_wmt_handler, IRQF_DISABLED, "i2c", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C: Failed to register I2C irq %i\n", i2c.irq_no);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void i2c_wmt_resource_release(void)
+{
+ if (is_master == 0)
+ return;
+ free_irq(i2c.irq_no, 0);
+}
+
+static struct i2c_algo_wmt_data i2c_wmt_data = {
+ write_msg: i2c_wmt_write_msg,
+ read_msg: i2c_wmt_read_msg,
+ send_request: i2c_send_request,
+ wait_bus_not_busy: i2c_wmt_wait_bus_not_busy,
+ reset: i2c_wmt_reset,
+ set_mode: i2c_wmt_set_mode,
+ udelay: I2C_ALGO_UDELAY,
+ timeout: I2C_ALGO_TIMEOUT,
+};
+
+static struct i2c_adapter i2c_wmt_ops = {
+ .owner = THIS_MODULE,
+ /*
+ .id = I2C_ALGO_WMT,
+ */
+ .algo_data = &i2c_wmt_data,
+ .name = "wmt_i2c3_adapter",
+ .retries = I2C_ADAPTER_RETRIES,
+ .nr = 3,
+};
+
+#ifdef CONFIG_PM
+static struct i2c_regs_s wmt_i2c_reg ;
+static void i2c_shutdown(void)
+{
+ printk("i2c3 shutdown\n");
+ wmt_i2c3_power_state = 2;
+ while (!list_empty(&wmt_i2c_fifohead))
+ msleep(1);
+ while (1) {/*wait busy clear*/
+ if ((REG16_VAL(I2C3_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY)
+ break ;
+ msleep(1);
+ }
+ return;
+}
+static int i2c_suspend(void)
+{
+ printk("i2c3 suspend\n");
+ wmt_i2c_reg.imr_reg = i2c.regs->imr_reg;
+ wmt_i2c_reg.tr_reg = i2c.regs->tr_reg;
+ wmt_i2c_reg.div_reg = i2c.regs->div_reg;
+ return 0;
+}
+static void i2c_resume(void)
+{
+ printk("i2c3 resume\n");
+ GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~(BIT0 | BIT1);
+ PULL_EN_GP23_I2C3_BYTE_VAL |= (BIT0 | BIT1);
+ PULL_CTRL_GP23_I2C3_BYTE_VAL |= (BIT0 | BIT1);
+ PIN_SHARING_SEL_4BYTE_VAL &= ~BIT28;
+ auto_pll_divisor(DEV_I2C3, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_I2C3, SET_DIV, 2, 20);/*20M Hz*/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = wmt_i2c_reg.div_reg;
+ i2c.regs->imr_reg = wmt_i2c_reg.imr_reg;
+ i2c.regs->tr_reg = wmt_i2c_reg.tr_reg ;
+ i2c.regs->cr_reg = 0x001 ;
+}
+#else
+#define i2c_suspend NULL
+#define i2c_resume NULL
+#define i2c_shutdown NULL
+#endif
+extern int wmt_i2c_add_bus(struct i2c_adapter *);
+extern int wmt_i2c_del_bus(struct i2c_adapter *);
+
+#ifdef CONFIG_PM
+static struct syscore_ops wmt_i2c_syscore_ops = {
+ .suspend = i2c_suspend,
+ .resume = i2c_resume,
+ .shutdown = i2c_shutdown,
+};
+#endif
+
+static int __init i2c_adap_wmt_init(void)
+{
+ unsigned short tmp ;
+ char varname[] = "wmt.i2c.param";
+#ifdef CONFIG_I2C_SLAVE_WMT
+ char varname1[] = "wmt.bus.i2c.slave_port";
+#endif
+ unsigned char buf[80];
+ int ret;
+ unsigned int port_num;
+ int idx = 0;
+ int varlen = 80;
+ unsigned int pllb_freq = 0;
+ unsigned int tr_val = 0;
+
+#ifdef CONFIG_I2C_SLAVE_WMT
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname1, buf, &varlen);
+#else
+ ret = 1;
+#endif
+ is_master = 1;
+ if (ret == 0) {
+ ret = sscanf(buf, "%x", &port_num);
+ while (ret) {
+ if (port_num != 0)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret;
+ ret = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+#endif
+ wmt_i2c3_is_master = is_master;
+ if (is_master == 1) {
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname, buf, &varlen);
+#else
+ ret = 1;
+#endif
+
+ if (ret == 0) {
+ ret = sscanf(buf, "%x:%x", &port_num, &speed_mode);
+ idx += 3;
+ while (ret) {
+ if (ret < 2)
+ speed_mode = 0;
+ else {
+ if (port_num != 3)
+ speed_mode = 0;
+ else
+ break;
+ }
+ ret = sscanf(buf + idx, ",%x:%x", &port_num, &speed_mode);
+ idx += 4;
+ }
+ }
+ if (speed_mode > 1)
+ speed_mode = 0;
+ wmt_i2c3_speed_mode = speed_mode;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C3_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C3 ;
+
+ printk("PORT 3 speed_mode = %d\n", speed_mode);
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else if (speed_mode == 1)
+ i2c.i2c_mode = I2C_FAST_MODE ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+ /**/
+ /* hardware initial*/
+ /**/
+ auto_pll_divisor(DEV_I2C3, CLK_ENABLE, 0, 0);
+ pllb_freq = auto_pll_divisor(DEV_I2C3, SET_DIV, 2, 20);/*20M Hz*/
+ printk("pllb_freq = %d\n", pllb_freq);
+ if ((pllb_freq%(1000*2*100)) != 0)
+ tr_val = pllb_freq/(1000*2*100) + 1;
+ else
+ tr_val = pllb_freq/(1000*2*100);
+ *(volatile unsigned char *)CTRL_GPIO &= ~(BIT0 | BIT1);
+ *(volatile unsigned char *)PU_EN_GPIO |= (BIT0 | BIT1);
+ *(volatile unsigned char *)PU_CTRL_GPIO |= (BIT0 | BIT1);
+ PIN_SHARING_SEL_4BYTE_VAL &= ~BIT28;
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = 0xff00|tr_val;
+ else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tr_val /= 4;
+ i2c.regs->tr_reg = 0xff00|tr_val ;
+ }
+ }
+
+
+ if (i2c_wmt_resource_init() == 0) {
+ if (wmt_i2c_add_bus(&i2c_wmt_ops) < 0) {
+ i2c_wmt_resource_release();
+ printk(KERN_INFO "i2c: Failed to add bus\n");
+ return -ENODEV;
+ }
+ } else
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&wmt_i2c_fifohead);
+
+#ifdef CONFIG_PM
+ register_syscore_ops(&wmt_i2c_syscore_ops);
+#endif
+
+ printk(KERN_INFO "i2c: successfully added bus\n");
+
+#ifdef I2C_REG_TEST
+ printk("i2c.regs->cr_reg= 0x%08x\n\r", i2c.regs->cr_reg);
+ printk("i2c.regs->tcr_reg= 0x%08x\n\r", i2c.regs->tcr_reg);
+ printk("i2c.regs->csr_reg= 0x%08x\n\r", i2c.regs->csr_reg);
+ printk("i2c.regs->isr_reg= 0x%08x\n\r", i2c.regs->isr_reg);
+ printk("i2c.regs->imr_reg= 0x%08x\n\r", i2c.regs->imr_reg);
+ printk("i2c.regs->cdr_reg= 0x%08x\n\r", i2c.regs->cdr_reg);
+ printk("i2c.regs->tr_reg= 0x%08x\n\r", i2c.regs->tr_reg);
+ printk("i2c.regs->div_reg= 0x%08x\n\r", i2c.regs->div_reg);
+#endif
+
+ return 0;
+}
+subsys_initcall(i2c_adap_wmt_init);
+
+static void i2c_adap_wmt_exit(void)
+{
+ wmt_i2c_del_bus(&i2c_wmt_ops);
+ i2c_wmt_resource_release();
+
+ printk(KERN_INFO "i2c: successfully removed bus\n");
+}
+
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT I2C Adapter Driver");
+MODULE_LICENSE("GPL");
+
+module_exit(i2c_adap_wmt_exit);
+
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-4.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-4.c
new file mode 100755
index 00000000..72e6531d
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus-4.c
@@ -0,0 +1,1274 @@
+/*++
+ drivers/i2c/busses/wmt_i2c_bus-4.c
+
+ Copyright (c) 2013 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+/* Include your headers here*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+/*
+#include <linux/i2c-id.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 <mach/hardware.h>
+#include <asm/irq.h>
+#include <mach/irqs.h>
+#include <mach/wmt-i2c-bus.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/syscore_ops.h>
+
+#ifdef __KERNEL__
+
+#ifdef DEBUG
+ #define DPRINTK printk
+#else
+ #define DPRINTK(x...)
+#endif
+
+#else
+ #define DPRINTK printf
+
+#endif
+
+
+#define MAX_BUS_READY_CNT 50 /* jiffy*/
+#define MAX_TX_TIMEOUT 500 /* ms*/
+#define MAX_RX_TIMEOUT 500 /* ms*/
+
+#define USE_UBOOT_PARA
+
+struct wmt_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int volatile isr_nack ;
+ int volatile isr_byte_end ;
+ int volatile isr_timeout ;
+ int volatile isr_int_pending ;
+};
+
+static int i2c_wmt_wait_bus_not_busy(void);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int speed_mode = 0;
+unsigned int wmt_i2c4_speed_mode = 0;
+static unsigned int is_master = 1;/*master:1, slave:0*/
+unsigned int wmt_i2c4_is_master = 1;
+static unsigned int wmt_i2c4_power_state = 0;/*0:power on, 1:suspend, 2:shutdown*/
+EXPORT_SYMBOL(wmt_i2c4_is_master);
+
+/**/
+/* variable*/
+/*-------------------------------------------------*/
+static volatile struct wmt_i2c_s i2c ;
+
+DECLARE_WAIT_QUEUE_HEAD(i2c4_wait);
+/*
+spinlock_t i2c_wmt_irqlock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_wmt_irqlock);
+static struct list_head wmt_i2c_fifohead;
+/*
+static spinlock_t i2c_fifolock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_fifolock);
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+
+static void i2c_gpio_init(void)
+{
+ GPIO_CTRL_GP10_I2S_BYTE_VAL &= ~BIT4;
+ GPIO_CTRL_GP11_I2S_BYTE_VAL &= ~BIT2;
+
+ PULL_EN_GP10_I2S_BYTE_VAL |= BIT4;
+ PULL_EN_GP11_I2S_BYTE_VAL |= BIT2;
+
+ PULL_CTRL_GP10_I2S_BYTE_VAL |= BIT4;
+ PULL_CTRL_GP11_I2S_BYTE_VAL |= BIT2;
+
+ PIN_SHARING_SEL_4BYTE_VAL |= BIT21 | BIT22 | BIT13 | BIT14;
+}
+
+static void i2c_wmt_set_mode(enum i2c_mode_e mode /*!<; //[IN] mode */)
+{
+ if (is_master == 0)
+ return;
+ i2c.i2c_mode = mode ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ DPRINTK("I2C: set standard mode \n");
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ DPRINTK("I2C: set fast mode \n");
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+ }
+}
+
+
+static int i2c_send_request(
+ struct i2c_msg *msg,
+ int msg_num,
+ int non_block,
+ void (*callback)(void *data),
+ void *data
+)
+{
+ struct wmt_i2cbusfifo *i2c_fifo_head;
+ struct i2c_msg *pmsg = NULL;
+ int ret = 0;
+ int restart = 0;
+ int last = 0;
+ unsigned long flags;
+ int slave_addr = msg[0].addr;
+
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (wmt_i2c4_power_state == 2) {
+ printk("I2C4 has been shutdown\n");
+ return -EIO;
+ }
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ if (non_block == 0)
+ i2c.isr_int_pending = 0;
+
+ i2c_fifo_head = kzalloc(sizeof(struct wmt_i2cbusfifo), GFP_ATOMIC);
+ INIT_LIST_HEAD(&i2c_fifo_head->busfifohead);
+
+ pmsg = &msg[0];
+ i2c_fifo_head->msg = pmsg;
+ i2c_fifo_head->msg_num = msg_num;
+
+ spin_lock_irqsave(&i2c_fifolock, flags);
+ if (list_empty(&wmt_i2c_fifohead)) {
+ i2c_wmt_wait_bus_not_busy();
+ pmsg = &msg[0];
+ i2c_fifo_head->xfer_length = 1;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ if (pmsg->flags & I2C_M_RD) {
+ i2c_fifo_head->xfer_length = 1;
+ ret = i2c_wmt_read_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ } else {
+ i2c_fifo_head->xfer_length = 1;
+ if (pmsg->flags & I2C_M_NOSTART)
+ i2c_fifo_head->restart = 1;
+ else
+ i2c_fifo_head->restart = 0;
+ ret = i2c_wmt_write_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ }
+
+ } else {
+ i2c_fifo_head->xfer_length = 0;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ }
+ spin_unlock_irqrestore(&i2c_fifolock, flags);
+ if (non_block == 0) {
+ wait_event(i2c4_wait, i2c.isr_int_pending);
+ ret = msg_num;
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ }
+
+ }
+
+ return ret;
+
+
+}
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value;
+ int ret = 0;
+
+ DPRINTK("[%s]:length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ tcr_value = 0 ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+ return ret;
+}
+
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int ret = 0 ;
+
+ DPRINTK("[%s]length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ ret = 0 ;
+ return ret;
+
+}
+static int i2c_wmt_read_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete read */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result = 0 ;
+
+ if (is_master == 0)
+ return -ENXIO;
+ if (length <= 0)
+ return -1 ;
+ xfer_length = 0 ;
+
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ ret = 0 ;
+ for (; ;) {
+ is_timeout = 0 ;
+ wait_event_result = wait_event_interruptible_timeout(i2c4_wait, i2c.isr_int_pending ,
+ (MAX_RX_TIMEOUT * HZ / 1000)) ;
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (rx) \n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (rx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err: write software timeout error (rx) \n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ buf[xfer_length] = (i2c.regs->cdr_reg >> 8) ;
+ ++xfer_length ;
+ DPRINTK("i2c_test: received BYTE_END\n\r");
+ }
+ i2c.isr_int_pending = 0;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+ if (length > xfer_length) {
+ if ((length - 1) == xfer_length) { /* next read is the last one*/
+ i2c.regs->cr_reg |= (I2C_CR_TX_NEXT_NO_ACK | I2C_CR_CPU_RDY);
+ DPRINTK("i2c_test: set CPU_RDY & TX_ACK. next data is last.\r\n");
+ } else {
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ DPRINTK("i2c_test: more data to read. only set CPU_RDY. \r\n");
+ }
+ } else if (length == xfer_length) { /* end rx xfer*/
+ if (last == 1) { /* stop case*/
+ DPRINTK("i2c_test: read completed \r\n");
+ break ;
+ } else { /* restart case*/
+ /* ??? how to handle the restart after read ?*/
+ DPRINTK("i2c_test: RX ReStart Case \r\n") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : read known error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ }
+
+ DPRINTK("i2c_test: read sequence completed\n\r");
+ return ret ;
+}
+
+static int i2c_wmt_write_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete write */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result ;
+
+ DPRINTK("length = %d , slave_addr = %x\n", length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+
+ ret = 0 ;
+ for (; ;) {
+
+ is_timeout = 0 ;
+ /**/
+ /* I2C: Wait for interrupt. if ( i2c.isr_int_pending == 1 ) ==> an interrupt exsits.*/
+ /**/
+ wait_event_result = wait_event_interruptible_timeout(i2c4_wait, i2c.isr_int_pending , (MAX_TX_TIMEOUT * HZ / 1000)) ;
+
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (tx)\n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (tx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (tx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (tx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err : write software timeout error (tx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ DPRINTK("i2c: isr end byte (tx)\n\r") ;
+ ++xfer_length ;
+ }
+ i2c.isr_int_pending = 0 ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+
+ if ((i2c.regs->csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK) {
+ DPRINTK("i2c_err : write RCV NACK error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0) {
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ break ;
+ }
+ if (length > xfer_length) {
+ i2c.regs->cdr_reg = (unsigned short) (buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+ i2c.regs->cr_reg = (I2C_CR_CPU_RDY | I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: write register data \n\r") ;
+ } else if (length == xfer_length) { /* end tx xfer*/
+ if (last == 1) { /* stop case*/
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: finish write \n\r") ;
+ break ;
+ } else { /* restart case*/
+ /* handle the restart for first write then the next is read*/
+ i2c.regs->cr_reg = (I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: tx restart Case \n\r") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : write unknown error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ } ;
+
+ DPRINTK("i2c_test: write sequence completed\n\r");
+
+ return ret ;
+}
+
+static int i2c_wmt_wait_bus_not_busy(void)
+{
+ int ret ;
+ int cnt ;
+
+ ret = 0 ;
+ cnt = 0 ;
+ while (1) {
+ if ((REG16_VAL(I2C4_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY) {
+ ret = 0;
+ break ;
+ }
+ cnt++ ;
+
+ if (cnt > MAX_BUS_READY_CNT) {
+ ret = (-EBUSY) ;
+ printk("i2c_err : wait but not ready time-out\n\r") ;
+ cnt = 0;
+ break;
+ }
+ }
+ return ret ;
+}
+
+static void i2c_wmt_reset(void)
+{
+ unsigned short tmp ;
+ if (is_master == 0)
+ return;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C4_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C4 ;
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* hardware initial*/
+ /**/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+
+ DPRINTK("Resetting I2C Controller Unit\n");
+
+ return ;
+}
+static int wmt_i2c_transfer_msg(struct wmt_i2cbusfifo *fifo_head)
+{
+ int xfer_length = fifo_head->xfer_length;
+ int xfer_msgnum = fifo_head->xfer_msgnum;
+ struct i2c_msg *pmsg = &fifo_head->msg[xfer_msgnum];
+ int restart = fifo_head->restart;
+ unsigned short tcr_value;
+ unsigned short slave_addr = pmsg->addr;
+ int length = pmsg->len;
+ int ret = 0;
+
+ if (pmsg->flags & I2C_M_RD) {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ } else {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(pmsg->buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ }
+ return ret;
+}
+
+static irqreturn_t i2c_wmt_handler(
+ int this_irq, /*!<; //[IN] IRQ number */
+ void *dev_id /*!<; //[IN] Pointer to device ID */
+)
+{
+ int wakeup ;
+ unsigned short isr_status ;
+ unsigned short tmp ;
+ unsigned long flags;
+ struct wmt_i2cbusfifo *fifo_head;
+ int xfer_length = 0;
+ int xfer_msgnum = 0;
+ struct i2c_msg *pmsg;
+ volatile unsigned short csr_reg;
+
+ spin_lock_irqsave(&i2c_wmt_irqlock, flags);
+ isr_status = i2c.regs->isr_reg ;
+ csr_reg = i2c.regs->csr_reg;
+ wakeup = 0 ;
+ fifo_head = list_first_entry(&wmt_i2c_fifohead, struct wmt_i2cbusfifo, busfifohead);
+
+ if (isr_status & I2C_ISR_NACK_ADDR) {
+ DPRINTK("[%s]:i2c NACK\n", __func__);
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_NACK_ADDR_WRITE_CLEAR ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ }
+
+ if ((isr_status & I2C_ISR_BYTE_END && ((csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK))) {
+ /*
+ printk("data rcv nack\n");
+ */
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ } else if (isr_status & I2C_ISR_BYTE_END) {
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_byte_end = 1 ;
+ xfer_length = fifo_head->xfer_length;
+ xfer_msgnum = fifo_head->xfer_msgnum;
+ pmsg = &fifo_head->msg[xfer_msgnum];
+
+ /*read case*/
+ if (pmsg->flags & I2C_M_RD) {
+ pmsg->buf[xfer_length - 1] = (i2c.regs->cdr_reg >> 8) ;
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len - 1) {
+ /*last msg of the current request?*/
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_TX_NEXT_NO_ACK);
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ } else if (xfer_length == pmsg->len) {/*next msg*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else { /*data of this msg has been transfered*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*next request exist?*/
+ if (list_empty(&wmt_i2c_fifohead)) {/*no more reqeust*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ } else { /*more request*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ fifo_head->xfer_length = 0;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("2 : non callback\n");
+ wakeup = 1;
+ } else {
+ printk("2 :callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ }
+
+ } else { /*write case*/
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len) {
+ /*last msg of the current request?*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ }
+ /*access next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else {/*this request finish*/
+ /*spin_lock(&i2c_fifolock);*/
+ /*next request exist?*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ if (list_empty(&wmt_i2c_fifohead)) {
+ /*kfree(fifo_head);*/
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+
+ } else {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ /*next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("4:non callback\n");
+ wakeup = 1;
+ } else {
+ printk("4:callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ i2c.regs->cdr_reg = (unsigned short) (pmsg->buf[fifo_head->xfer_length] & I2C_CDR_DATA_WRITE_MASK);
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_ENABLE);
+ }
+ }
+ }
+
+ if (isr_status & I2C_ISR_SCL_TIME_OUT) {
+ DPRINTK("[%s]SCL timeout\n", __func__);
+#if 0
+ i2c.regs->cr_reg |= BIT7;/*reset status*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR | I2C_ISR_BYTE_END_WRITE_CLEAR;
+ i2c.isr_timeout = 1 ;
+ wakeup = 1;
+#endif
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR ;
+ }
+
+
+ if (wakeup) {
+ /*spin_lock_irqsave(&i2c_wmt_irqlock, flags);*/
+ i2c.isr_int_pending = 1;
+ /*spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);*/
+ wake_up(&i2c4_wait);
+ } else
+ DPRINTK("i2c_err : unknown I2C ISR Handle 0x%4.4X" , isr_status) ;
+ spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);
+ return IRQ_HANDLED;
+}
+
+static int i2c_wmt_resource_init(void)
+{
+ if (is_master == 0)
+ return 0;
+ if (request_irq(i2c.irq_no , &i2c_wmt_handler, IRQF_DISABLED, "i2c", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C: Failed to register I2C irq %i\n", i2c.irq_no);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void i2c_wmt_resource_release(void)
+{
+ if (is_master == 0)
+ return;
+ free_irq(i2c.irq_no, 0);
+}
+
+static struct i2c_algo_wmt_data i2c_wmt_data = {
+ write_msg: i2c_wmt_write_msg,
+ read_msg: i2c_wmt_read_msg,
+ send_request: i2c_send_request,
+ wait_bus_not_busy: i2c_wmt_wait_bus_not_busy,
+ reset: i2c_wmt_reset,
+ set_mode: i2c_wmt_set_mode,
+ udelay: I2C_ALGO_UDELAY,
+ timeout: I2C_ALGO_TIMEOUT,
+};
+
+static struct i2c_adapter i2c_wmt_ops = {
+ .owner = THIS_MODULE,
+ /*
+ .id = I2C_ALGO_WMT,
+ */
+ .algo_data = &i2c_wmt_data,
+ .name = "wmt_i2c4_adapter",
+ .retries = I2C_ADAPTER_RETRIES,
+ .nr = 4,
+};
+
+#ifdef CONFIG_PM
+static struct i2c_regs_s wmt_i2c_reg ;
+static void i2c_shutdown(void)
+{
+ printk("i2c4 shutdown\n");
+ wmt_i2c4_power_state = 2;
+ while (!list_empty(&wmt_i2c_fifohead))
+ msleep(1);
+ while (1) {/*wait busy clear*/
+ if ((REG16_VAL(I2C4_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY)
+ break ;
+ msleep(1);
+ }
+ return;
+}
+static int i2c_suspend(void)
+{
+ printk("i2c4 suspend\n");
+ wmt_i2c_reg.imr_reg = i2c.regs->imr_reg;
+ wmt_i2c_reg.tr_reg = i2c.regs->tr_reg;
+ wmt_i2c_reg.div_reg = i2c.regs->div_reg;
+ return 0;
+}
+static void i2c_resume(void)
+{
+ printk("i2c4 resume\n");
+ /*
+ GPIO_CTRL_GP17_I2C_BYTE_VAL &= ~(BIT2 | BIT3);
+ PULL_EN_GP17_I2C_BYTE_VAL |= (BIT2 | BIT3);
+ PULL_CTRL_GP17_I2C_BYTE_VAL |= (BIT2 | BIT3);
+ */
+ i2c_gpio_init();
+ auto_pll_divisor(DEV_I2C4, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_I2C4, SET_DIV, 2, 20);/*20M Hz*/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = wmt_i2c_reg.div_reg;
+ i2c.regs->imr_reg = wmt_i2c_reg.imr_reg;
+ i2c.regs->tr_reg = wmt_i2c_reg.tr_reg ;
+ i2c.regs->cr_reg = 0x001 ;
+}
+#else
+#define i2c_suspend NULL
+#define i2c_resume NULL
+#define i2c_shutdown NULL
+#endif
+extern int wmt_i2c_add_bus(struct i2c_adapter *);
+extern int wmt_i2c_del_bus(struct i2c_adapter *);
+
+#ifdef CONFIG_PM
+static struct syscore_ops wmt_i2c_syscore_ops =
+{
+ .suspend = i2c_suspend,
+ .resume = i2c_resume,
+ .shutdown = i2c_shutdown,
+};
+#endif
+
+static int __init i2c_adap_wmt_init(void)
+{
+ unsigned short tmp ;
+ char varname[] = "wmt.i2c.param";
+#ifdef CONFIG_I2C_SLAVE_WMT
+ char varname1[] = "wmt.bus.i2c.slave_port";
+#endif
+ unsigned char buf[80];
+ int ret;
+ unsigned int port_num;
+ int idx = 0;
+ int varlen = 80;
+ /*since i2c4 is share pin, it turn on while uboot parameter define i2c4 mode*/
+ int i2c_turn_on = 0;
+ unsigned int pllb_freq = 0;
+ unsigned int tr_val = 0;
+
+#ifdef CONFIG_I2C_SLAVE_WMT
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname1, buf, &varlen);
+#else
+ ret = 1;
+#endif
+ is_master = 1;
+ if (ret == 0) {
+ ret = sscanf(buf, "%x", &port_num);
+ while (ret) {
+ if (port_num != 4)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret;
+ ret = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+#endif
+ wmt_i2c4_is_master = is_master;
+ if (is_master == 1) {
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname, buf, &varlen);
+#else
+ ret = 1;
+#endif
+
+ if (ret == 0) {
+ ret = sscanf(buf, "%x:%x", &port_num, &speed_mode);
+ idx += 3;
+ while (ret) {
+ if (ret < 2)
+ speed_mode = 0;
+ else {
+ if (port_num != 4)
+ speed_mode = 0;
+ else {
+ i2c_turn_on = 1;
+ break;
+ }
+ }
+ ret = sscanf(buf + idx, ",%x:%x", &port_num, &speed_mode);
+ idx += 4;
+ }
+ }
+ if (i2c_turn_on == 0) {
+ printk("I2C4 turn off\n");
+ return -EIO;
+ }
+ if (speed_mode > 1)
+ speed_mode = 0;
+ wmt_i2c4_speed_mode = speed_mode;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C4_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C4 ;
+ printk("PORT 4 speed_mode = %d\n", speed_mode);
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else if (speed_mode == 1)
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+ /**/
+ /* hardware initial*/
+ /**/
+ auto_pll_divisor(DEV_I2C4, CLK_ENABLE, 0, 0);
+ pllb_freq = auto_pll_divisor(DEV_I2C4, SET_DIV, 2, 20);/*20M Hz*/
+ i2c_gpio_init();
+ printk("pllb_freq = %d\n", pllb_freq);
+ if ((pllb_freq%(1000*2*100)) != 0)
+ tr_val = pllb_freq/(1000*2*100) + 1;
+ else
+ tr_val = pllb_freq/(1000*2*100);
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = 0xff00|tr_val;
+ else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tr_val /= 4;
+ i2c.regs->tr_reg = 0xff00|tr_val ;
+ }
+ }
+
+
+ if (i2c_wmt_resource_init() == 0) {
+ if (wmt_i2c_add_bus(&i2c_wmt_ops) < 0) {
+ i2c_wmt_resource_release();
+ printk(KERN_INFO "i2c: Failed to add bus\n");
+ return -ENODEV;
+ }
+ } else
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&wmt_i2c_fifohead);
+
+#ifdef CONFIG_PM
+ register_syscore_ops(&wmt_i2c_syscore_ops);
+#endif
+
+ wmt_i2c4_power_state = 0;
+ printk(KERN_INFO "i2c: successfully added bus\n");
+
+#ifdef I2C_REG_TEST
+ printk("i2c.regs->cr_reg= 0x%08x\n\r", i2c.regs->cr_reg);
+ printk("i2c.regs->tcr_reg= 0x%08x\n\r", i2c.regs->tcr_reg);
+ printk("i2c.regs->csr_reg= 0x%08x\n\r", i2c.regs->csr_reg);
+ printk("i2c.regs->isr_reg= 0x%08x\n\r", i2c.regs->isr_reg);
+ printk("i2c.regs->imr_reg= 0x%08x\n\r", i2c.regs->imr_reg);
+ printk("i2c.regs->cdr_reg= 0x%08x\n\r", i2c.regs->cdr_reg);
+ printk("i2c.regs->tr_reg= 0x%08x\n\r", i2c.regs->tr_reg);
+ printk("i2c.regs->div_reg= 0x%08x\n\r", i2c.regs->div_reg);
+#endif
+
+ return 0;
+}
+subsys_initcall(i2c_adap_wmt_init);
+
+static void i2c_adap_wmt_exit(void)
+{
+ wmt_i2c_del_bus(&i2c_wmt_ops);
+ i2c_wmt_resource_release();
+
+ printk(KERN_INFO "i2c: successfully removed bus\n");
+}
+
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT I2C Adapter Driver");
+MODULE_LICENSE("GPL");
+
+module_exit(i2c_adap_wmt_exit);
+
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus.c
new file mode 100755
index 00000000..ecfda642
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-bus.c
@@ -0,0 +1,1254 @@
+/*++
+ drivers/i2c/busses/wmt-i2c-bus.c
+
+ Copyright (c) 2013 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+/* Include your headers here*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+/*
+#include <linux/i2c-id.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 <mach/hardware.h>
+#include <asm/irq.h>
+#include <mach/irqs.h>
+#include <mach/wmt-i2c-bus.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/syscore_ops.h>
+
+#ifdef __KERNEL__
+
+#ifdef DEBUG
+ #define DPRINTK printk
+#else
+ #define DPRINTK(x...)
+#endif
+
+#else
+ #define DPRINTK printf
+
+#endif
+
+
+#define MAX_BUS_READY_CNT 50 /* jiffy*/
+#define MAX_TX_TIMEOUT 500 /* ms*/
+#define MAX_RX_TIMEOUT 500 /* ms*/
+#define CTRL_GPIO GPIO_CTRL_GP17_I2C_BYTE_ADDR
+#define PU_EN_GPIO PULL_EN_GP17_I2C_BYTE_ADDR
+#define PU_CTRL_GPIO PULL_CTRL_GP17_I2C_BYTE_ADDR
+
+#define USE_UBOOT_PARA
+
+struct wmt_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int volatile isr_nack ;
+ int volatile isr_byte_end ;
+ int volatile isr_timeout ;
+ int volatile isr_int_pending ;
+};
+
+static int i2c_wmt_wait_bus_not_busy(void);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int speed_mode = 0;
+static unsigned int is_master = 1;/*master:1, slave:0*/
+unsigned int wmt_i2c0_is_master = 1;
+unsigned int wmt_i2c0_speed_mode = 0;
+static unsigned int wmt_i2c0_power_state = 0;/*0:power on, 1:suspend, 2:shutdown*/
+EXPORT_SYMBOL(wmt_i2c0_is_master);
+
+/**/
+/* variable*/
+/*-------------------------------------------------*/
+static volatile struct wmt_i2c_s i2c ;
+
+DECLARE_WAIT_QUEUE_HEAD(i2c1_wait);
+/*
+spinlock_t i2c1_wmt_irqlock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c1_wmt_irqlock);
+static struct list_head wmt_i2c_fifohead;
+/*
+static spinlock_t i2c_fifolock = SPIN_LOCK_UNLOCKED;
+*/
+static DEFINE_SPINLOCK(i2c_fifolock);
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+);
+
+static void i2c_wmt_set_mode(enum i2c_mode_e mode /*!<; //[IN] mode */)
+{
+ if (is_master == 0)
+ return;
+ i2c.i2c_mode = mode ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ DPRINTK("I2C: set standard mode \n");
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ DPRINTK("I2C: set fast mode \n");
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+ }
+}
+
+
+static int i2c_send_request(
+ struct i2c_msg *msg,
+ int msg_num,
+ int non_block,
+ void (*callback)(void *data),
+ void *data
+)
+{
+ struct wmt_i2cbusfifo *i2c_fifo_head;
+ struct i2c_msg *pmsg = NULL;
+ int ret = 0;
+ int restart = 0;
+ int last = 0;
+ unsigned long flags;
+ int slave_addr = msg[0].addr;
+
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+ if (wmt_i2c0_power_state == 2) {
+ printk("I2C0 has been shutdown\n");
+ return -EIO;
+ }
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c_fifo_head = kzalloc(sizeof(struct wmt_i2cbusfifo), GFP_ATOMIC);
+ INIT_LIST_HEAD(&i2c_fifo_head->busfifohead);
+
+ pmsg = &msg[0];
+ i2c_fifo_head->msg = pmsg;
+ i2c_fifo_head->msg_num = msg_num;
+
+ spin_lock_irqsave(&i2c_fifolock, flags);
+ if (list_empty(&wmt_i2c_fifohead)) {
+ i2c_wmt_wait_bus_not_busy();
+ pmsg = &msg[0];
+ i2c_fifo_head->xfer_length = 1;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ if (pmsg->flags & I2C_M_RD) {
+ i2c_fifo_head->xfer_length = 1;
+ ret = i2c_wmt_read_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ } else {
+ i2c_fifo_head->xfer_length = 1;
+ if (pmsg->flags & I2C_M_NOSTART)
+ i2c_fifo_head->restart = 1;
+ else
+ i2c_fifo_head->restart = 0;
+ ret = i2c_wmt_write_buf(pmsg->addr, pmsg->buf, pmsg->len, restart, last);
+ }
+
+ } else {
+ i2c_fifo_head->xfer_length = 0;
+ i2c_fifo_head->xfer_msgnum = 0;
+ i2c_fifo_head->restart = 0;
+ i2c_fifo_head->non_block = non_block;
+ if (non_block == 1) {
+ i2c_fifo_head->callback = callback;
+ i2c_fifo_head->data = data;
+ } else {
+ i2c_fifo_head->callback = 0;
+ i2c_fifo_head->data = 0;
+ }
+ list_add_tail(&i2c_fifo_head->busfifohead, &wmt_i2c_fifohead);
+ }
+ spin_unlock_irqrestore(&i2c_fifolock, flags);
+ if (non_block == 0) {
+ wait_event(i2c1_wait, i2c.isr_int_pending);
+ ret = msg_num;
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ }
+
+ }
+
+ return ret;
+
+
+}
+static int i2c_wmt_read_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value;
+ int ret = 0;
+
+ DPRINTK("[%s]:length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (length <=0)
+ return -1;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ tcr_value = 0 ;
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+ return ret;
+}
+
+static int i2c_wmt_write_buf(
+ unsigned int slave_addr,
+ char *buf,
+ unsigned int length,
+ int restart,
+ int last
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int ret = 0 ;
+
+ DPRINTK("[%s]length = %d , slave_addr = %x\n", __func__, length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ ret = 0 ;
+ return ret;
+
+}
+static int i2c_wmt_read_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete read */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result = 0 ;
+
+ if (is_master == 0)
+ return -ENXIO;
+ if (length <= 0)
+ return -1 ;
+ xfer_length = 0 ;
+
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ ret = 0 ;
+ for (; ;) {
+ is_timeout = 0 ;
+ wait_event_result = wait_event_interruptible_timeout(i2c1_wait, i2c.isr_int_pending ,
+ (MAX_RX_TIMEOUT * HZ / 1000)) ;
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (rx) \n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (rx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (rx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (rx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err: write software timeout error (rx) \n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ buf[xfer_length] = (i2c.regs->cdr_reg >> 8) ;
+ ++xfer_length ;
+ DPRINTK("i2c_test: received BYTE_END\n\r");
+ }
+ i2c.isr_int_pending = 0;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+ if (length > xfer_length) {
+ if ((length - 1) == xfer_length) { /* next read is the last one*/
+ i2c.regs->cr_reg |= (I2C_CR_TX_NEXT_NO_ACK | I2C_CR_CPU_RDY);
+ DPRINTK("i2c_test: set CPU_RDY & TX_ACK. next data is last.\r\n");
+ } else {
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ DPRINTK("i2c_test: more data to read. only set CPU_RDY. \r\n");
+ }
+ } else if (length == xfer_length) { /* end rx xfer*/
+ if (last == 1) { /* stop case*/
+ DPRINTK("i2c_test: read completed \r\n");
+ break ;
+ } else { /* restart case*/
+ /* ??? how to handle the restart after read ?*/
+ DPRINTK("i2c_test: RX ReStart Case \r\n") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : read known error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ }
+
+ DPRINTK("i2c_test: read sequence completed\n\r");
+ return ret ;
+}
+
+static int i2c_wmt_write_msg(
+ unsigned int slave_addr, /*!<; //[IN] Salve address */
+ char *buf, /*!<; //[OUT] Pointer to data */
+ unsigned int length, /*!<; //Data length */
+ int restart, /*!<; //Need to restart after a complete write */
+ int last /*!<; //Last read */
+)
+{
+ unsigned short tcr_value ;
+ unsigned int xfer_length ;
+ int is_timeout ;
+ int ret = 0 ;
+ int wait_event_result ;
+
+ DPRINTK("length = %d , slave_addr = %x\n", length , slave_addr);
+ if (slave_addr == WMT_I2C_API_I2C_ADDR)
+ return ret ;
+
+ if (is_master == 0)
+ return -ENXIO;
+
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length < 0)
+ return -1 ;
+ xfer_length = 0 ; /* for array index and also for checking counting*/
+ if (restart == 0)
+ ret = i2c_wmt_wait_bus_not_busy() ;
+ if (ret < 0)
+ return ret ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+
+ ret = 0 ;
+ for (; ;) {
+
+ is_timeout = 0 ;
+ /**/
+ /* I2C: Wait for interrupt. if ( i2c.isr_int_pending == 1 ) ==> an interrupt exsits.*/
+ /**/
+ wait_event_result = wait_event_interruptible_timeout(i2c1_wait, i2c.isr_int_pending , (MAX_TX_TIMEOUT * HZ / 1000)) ;
+
+ if (likely(wait_event_result > 0)) {
+ DPRINTK("I2C: wait interrupted (tx)\n");
+ ret = 0 ;
+ } else if (likely(i2c.isr_int_pending == 0)) {
+ DPRINTK("I2C: wait timeout (tx) \n");
+ is_timeout = 1 ;
+ ret = -ETIMEDOUT ;
+ }
+
+ /**/
+ /* fail case*/
+ /**/
+ if (i2c.isr_nack == 1) {
+ DPRINTK("i2c_err : write NACK error (tx) \n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ if (i2c.isr_timeout == 1) {
+ DPRINTK("i2c_err : write SCL timeout error (tx)\n\r") ;
+ msleep(10);
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+ if (is_timeout == 1) {
+ DPRINTK("i2c_err : write software timeout error (tx)\n\r") ;
+ ret = -ETIMEDOUT ;
+ break ;
+ }
+
+ /**/
+ /* pass case*/
+ /**/
+ if (i2c.isr_byte_end == 1) {
+ DPRINTK("i2c: isr end byte (tx)\n\r") ;
+ ++xfer_length ;
+ }
+ i2c.isr_int_pending = 0 ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+
+
+ if ((i2c.regs->csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK) {
+ DPRINTK("i2c_err : write RCV NACK error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0) {
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ break ;
+ }
+ if (length > xfer_length) {
+ i2c.regs->cdr_reg = (unsigned short) (buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+ i2c.regs->cr_reg = (I2C_CR_CPU_RDY | I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: write register data \n\r") ;
+ } else if (length == xfer_length) { /* end tx xfer*/
+ if (last == 1) { /* stop case*/
+ i2c.regs->cr_reg = (I2C_CR_TX_END|I2C_CR_CPU_RDY|I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: finish write \n\r") ;
+ break ;
+ } else { /* restart case*/
+ /* handle the restart for first write then the next is read*/
+ i2c.regs->cr_reg = (I2C_CR_ENABLE) ;
+ DPRINTK("i2c_test: tx restart Case \n\r") ;
+ break ;
+ }
+ } else {
+ DPRINTK("i2c_err : write unknown error\n\r") ;
+ ret = -EIO ;
+ break ;
+ }
+ } ;
+
+ DPRINTK("i2c_test: write sequence completed\n\r");
+
+ return ret ;
+}
+
+static int i2c_wmt_wait_bus_not_busy(void)
+{
+ int ret ;
+ int cnt ;
+
+ ret = 0 ;
+ cnt = 0 ;
+ while (1) {
+ if ((REG16_VAL(I2C_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY) {
+ ret = 0;
+ break ;
+ }
+ cnt++ ;
+
+ if (cnt > MAX_BUS_READY_CNT) {
+ ret = (-EBUSY) ;
+ printk("i2c_err 0: wait but not ready time-out\n\r") ;
+ cnt = 0;
+ break; //add by rambo d10 always has it 2013-4-14
+ }
+ }
+ return ret ;
+}
+
+static void i2c_wmt_reset(void)
+{
+ unsigned short tmp ;
+ if (is_master == 0)
+ return;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C0_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C0 ;
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else
+ i2c.i2c_mode = I2C_FAST_MODE ;
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+
+ /**/
+ /* hardware initial*/
+ /**/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = I2C_TR_STD_VALUE ; /* 0x8041*/
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ i2c.regs->tr_reg = I2C_TR_FAST_VALUE ; /* 0x8011*/
+
+ DPRINTK("Resetting I2C Controller Unit\n");
+
+ return ;
+}
+static int wmt_i2c_transfer_msg(struct wmt_i2cbusfifo *fifo_head)
+{
+ int xfer_length = fifo_head->xfer_length;
+ int xfer_msgnum = fifo_head->xfer_msgnum;
+ struct i2c_msg *pmsg = &fifo_head->msg[xfer_msgnum];
+ int restart = fifo_head->restart;
+ unsigned short tcr_value;
+ unsigned short slave_addr = pmsg->addr;
+ int length = pmsg->len;
+ int ret = 0;
+
+ if (pmsg->flags & I2C_M_RD) {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_NEXT_NO_ACK); /*clear NEXT_NO_ACK*/
+ if (restart == 0)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ } else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_READ |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ }
+ if (length == 1)
+ i2c.regs->cr_reg |= I2C_CR_TX_NEXT_NO_ACK; /*only 8-bit to read*/
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ /*repeat start case*/
+ if (restart == 1)
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ } else {
+ if (restart == 0)
+ i2c_wmt_wait_bus_not_busy();
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ /*i2c.isr_int_pending = 0;*/
+
+ /**/
+ /* special case allow length:0, for i2c_smbus_xfer*/
+ /**/
+ if (length == 0)
+ i2c.regs->cdr_reg = 0 ;
+ else
+ i2c.regs->cdr_reg = (unsigned short)(pmsg->buf[xfer_length] & I2C_CDR_DATA_WRITE_MASK) ;
+
+ if (restart == 0) {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END); /*clear Tx end*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY); /*release SCL*/
+ }
+
+ /**/
+ /* I2C: Set transfer mode [standard/fast]*/
+ /**/
+ tcr_value = 0 ;
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_STANDARD_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+ else if (i2c.i2c_mode == I2C_FAST_MODE)
+ tcr_value = (unsigned short)(I2C_TCR_FAST_MODE|I2C_TCR_MASTER_WRITE |\
+ (slave_addr & I2C_TCR_SLAVE_ADDR_MASK)) ;
+
+ i2c.regs->tcr_reg = tcr_value ;
+
+ if (restart == 1)
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY ;
+ }
+ return ret;
+}
+
+static irqreturn_t i2c_wmt_handler(
+ int this_irq, /*!<; //[IN] IRQ number */
+ void *dev_id /*!<; //[IN] Pointer to device ID */
+)
+{
+ int wakeup ;
+ unsigned short isr_status ;
+ unsigned short tmp ;
+ unsigned long flags;
+ struct wmt_i2cbusfifo *fifo_head;
+ int xfer_length = 0;
+ int xfer_msgnum = 0;
+ struct i2c_msg *pmsg;
+ volatile unsigned short csr_reg;
+
+ spin_lock_irqsave(&i2c1_wmt_irqlock, flags);
+ isr_status = i2c.regs->isr_reg ;
+ csr_reg = i2c.regs->csr_reg;
+ wakeup = 0 ;
+ fifo_head = list_first_entry(&wmt_i2c_fifohead, struct wmt_i2cbusfifo, busfifohead);
+
+ if (isr_status & I2C_ISR_NACK_ADDR) {
+ DPRINTK("[%s]:i2c NACK\n", __func__);
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_NACK_ADDR_WRITE_CLEAR ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ }
+
+ if ((isr_status & I2C_ISR_BYTE_END && ((csr_reg & I2C_CSR_RCV_ACK_MASK) == I2C_CSR_RCV_NOT_ACK))) {
+ /*
+ printk("data rcv nack\n");
+ */
+ list_del(&fifo_head->busfifohead);/*del request*/
+ kfree(fifo_head);
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_nack = 1 ;
+ wakeup = 1 ;
+ } else if (isr_status & I2C_ISR_BYTE_END) {
+ i2c.regs->isr_reg = I2C_ISR_BYTE_END_WRITE_CLEAR ;
+ i2c.isr_byte_end = 1 ;
+ xfer_length = fifo_head->xfer_length;
+ xfer_msgnum = fifo_head->xfer_msgnum;
+ pmsg = &fifo_head->msg[xfer_msgnum];
+
+ /*read case*/
+ if (pmsg->flags & I2C_M_RD) {
+ pmsg->buf[xfer_length - 1] = (i2c.regs->cdr_reg >> 8) ;
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len - 1) {
+ /*last msg of the current request?*/
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ /*
+ ++fifo_head->xfer_msgnum;
+ */
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_TX_NEXT_NO_ACK);
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ } else if (xfer_length == pmsg->len) {/*next msg*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else { /*data of this msg has been transfered*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*next request exist?*/
+ if (list_empty(&wmt_i2c_fifohead)) {/*no more reqeust*/
+ /*kfree(fifo_head);*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ } else { /*more request*/
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ fifo_head->xfer_length = 0;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("2 : non callback\n");
+ wakeup = 1;
+ } else {
+ printk("2 :callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= I2C_CR_CPU_RDY;
+ }
+
+ } else { /*write case*/
+ /*the last data in current msg?*/
+ if (xfer_length == pmsg->len) {
+ /*last msg of the current request?*/
+ if (xfer_msgnum < fifo_head->msg_num - 1) {
+ /*spin_lock(&i2c_fifolock);*/
+ if (pmsg->flags & I2C_M_NOSTART) {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 1;
+ } else {
+ ++fifo_head->xfer_length;
+ fifo_head->restart = 0;
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ }
+ /*access next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ } else {/*this request finish*/
+ /*spin_lock(&i2c_fifolock);*/
+ /*next request exist?*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ if (list_empty(&wmt_i2c_fifohead)) {
+ /*kfree(fifo_head);*/
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+
+ } else {
+ i2c.regs->cr_reg &= ~(I2C_CR_TX_END);
+ udelay(2);
+ i2c.regs->cr_reg |= (I2C_CR_TX_END);
+ if (fifo_head->non_block == 0) {
+ wakeup = 1;
+ } else {
+ fifo_head->callback(fifo_head->data);
+ }
+ kfree(fifo_head);
+ fifo_head = list_first_entry(&wmt_i2c_fifohead,
+ struct wmt_i2cbusfifo, busfifohead);
+ /*
+ if (fifo_head->non_block == 0)
+ wakeup = 1;
+ */
+
+ /*next msg*/
+ fifo_head->xfer_length = 0;
+ ++fifo_head->xfer_msgnum;
+ wmt_i2c_transfer_msg(fifo_head);
+ ++fifo_head->xfer_length;
+ /*
+ if (fifo_head->non_block == 0) {
+ printk("4:non callback\n");
+ wakeup = 1;
+ } else {
+ printk("4:callback\n");
+ fifo_head->callback(fifo_head->data);
+ }
+ */
+ }
+ /*spin_unlock(&i2c_fifolock);*/
+ }
+ } else {/*next data*/
+ i2c.regs->cdr_reg = (unsigned short) (pmsg->buf[fifo_head->xfer_length] & I2C_CDR_DATA_WRITE_MASK);
+ /*spin_lock(&i2c_fifolock);*/
+ ++fifo_head->xfer_length;
+ /*spin_unlock(&i2c_fifolock);*/
+ i2c.regs->cr_reg |= (I2C_CR_CPU_RDY | I2C_CR_ENABLE);
+ }
+ }
+ }
+
+ if (isr_status & I2C_ISR_SCL_TIME_OUT) {
+ DPRINTK("[%s]SCL timeout\n", __func__);
+#if 0
+ i2c.regs->cr_reg |= BIT7;/*reset status*/
+ /*spin_lock(&i2c_fifolock);*/
+ list_del(&fifo_head->busfifohead);/*del request*/
+ /*spin_unlock(&i2c_fifolock);*/
+ xfer_length = 0;
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR | I2C_ISR_BYTE_END_WRITE_CLEAR;
+ i2c.isr_timeout = 1 ;
+ wakeup = 1;
+#endif
+ i2c.regs->isr_reg = I2C_ISR_SCL_TIME_OUT_WRITE_CLEAR ;
+ }
+
+
+ if (wakeup) {
+ /*spin_lock_irqsave(&i2c_wmt_irqlock, flags);*/
+ i2c.isr_int_pending = 1;
+ /*spin_unlock_irqrestore(&i2c_wmt_irqlock, flags);*/
+ wake_up(&i2c1_wait);
+ } else
+ DPRINTK("i2c_err : unknown I2C ISR Handle 0x%4.4X" , isr_status) ;
+ spin_unlock_irqrestore(&i2c1_wmt_irqlock, flags);
+ return IRQ_HANDLED;
+}
+
+static int i2c_wmt_resource_init(void)
+{
+ if (is_master == 0)
+ return 0;
+ if (request_irq(i2c.irq_no , &i2c_wmt_handler, IRQF_DISABLED, "i2c", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C: Failed to register I2C irq %i\n", i2c.irq_no);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void i2c_wmt_resource_release(void)
+{
+ if (is_master == 0)
+ return;
+ free_irq(i2c.irq_no, 0);
+}
+
+static struct i2c_algo_wmt_data i2c_wmt_data = {
+ write_msg: i2c_wmt_write_msg,
+ read_msg: i2c_wmt_read_msg,
+ send_request: i2c_send_request,
+ wait_bus_not_busy: i2c_wmt_wait_bus_not_busy,
+ reset: i2c_wmt_reset,
+ set_mode: i2c_wmt_set_mode,
+ udelay: I2C_ALGO_UDELAY,
+ timeout: I2C_ALGO_TIMEOUT,
+};
+
+static struct i2c_adapter i2c_wmt_ops = {
+ .owner = THIS_MODULE,
+ /*
+ .id = I2C_ALGO_WMT,
+ */
+ .algo_data = &i2c_wmt_data,
+ .name = "wmt_i2c_adapter",
+ .retries = I2C_ADAPTER_RETRIES,
+ .nr = 0,
+};
+
+#ifdef CONFIG_PM
+static struct i2c_regs_s wmt_i2c_reg ;
+static void i2c_shutdown(void)
+{
+ printk("i2c0 shutdown\n");
+ wmt_i2c0_power_state = 2;
+ while (!list_empty(&wmt_i2c_fifohead))
+ msleep(1);
+ while (1) {/*wait busy clear*/
+ if ((REG16_VAL(I2C_CSR_ADDR) & I2C_STATUS_MASK) == I2C_READY)
+ break ;
+ msleep(1);
+ }
+ return;
+}
+static int i2c_suspend(void)
+{
+ printk("i2c0 suspend\n");
+ wmt_i2c_reg.imr_reg = i2c.regs->imr_reg;
+ wmt_i2c_reg.tr_reg = i2c.regs->tr_reg;
+ wmt_i2c_reg.div_reg = i2c.regs->div_reg;
+ return 0;
+}
+static void i2c_resume(void)
+{
+ printk("i2c0 resume\n");
+ GPIO_CTRL_GP17_I2C_BYTE_VAL &= ~(BIT0 | BIT1);
+ PULL_EN_GP17_I2C_BYTE_VAL |= (BIT0 | BIT1);
+ PULL_CTRL_GP17_I2C_BYTE_VAL |= (BIT0 | BIT1);
+ auto_pll_divisor(DEV_I2C0, CLK_ENABLE, 0, 0);
+ auto_pll_divisor(DEV_I2C0, SET_DIV, 2, 20);/*20M Hz*/
+
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = wmt_i2c_reg.div_reg;
+ i2c.regs->imr_reg = wmt_i2c_reg.imr_reg;
+ i2c.regs->tr_reg = wmt_i2c_reg.tr_reg ;
+ i2c.regs->cr_reg = 0x001 ;
+}
+#else
+#define i2c_suspend NULL
+#define i2c_resume NULL
+#define i2c_shutdown NULL
+#endif
+extern int wmt_i2c_add_bus(struct i2c_adapter *);
+extern int wmt_i2c_del_bus(struct i2c_adapter *);
+
+#ifdef CONFIG_PM
+static struct syscore_ops wmt_i2c_syscore_ops =
+{
+ .suspend = i2c_suspend,
+ .resume = i2c_resume,
+ .shutdown = i2c_shutdown,
+};
+#endif
+
+static int __init i2c_adap_wmt_init(void)
+{
+ unsigned short tmp ;
+ char varname[] = "wmt.i2c.param";
+#ifdef CONFIG_I2C_SLAVE_WMT
+ char varname1[] = "wmt.bus.i2c.slave_port";
+#endif
+ unsigned char buf[80];
+ int ret;
+ unsigned int port_num;
+ int idx = 0;
+ int varlen = 80;
+ unsigned int pllb_freq = 0;
+ unsigned int tr_val = 0;
+
+#ifdef CONFIG_I2C_SLAVE_WMT
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname1, buf, &varlen);
+#else
+ ret = 1;
+#endif
+ is_master = 1;
+ if (ret == 0) {
+ ret = sscanf(buf, "%x", &port_num);
+ while (ret) {
+ if (port_num != 0)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret;
+ ret = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+#endif
+ wmt_i2c0_is_master = is_master;
+ if (is_master == 1) {
+#ifdef USE_UBOOT_PARA
+ ret = wmt_getsyspara(varname, buf, &varlen);
+#else
+ ret = 1;
+#endif
+
+ if (ret == 0) {
+ ret = sscanf(buf, "%x:%x", &port_num, &speed_mode);
+ idx += 3;
+ while (ret) {
+ if (ret < 2)
+ speed_mode = 0;
+ else {
+ if (port_num != 0)
+ speed_mode = 0;
+ else
+ break;
+ }
+ ret = sscanf(buf + idx, ",%x:%x", &port_num, &speed_mode);
+ idx += 4;
+ }
+ }
+ if (speed_mode > 1)
+ speed_mode = 0;
+ wmt_i2c0_speed_mode = speed_mode;
+
+ /**/
+ /* software initial*/
+ /**/
+ i2c.regs = (struct i2c_regs_s *)I2C0_BASE_ADDR ;
+ i2c.irq_no = IRQ_I2C0 ;
+
+ printk("PORT 0 speed_mode = %d\n", speed_mode);
+ if (speed_mode == 0)
+ i2c.i2c_mode = I2C_STANDARD_MODE ;
+ else if (speed_mode == 1)
+ i2c.i2c_mode = I2C_FAST_MODE ;
+
+ i2c.isr_nack = 0 ;
+ i2c.isr_byte_end = 0 ;
+ i2c.isr_timeout = 0 ;
+ i2c.isr_int_pending = 0;
+ /**/
+ /* hardware initial*/
+ /**/
+ auto_pll_divisor(DEV_I2C0, CLK_ENABLE, 0, 0);
+ pllb_freq = auto_pll_divisor(DEV_I2C0, SET_DIV, 2, 20);/*20M Hz*/
+ if ((pllb_freq%(1000*2*100)) != 0)
+ tr_val = pllb_freq/(1000*2*100) + 1;
+ else
+ tr_val = pllb_freq/(1000*2*100);
+ *(volatile unsigned char *)CTRL_GPIO &= ~(BIT0 | BIT1);
+ *(volatile unsigned char *)PU_EN_GPIO |= (BIT0 | BIT1);
+ *(volatile unsigned char *)PU_CTRL_GPIO |= (BIT0 | BIT1);
+ i2c.regs->cr_reg = 0 ;
+ i2c.regs->div_reg = APB_96M_I2C_DIV ;
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+ i2c.regs->imr_reg = I2C_IMR_ALL_ENABLE ; /* 0x0007*/
+
+ i2c.regs->cr_reg = I2C_CR_ENABLE ;
+ tmp = i2c.regs->csr_reg ; /* read clear*/
+ i2c.regs->isr_reg = I2C_ISR_ALL_WRITE_CLEAR ; /* 0x0007*/
+
+ if (i2c.i2c_mode == I2C_STANDARD_MODE)
+ i2c.regs->tr_reg = 0xff00|tr_val;
+ else if (i2c.i2c_mode == I2C_FAST_MODE) {
+ tr_val /= 4;
+ i2c.regs->tr_reg = 0xff00|tr_val ;
+ }
+ }
+
+
+ if (i2c_wmt_resource_init() == 0) {
+ if (wmt_i2c_add_bus(&i2c_wmt_ops) < 0) {
+ i2c_wmt_resource_release();
+ printk(KERN_INFO "i2c: Failed to add bus\n");
+ return -ENODEV;
+ }
+ } else
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&wmt_i2c_fifohead);
+
+#ifdef CONFIG_PM
+ printk("register i2c0 syscore ops\n");
+ register_syscore_ops(&wmt_i2c_syscore_ops);
+#endif
+ wmt_i2c0_power_state = 0;
+ printk(KERN_INFO "i2c: successfully added bus\n");
+
+#ifdef I2C_REG_TEST
+ printk("i2c.regs->cr_reg= 0x%08x\n\r", i2c.regs->cr_reg);
+ printk("i2c.regs->tcr_reg= 0x%08x\n\r", i2c.regs->tcr_reg);
+ printk("i2c.regs->csr_reg= 0x%08x\n\r", i2c.regs->csr_reg);
+ printk("i2c.regs->isr_reg= 0x%08x\n\r", i2c.regs->isr_reg);
+ printk("i2c.regs->imr_reg= 0x%08x\n\r", i2c.regs->imr_reg);
+ printk("i2c.regs->cdr_reg= 0x%08x\n\r", i2c.regs->cdr_reg);
+ printk("i2c.regs->tr_reg= 0x%08x\n\r", i2c.regs->tr_reg);
+ printk("i2c.regs->div_reg= 0x%08x\n\r", i2c.regs->div_reg);
+#endif
+
+ return 0;
+}
+subsys_initcall(i2c_adap_wmt_init);
+
+static void i2c_adap_wmt_exit(void)
+{
+ wmt_i2c_del_bus(&i2c_wmt_ops);
+ i2c_wmt_resource_release();
+
+ printk(KERN_INFO "i2c: successfully removed bus\n");
+}
+
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT I2C Adapter Driver");
+MODULE_LICENSE("GPL");
+
+module_exit(i2c_adap_wmt_exit);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus-1.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus-1.c
new file mode 100755
index 00000000..90b49ea8
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus-1.c
@@ -0,0 +1,661 @@
+/*++
+ drivers/i2c/busses/wmt-i2c-slave-bus-1.c
+
+ Copyright (c) 2008 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+
+ History:
+ 2010/03/15 First Version
+--*/
+
+#include <linux/config.h>
+#define WMT_I2C1_SLAVE_C
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <asm/semaphore.h>
+#include <linux/proc_fs.h>
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <mach/hardware.h>
+#include "./wmt-i2c-slave-bus.h"
+/*#define DEBUG*/
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+
+#define DEVICE_NAME "WMT_I2C_SLAVE-1"
+#define PMC_ClOCK_ENABLE_LOWER 0xd8130250
+#define CTRL_GPIO21 0xD8110055
+#define PU_EN_GPIO21 0xD8110495
+#define PU_CTRL_GPIO21 0xD81104D5
+
+#define DISABLE_I2C_SLAVE BIT15
+
+struct i2c_slave_msg {
+ __u16 addr; /* slave address */
+ __u16 flags;
+#define I2C_M_RD 0x01
+ __u16 len; /* data length */
+ __u8 *buf; /* pointer to data */
+};
+
+struct slave_i2c_dev_s {
+ /* module parameters */
+ char *buf;
+
+ /* char dev struct */
+ struct cdev cdev;
+ struct class *class_slave_i2c;
+};
+
+
+struct wmt_slave_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int isr_nack ;
+ int isr_byte_end ;
+ int isr_timeout ;
+ int isr_int_pending ;
+ struct compat_semaphore tx_sem;
+ struct compat_semaphore rx_sem;
+};
+
+static struct i2c_regs_s regs_backup;
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int is_master = 1;/*master:1, slave:0*/
+
+static DEFINE_SPINLOCK(slave_i2c_lock);
+
+static int slave_i2c_dev_major = SLAVE_I2C_MAJOR;
+static int slave_i2c_dev_minor = 1;
+static int slave_i2c_dev_nr = 1;
+static struct slave_i2c_dev_s slave_i2c_dev;
+
+static struct wmt_slave_i2c_s slave_i2c_port;
+
+static unsigned char slave_i2c_addr = 0x31;
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *slave_i2c_proc;
+
+static int slave_i2c_reg_read(char *buf, char **start, off_t offset, int len)
+{
+ char *p = buf;
+ p += sprintf(p, "reg : value\n");
+ p += sprintf(p, "cr : 0x%.4x\n", slave_i2c_port.regs->cr_reg);
+ p += sprintf(p, "tcr : 0x%.4x\n", slave_i2c_port.regs->tcr_reg);
+ p += sprintf(p, "csr : 0x%.4x\n", slave_i2c_port.regs->csr_reg);
+ p += sprintf(p, "isr : 0x%.4x\n", slave_i2c_port.regs->isr_reg);
+ p += sprintf(p, "imr : 0x%.4x\n", slave_i2c_port.regs->imr_reg);
+ p += sprintf(p, "cdr : 0x%.4x\n", slave_i2c_port.regs->cdr_reg);
+ p += sprintf(p, "tr : 0x%.4x\n", slave_i2c_port.regs->tr_reg);
+ p += sprintf(p, "scr : 0x%.4x\n", slave_i2c_port.regs->scr_reg);
+ p += sprintf(p, "cssr : 0x%.4x\n", slave_i2c_port.regs->cssr_reg);
+ p += sprintf(p, "simr : 0x%.4x\n", slave_i2c_port.regs->simr_reg);
+ p += sprintf(p, "sisr : 0x%.4x\n", slave_i2c_port.regs->sisr_reg);
+ p += sprintf(p, "csdr : 0x%.4x\n", slave_i2c_port.regs->csdr_reg);
+ p += sprintf(p, "str : 0x%.4x\n", slave_i2c_port.regs->str_reg);
+ return p - buf;
+}
+
+static int slave_i2c_addr_read(char *buf, char **start, off_t offset, int len)
+{
+ char *p = buf;
+ p += sprintf(p, "i2c-slave address : 0x%.2x\n", slave_i2c_addr);
+ return p - buf;
+}
+
+#endif
+
+static irqreturn_t slave_i2c_isr(
+ int irq, /*!<; // IRQ number */
+ void *dev, /*!<; // Private paramater(i.e. pointer of spi port) */
+ struct pt_regs *regs /*!<; // interrupt register */
+)
+{
+ unsigned short isr_status = slave_i2c_port.regs->sisr_reg;
+ unsigned short ssr_status = slave_i2c_port.regs->cssr_reg;
+ DPRINTK("slave_i2c isr sisr = %x\n", isr_status);
+ DPRINTK("slave_i2c isr cssr = %x\n", ssr_status);
+ if (isr_status & I2C_SISR_DAT_REQ) {
+ slave_i2c_port.regs->sisr_reg |= I2C_SISR_DAT_REQ_WRITE_CLEAR;
+ slave_i2c_port.isr_nack = ssr_status & I2C_SRCV_NACK_MASK;
+ compat_up(&slave_i2c_port.tx_sem);
+ } else if (isr_status & I2C_SISR_BYTE_END) {
+ slave_i2c_port.regs->sisr_reg |= I2C_SISR_BYTE_END_WRITE_CLEAR;
+ slave_i2c_port.isr_byte_end = 1;
+ slave_i2c_port.isr_nack = ssr_status & I2C_SRCV_NACK_MASK;
+ compat_up(&slave_i2c_port.rx_sem);
+ } else if (isr_status & I2C_SISR_SCL_TIME_OUT) {
+ slave_i2c_port.regs->sisr_reg |= I2C_SISR_SCL_TIME_OUT_WRITE_CLEAR;
+ slave_i2c_port.isr_timeout = 1 ;
+ }
+ return IRQ_HANDLED;
+}
+
+static int wmt_slave_i2c_read_data(unsigned short addr , unsigned char *buf, int size, int flags)
+{
+ int ret = 0;
+ int xfer_len = 0;
+ int sleep_count = 1;
+ DPRINTK("ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+ while (xfer_len < size) {
+ compat_down_interruptible(&slave_i2c_port.rx_sem);
+ buf[xfer_len] = ((slave_i2c_port.regs->csdr_reg & I2C_SLAVE_READ_DATA_MASK) >> I2C_SLAVE_READ_DATA_SHIFT);
+ DPRINTK("data = %x\n", buf[xfer_len]);
+ xfer_len++;
+ }
+ ret = xfer_len;
+ while (slave_i2c_port.regs->cssr_reg & I2C_SLAVE_ACTIVE) {
+ if (compat_sema_count(&slave_i2c_port.rx_sem) > 0) {/*receive data was longer than request*/
+ ret = -1;
+ break;
+ }
+ msleep(sleep_count);
+ if (sleep_count < 16)
+ sleep_count *= 2;
+ }
+ DPRINTK("ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+
+ return ret;
+}
+
+static int wmt_slave_i2c_write_data(unsigned short addr, unsigned char *buf, int size, int flags)
+{
+ int ret = 0;
+ int xfer_len = 0;
+ int sleep_count = 1;
+ DPRINTK("tx ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+ while (xfer_len < size) {
+ compat_down_interruptible(&slave_i2c_port.tx_sem);
+ slave_i2c_port.regs->csdr_reg = buf[xfer_len];
+ DPRINTK("data = %x\n", buf[xfer_len]);
+ ++xfer_len;
+ }
+ ret = xfer_len;
+ while (slave_i2c_port.regs->cssr_reg & I2C_SLAVE_ACTIVE) {
+ msleep(sleep_count);
+ if (sleep_count < 16)
+ sleep_count *= 2;
+ }
+ DPRINTK("2.tx ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+ return ret;
+}
+
+static int slave_i2c_do_xfer(unsigned short addr, unsigned char *buf, int size, int flags)
+{
+ int ret;
+ if (flags & I2C_M_RD)
+ ret = wmt_slave_i2c_read_data(addr , buf, size, flags);
+ else
+ ret = wmt_slave_i2c_write_data(addr , buf, size, flags);
+ return ret;
+}
+
+int wmt_i2cslave_transfer1(struct i2c_slave_msg slave_msg)
+{
+ int flags = slave_msg.flags;
+ unsigned char *buf = slave_msg.buf;
+ unsigned short addr = slave_msg.addr;
+ int size = slave_msg.len;
+ int xfer_len;
+ if (is_master == 1)
+ return 0;
+ spin_lock(&slave_i2c_lock);
+ xfer_len = slave_i2c_do_xfer(addr, buf, size, flags);
+ spin_unlock(&slave_i2c_lock);
+ return xfer_len;
+}
+EXPORT_SYMBOL(wmt_i2cslave_transfer1);
+
+void wmt_i2cslave_setaddr1(struct i2c_slave_msg msg)
+{
+ if (is_master == 1)
+ return;
+ spin_lock(&slave_i2c_lock);
+
+ slave_i2c_addr = msg.addr;
+
+ if (msg.addr & DISABLE_I2C_SLAVE)
+ slave_i2c_port.regs->cr_reg &= ~I2C_CR_ENABLE;
+ else {
+ slave_i2c_port.regs->cr_reg = 0;
+ slave_i2c_port.regs->scr_reg = 0;
+ slave_i2c_port.regs->cr_reg = (I2C_SLAV_MODE_SEL|I2C_CR_ENABLE);
+ slave_i2c_port.regs->sisr_reg = I2C_SISR_ALL_WRITE_CLEAR;
+
+ if (slave_i2c_port.i2c_mode == I2C_STANDARD_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else if (slave_i2c_port.i2c_mode == I2C_FAST_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else
+ slave_i2c_port.regs->scr_reg = (slave_i2c_addr|I2C_SLAVE_HS_MODE);
+
+ slave_i2c_port.regs->simr_reg = I2C_SIMR_ALL_ENABLE;
+ }
+ spin_unlock(&slave_i2c_lock);
+}
+EXPORT_SYMBOL(wmt_i2cslave_setaddr1);
+
+static ssize_t slave_i2c_read(
+ struct file *filp,
+ char __user *buf,
+ size_t count,
+ loff_t *f_pos
+)
+{
+ int ret = 0;
+ struct i2c_slave_msg slave_msg;
+ if (is_master == 1)
+ return ret;
+ slave_msg.buf = (char *)kmalloc(count * sizeof(unsigned char), GFP_KERNEL);
+ slave_msg.flags = 0;
+ slave_msg.flags |= I2C_M_RD;
+ slave_msg.len = count;
+ slave_msg.addr = slave_i2c_addr;
+ ret = wmt_i2cslave_transfer1(slave_msg);
+ if (copy_to_user(buf, slave_msg.buf, count)) {
+ kfree(slave_msg.buf);
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static ssize_t slave_i2c_write(
+ struct file *filp,
+ const char __user *buf,
+ size_t count,
+ loff_t *f_pos
+)
+{
+ int ret = 0;
+ struct i2c_slave_msg slave_msg;
+ if (is_master == 1)
+ return ret;
+ slave_msg.buf = (char *)kmalloc(count * sizeof(unsigned char), GFP_KERNEL);
+ slave_msg.flags = 0;
+ slave_msg.flags &= ~I2C_M_RD;
+ slave_msg.len = count;
+ slave_msg.addr = slave_i2c_addr;
+ if (copy_from_user(slave_msg.buf, buf, count)) {
+ kfree(slave_msg.buf);
+ return -EFAULT;
+ }
+ ret = wmt_i2cslave_transfer1(slave_msg);
+ return ret; /* return Write out data size*/
+}
+
+static int slave_i2c_open(
+ struct inode *inode,
+ struct file *filp
+)
+{
+ struct slave_i2c_dev_s *dev;
+ char name[40];
+ int minor_no;
+
+ dev = container_of(inode->i_cdev, struct slave_i2c_dev_s, cdev);
+ filp->private_data = dev;
+ minor_no = iminor(inode); /* get */
+
+ /* Create user name*/
+ memset(name, 0x0, 8);
+ sprintf(name, "slave-i2c%d", minor_no);
+ return 0;
+}
+
+static int slave_i2c_release(
+ struct inode *inode,
+ struct file *filp
+)
+{
+ struct slave_i2c_dev_s *dev;
+ int minor_no;
+
+ dev = container_of(inode->i_cdev, struct slave_i2c_dev_s, cdev);
+ minor_no = iminor(inode);
+
+ return 0;
+}
+
+static int slave_i2c_ioctl(
+ struct inode *inode,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg
+)
+{
+ int ret = 0;
+ struct i2c_slave_msg slave_msg[1];
+ unsigned char *data_ptr;
+ unsigned char __user *usr_ptr;
+ switch (cmd) {
+ case IOCTL_DO_TRANSFER:
+ if (copy_from_user(slave_msg, (struct i2c_slave_msg *)arg,
+ sizeof(struct i2c_slave_msg)))
+ return -EFAULT;
+
+ data_ptr = (unsigned char *)kmalloc(slave_msg->len*sizeof(unsigned char), GFP_KERNEL);
+ usr_ptr = (unsigned char __user *)slave_msg->buf;
+
+ if (copy_from_user(data_ptr, (unsigned char *)slave_msg->buf,
+ slave_msg->len*sizeof(unsigned char))) {
+ kfree(data_ptr);
+ return -EFAULT;
+ }
+ slave_msg->buf = data_ptr;
+
+ ret = wmt_i2cslave_transfer1((struct i2c_slave_msg)*slave_msg);
+
+ if (slave_msg->flags & I2C_M_RD) {
+ if (copy_to_user(
+ usr_ptr,
+ data_ptr,
+ slave_msg->len))
+ ret = -EFAULT;
+ }
+
+ kfree(data_ptr);
+ break;
+ case IOCTL_SET_ADDR:
+ if (copy_from_user(slave_msg, (struct i2c_slave_msg *)arg,
+ sizeof(struct i2c_slave_msg)))
+ return -EFAULT;
+ wmt_i2cslave_setaddr1((struct i2c_slave_msg) *slave_msg);
+ break;
+ case IOCTL_QUERY_DATA:
+ break;
+ case IOCTL_SET_SPEED_MODE:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+/*!*************************************************************************
+ driver file operations struct define
+****************************************************************************/
+static struct file_operations i2c_slave_fops = {
+ .owner = THIS_MODULE,
+ .open = slave_i2c_open,
+ .read = slave_i2c_read,
+ .write = slave_i2c_write,
+ .ioctl = slave_i2c_ioctl,
+ .release = slave_i2c_release,
+};
+
+static int slave_i2c_probe(
+ struct device *dev
+)
+{
+ int ret = 0;
+ dev_t dev_no;
+ struct cdev *cdev;
+ char name[40];
+ char buf[80];
+ unsigned int port_num;
+ int idx = 0;
+ char varname1[] = "wmt.bus.i2c.slave_port";
+ int ret_val = 0;
+ int varlen = 80;
+ memset(name, 0, 40);
+
+ dev_no = MKDEV(slave_i2c_dev_major, slave_i2c_dev_minor);
+
+ sprintf(name, "wmt_i2cslave%d",slave_i2c_dev_minor);
+ cdev = &slave_i2c_dev.cdev;
+ cdev_init(cdev, &i2c_slave_fops);
+ ret = cdev_add(cdev, dev_no, 8);
+ slave_i2c_dev.class_slave_i2c = class_create(THIS_MODULE, "wmt_i2cslave1");
+ device_create(slave_i2c_dev.class_slave_i2c, NULL ,
+ MKDEV(slave_i2c_dev_major,slave_i2c_dev_minor),
+ NULL, name);
+ if (ret) {
+ printk(KERN_ALERT "*E* register char dev \n");
+ return ret;
+ }
+
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *res;
+
+ slave_i2c_proc = proc_mkdir("driver/wmt_i2cslave1", NULL);
+ /*
+ slave_i2c_proc->owner = THIS_MODULE;
+ */
+ res = create_proc_entry("registers", 0, slave_i2c_proc);
+ if (res) {
+ res->read_proc = slave_i2c_reg_read;
+ }
+
+ res = create_proc_entry("address", 0, slave_i2c_proc);
+ if (res) {
+ res->read_proc = slave_i2c_addr_read;
+ }
+#endif
+ slave_i2c_port.regs = (struct i2c_regs_s *)I2C1_BASE_ADDR;
+ slave_i2c_port.irq_no = IRQ_I2C1;
+ slave_i2c_port.i2c_mode = I2C_STANDARD_MODE;
+ slave_i2c_port.isr_nack = 0;
+ slave_i2c_port.isr_byte_end = 0;
+ slave_i2c_port.isr_timeout = 0;
+ slave_i2c_port.isr_int_pending = 0;
+ compat_sema_init(&slave_i2c_port.tx_sem, 0);
+ compat_sema_init(&slave_i2c_port.rx_sem, 0);
+ ret_val = wmt_getsyspara(varname1, buf, &varlen);
+ is_master = 1;
+ if (ret_val == 0) {
+ ret_val = sscanf(buf, "%x", &port_num);
+ while (ret_val) {
+ if (port_num != 1)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret_val;
+ ret_val = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+ /**/
+ /* hardware initial*/
+ /**/
+ if (is_master == 0) {
+ *(volatile unsigned int *)PMC_ClOCK_ENABLE_LOWER |= (BIT0);
+ *(volatile unsigned int *)CTRL_GPIO21 &= ~(BIT2 | BIT3);
+ *(volatile unsigned int *)PU_EN_GPIO21 |= (BIT2 | BIT3);
+ *(volatile unsigned int *)PU_CTRL_GPIO21 |= (BIT2 | BIT3);
+
+ /*set i2c slave register*/
+ slave_i2c_port.regs->cr_reg = 0;
+ slave_i2c_port.regs->scr_reg = 0;
+ slave_i2c_port.regs->cr_reg = (I2C_SLAV_MODE_SEL|I2C_CR_ENABLE);
+ slave_i2c_port.regs->sisr_reg = I2C_SISR_ALL_WRITE_CLEAR;
+
+ if (slave_i2c_port.i2c_mode == I2C_STANDARD_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else if (slave_i2c_port.i2c_mode == I2C_FAST_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else
+ slave_i2c_port.regs->scr_reg = (slave_i2c_addr|I2C_SLAVE_HS_MODE);
+
+ slave_i2c_port.regs->simr_reg = I2C_SIMR_ALL_ENABLE;
+
+ slave_i2c_port.regs->cr_reg &= ~I2C_CR_ENABLE;
+
+ if (request_irq(slave_i2c_port.irq_no , &slave_i2c_isr, IRQF_DISABLED, "i2c-slave", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C-SLAVE: Failed to register I2C-SLAVE irq %i\n", slave_i2c_port.irq_no);
+ return -ENODEV;
+ }
+ }
+
+ return ret;
+}
+
+static int slave_i2c_remove(
+ struct device *dev /*!<; // please add parameters description her*/
+)
+{
+ struct cdev *cdev;
+
+ cdev = &slave_i2c_dev.cdev;
+ cdev_del(cdev);
+
+ return 0;
+} /* End of spi_remove() */
+
+static void slave_i2c_backup(void)
+{
+ regs_backup.cr_reg = slave_i2c_port.regs->cr_reg;
+ regs_backup.tcr_reg = slave_i2c_port.regs->tcr_reg;
+ regs_backup.scr_reg = slave_i2c_port.regs->scr_reg;
+ regs_backup.simr_reg = slave_i2c_port.regs->simr_reg;
+ regs_backup.str_reg = slave_i2c_port.regs->str_reg;
+
+}
+
+static void slave_i2c_restore(void)
+{
+ slave_i2c_port.regs->cr_reg = 0;
+ slave_i2c_port.regs->cr_reg = regs_backup.cr_reg;
+ slave_i2c_port.regs->tcr_reg = regs_backup.tcr_reg;
+ slave_i2c_port.regs->scr_reg = regs_backup.scr_reg;
+ slave_i2c_port.regs->simr_reg = regs_backup.simr_reg;
+ slave_i2c_port.regs->str_reg = regs_backup.str_reg;
+}
+
+static int slave_i2c_suspend(
+ struct device *dev, /*!<; // please add parameters description her*/
+ pm_message_t state /*!<; // please add parameters description her*/
+)
+{
+ if (is_master == 1)
+ return 0;
+ slave_i2c_backup();
+ compat_sema_init(&slave_i2c_port.tx_sem, 0);
+ compat_sema_init(&slave_i2c_port.rx_sem, 0);
+ return 0;
+}
+
+
+static int slave_i2c_resume(
+ struct device *dev
+)
+{
+ if (is_master == 1)
+ return 0;
+ *(volatile unsigned int *)PMC_ClOCK_ENABLE_LOWER |= (BIT0);
+ *(volatile unsigned int *)CTRL_GPIO21 &= ~(BIT2 | BIT3);
+ *(volatile unsigned int *)PU_EN_GPIO21 |= (BIT2 | BIT3);
+ *(volatile unsigned int *)PU_CTRL_GPIO21 |= (BIT2 | BIT3);
+ slave_i2c_restore();
+ return 0;
+}
+
+/*!*************************************************************************
+ device driver struct define
+****************************************************************************/
+static struct device_driver slave_i2c_driver = {
+ .name = "wmt_i2c_slave_1", /* This name should equal to platform device name.*/
+ .bus = &platform_bus_type,
+ .probe = slave_i2c_probe,
+ .remove = slave_i2c_remove,
+ .suspend = slave_i2c_suspend,
+ .resume = slave_i2c_resume
+};
+
+static void slave_i2c_platform_release(
+ struct device *device
+)
+{
+}
+
+/*!*************************************************************************
+ platform device struct define
+****************************************************************************/
+
+static struct platform_device slave_i2c_device = {
+ .name = "wmt_i2c_slave_1",
+ .id = 1,
+ .dev = { .release = slave_i2c_platform_release,
+ },
+ .num_resources = 0,
+ .resource = NULL,
+};
+
+static int slave_i2c_init(void)
+{
+ int ret;
+ dev_t dev_no;
+ char dev_name[40];
+ memset(dev_name, 0, 40);
+ sprintf(dev_name, "wmt_i2c_slave%d", slave_i2c_device.id);
+
+ if (slave_i2c_dev_major) {
+ dev_no = MKDEV(slave_i2c_dev_major, slave_i2c_dev_minor);
+ ret = register_chrdev_region(dev_no, slave_i2c_dev_nr, dev_name);
+ } else {
+ ret = alloc_chrdev_region(&dev_no, slave_i2c_dev_minor, slave_i2c_dev_nr, dev_name);
+ slave_i2c_dev_major = MAJOR(dev_no);
+ }
+
+ if (ret < 0) {
+ printk(KERN_ALERT "*E* can't get major %d\n", slave_i2c_dev_major);
+ return ret;
+ }
+
+ platform_device_register(&slave_i2c_device);
+ ret = driver_register(&slave_i2c_driver);
+
+ return ret;
+}
+
+module_init(slave_i2c_init);
+
+static void slave_i2c_exit(void)
+{
+ dev_t dev_no;
+
+ driver_unregister(&slave_i2c_driver);
+ platform_device_unregister(&slave_i2c_device);
+ dev_no = MKDEV(slave_i2c_dev_major, slave_i2c_dev_minor);
+ unregister_chrdev_region(dev_no, slave_i2c_dev_nr);
+
+ return;
+}
+
+module_exit(slave_i2c_exit);
+
+MODULE_AUTHOR("WMT SW Team");
+MODULE_DESCRIPTION("WMT_slave_i2c device driver");
+MODULE_LICENSE("GPL");
+#undef WMT_I2C_SLAVE_C
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.c b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.c
new file mode 100755
index 00000000..547e5ad0
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.c
@@ -0,0 +1,662 @@
+/*++
+ drivers/i2c/busses/wmt-i2c-slave-bus.c
+
+ Copyright (c) 2008 WonderMedia Technologies, 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+
+ History:
+ 2010/03/11 First Version
+--*/
+
+#include <linux/config.h>
+#define WMT_I2C_SLAVE_C
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <asm/semaphore.h>
+#include <linux/proc_fs.h>
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <mach/hardware.h>
+#include "./wmt-i2c-slave-bus.h"
+/*#define DEBUG*/
+#ifdef DEBUG
+
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+
+#define DEVICE_NAME "WMT_I2C_SLAVE-0"
+#define PMC_ClOCK_ENABLE_LOWER 0xd8130250
+#define CTRL_GPIO21 0xD8110055
+#define PU_EN_GPIO21 0xD8110495
+#define PU_CTRL_GPIO21 0xD81104D5
+
+#define DISABLE_I2C_SLAVE BIT15
+
+struct i2c_slave_msg {
+ __u16 addr; /* slave address */
+ __u16 flags;
+#define I2C_M_RD 0x01
+ __u16 len; /* data length */
+ __u8 *buf; /* pointer to data */
+};
+
+struct slave_i2c_dev_s {
+ /* module parameters */
+ char *buf;
+
+ /* char dev struct */
+ struct cdev cdev;
+ struct class *class_slave_i2c;
+};
+
+
+struct wmt_slave_i2c_s {
+ struct i2c_regs_s *regs;
+ int irq_no ;
+ enum i2c_mode_e i2c_mode ;
+ int isr_nack ;
+ int isr_byte_end ;
+ int isr_timeout ;
+ int isr_int_pending ;
+ struct compat_semaphore tx_sem;
+ struct compat_semaphore rx_sem;
+};
+
+static struct i2c_regs_s regs_backup;
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static unsigned int is_master = 1;/*master:1, slave:0*/
+
+static DEFINE_SPINLOCK(slave_i2c_lock);
+
+static int slave_i2c_dev_major = SLAVE_I2C_MAJOR;
+static int slave_i2c_dev_minor;
+static int slave_i2c_dev_nr = 1;
+static struct slave_i2c_dev_s slave_i2c_dev;
+
+static struct wmt_slave_i2c_s slave_i2c_port;
+
+static unsigned char slave_i2c_addr = 0x31;
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *slave_i2c_proc;
+
+static int slave_i2c_reg_read(char *buf, char **start, off_t offset, int len)
+{
+ char *p = buf;
+ p += sprintf(p, "reg : value\n");
+ p += sprintf(p, "cr : 0x%.4x\n", slave_i2c_port.regs->cr_reg);
+ p += sprintf(p, "tcr : 0x%.4x\n", slave_i2c_port.regs->tcr_reg);
+ p += sprintf(p, "csr : 0x%.4x\n", slave_i2c_port.regs->csr_reg);
+ p += sprintf(p, "isr : 0x%.4x\n", slave_i2c_port.regs->isr_reg);
+ p += sprintf(p, "imr : 0x%.4x\n", slave_i2c_port.regs->imr_reg);
+ p += sprintf(p, "cdr : 0x%.4x\n", slave_i2c_port.regs->cdr_reg);
+ p += sprintf(p, "tr : 0x%.4x\n", slave_i2c_port.regs->tr_reg);
+ p += sprintf(p, "scr : 0x%.4x\n", slave_i2c_port.regs->scr_reg);
+ p += sprintf(p, "cssr : 0x%.4x\n", slave_i2c_port.regs->cssr_reg);
+ p += sprintf(p, "simr : 0x%.4x\n", slave_i2c_port.regs->simr_reg);
+ p += sprintf(p, "sisr : 0x%.4x\n", slave_i2c_port.regs->sisr_reg);
+ p += sprintf(p, "csdr : 0x%.4x\n", slave_i2c_port.regs->csdr_reg);
+ p += sprintf(p, "str : 0x%.4x\n", slave_i2c_port.regs->str_reg);
+ return p - buf;
+}
+
+static int slave_i2c_addr_read(char *buf, char **start, off_t offset, int len)
+{
+ char *p = buf;
+ p += sprintf(p, "i2c-slave address : 0x%.2x\n", slave_i2c_addr);
+ return p - buf;
+}
+
+#endif
+
+static irqreturn_t slave_i2c_isr(
+ int irq, /*!<; // IRQ number */
+ void *dev, /*!<; // Private paramater(i.e. pointer of spi port) */
+ struct pt_regs *regs /*!<; // interrupt register */
+)
+{
+ unsigned short isr_status = slave_i2c_port.regs->sisr_reg;
+ unsigned short ssr_status = slave_i2c_port.regs->cssr_reg;
+ DPRINTK("slave_i2c isr sisr = %x\n", isr_status);
+ DPRINTK("slave_i2c isr cssr = %x\n", ssr_status);
+ if (isr_status & I2C_SISR_DAT_REQ) {
+ slave_i2c_port.regs->sisr_reg |= I2C_SISR_DAT_REQ_WRITE_CLEAR;
+ slave_i2c_port.isr_nack = ssr_status & I2C_SRCV_NACK_MASK;
+ compat_up(&slave_i2c_port.tx_sem);
+ } else if (isr_status & I2C_SISR_BYTE_END) {
+ slave_i2c_port.regs->sisr_reg |= I2C_SISR_BYTE_END_WRITE_CLEAR;
+ slave_i2c_port.isr_byte_end = 1;
+ slave_i2c_port.isr_nack = ssr_status & I2C_SRCV_NACK_MASK;
+ compat_up(&slave_i2c_port.rx_sem);
+ } else if (isr_status & I2C_SISR_SCL_TIME_OUT) {
+ slave_i2c_port.regs->sisr_reg |= I2C_SISR_SCL_TIME_OUT_WRITE_CLEAR;
+ slave_i2c_port.isr_timeout = 1 ;
+ }
+ return IRQ_HANDLED;
+}
+
+static int wmt_slave_i2c_read_data(unsigned short addr , unsigned char *buf, int size, int flags)
+{
+ int ret = 0;
+ int xfer_len = 0;
+ int sleep_count = 1;
+ DPRINTK("ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+ while (xfer_len < size) {
+ compat_down_interruptible(&slave_i2c_port.rx_sem);
+ buf[xfer_len] = ((slave_i2c_port.regs->csdr_reg & I2C_SLAVE_READ_DATA_MASK) >> I2C_SLAVE_READ_DATA_SHIFT);
+ DPRINTK("data = %x\n", buf[xfer_len]);
+ xfer_len++;
+ }
+ ret = xfer_len;
+ while (slave_i2c_port.regs->cssr_reg & I2C_SLAVE_ACTIVE) {
+ if (compat_sema_count(&slave_i2c_port.rx_sem) > 0) {/*receive data was longer than request*/
+ ret = -1;
+ break;
+ }
+ msleep(sleep_count);
+ if (sleep_count < 16)
+ sleep_count *= 2;
+ }
+ DPRINTK("ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+
+ return ret;
+}
+
+static int wmt_slave_i2c_write_data(unsigned short addr, unsigned char *buf, int size, int flags)
+{
+ int ret = 0;
+ int xfer_len = 0;
+ int sleep_count = 1;
+ DPRINTK("tx ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+ while (xfer_len < size) {
+ compat_down_interruptible(&slave_i2c_port.tx_sem);
+ slave_i2c_port.regs->csdr_reg = buf[xfer_len];
+ DPRINTK("data = %x\n", buf[xfer_len]);
+ ++xfer_len;
+ }
+ ret = xfer_len;
+ while (slave_i2c_port.regs->cssr_reg & I2C_SLAVE_ACTIVE) {
+ msleep(sleep_count);
+ if (sleep_count < 16)
+ sleep_count *= 2;
+ }
+ DPRINTK("2.tx ssr = %x, isr = %x\n", slave_i2c_port.regs->cssr_reg, slave_i2c_port.regs->sisr_reg);
+ return ret;
+}
+
+static int slave_i2c_do_xfer(unsigned short addr, unsigned char *buf, int size, int flags)
+{
+ int ret;
+ if (flags & I2C_M_RD)
+ ret = wmt_slave_i2c_read_data(addr , buf, size, flags);
+ else
+ ret = wmt_slave_i2c_write_data(addr , buf, size, flags);
+ return ret;
+}
+
+int wmt_i2cslave_transfer0(struct i2c_slave_msg slave_msg)
+{
+ int flags = slave_msg.flags;
+ unsigned char *buf = slave_msg.buf;
+ unsigned short addr = slave_msg.addr;
+ int size = slave_msg.len;
+ int xfer_len;
+ if (is_master == 1)
+ return 0;
+ spin_lock(&slave_i2c_lock);
+ xfer_len = slave_i2c_do_xfer(addr, buf, size, flags);
+ spin_unlock(&slave_i2c_lock);
+ return xfer_len;
+}
+EXPORT_SYMBOL(wmt_i2cslave_transfer0);
+
+void wmt_i2cslave_setaddr0(struct i2c_slave_msg msg)
+{
+ if (is_master == 1)
+ return;
+ spin_lock(&slave_i2c_lock);
+
+ slave_i2c_addr = msg.addr;
+
+ if (msg.addr & DISABLE_I2C_SLAVE)
+ slave_i2c_port.regs->cr_reg &= ~I2C_CR_ENABLE;
+ else {
+ slave_i2c_port.regs->cr_reg = 0;
+ slave_i2c_port.regs->scr_reg = 0;
+ slave_i2c_port.regs->cr_reg = (I2C_SLAV_MODE_SEL|I2C_CR_ENABLE);
+ slave_i2c_port.regs->sisr_reg = I2C_SISR_ALL_WRITE_CLEAR;
+
+ if (slave_i2c_port.i2c_mode == I2C_STANDARD_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else if (slave_i2c_port.i2c_mode == I2C_FAST_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else
+ slave_i2c_port.regs->scr_reg = (slave_i2c_addr|I2C_SLAVE_HS_MODE);
+
+ slave_i2c_port.regs->simr_reg = I2C_SIMR_ALL_ENABLE;
+ }
+ spin_unlock(&slave_i2c_lock);
+}
+EXPORT_SYMBOL(wmt_i2cslave_setaddr0);
+
+static ssize_t slave_i2c_read(
+ struct file *filp,
+ char __user *buf,
+ size_t count,
+ loff_t *f_pos
+)
+{
+ int ret = 0;
+ struct i2c_slave_msg slave_msg;
+ if (is_master == 1)
+ return ret;
+ slave_msg.buf = (char *)kmalloc(count * sizeof(unsigned char), GFP_KERNEL);
+ slave_msg.flags = 0;
+ slave_msg.flags |= I2C_M_RD;
+ slave_msg.len = count;
+ slave_msg.addr = slave_i2c_addr;
+ ret = wmt_i2cslave_transfer0(slave_msg);
+ if (copy_to_user(buf, slave_msg.buf, count)) {
+ kfree(slave_msg.buf);
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static ssize_t slave_i2c_write(
+ struct file *filp,
+ const char __user *buf,
+ size_t count,
+ loff_t *f_pos
+)
+{
+ int ret = 0;
+ struct i2c_slave_msg slave_msg;
+ if (is_master == 1)
+ return ret;
+ slave_msg.buf = (char *)kmalloc(count * sizeof(unsigned char), GFP_KERNEL);
+ slave_msg.flags = 0;
+ slave_msg.flags &= ~I2C_M_RD;
+ slave_msg.len = count;
+ slave_msg.addr = slave_i2c_addr;
+ if (copy_from_user(slave_msg.buf, buf, count)) {
+ kfree(slave_msg.buf);
+ return -EFAULT;
+ }
+ ret = wmt_i2cslave_transfer0(slave_msg);
+ return ret; /* return Write out data size*/
+}
+
+static int slave_i2c_open(
+ struct inode *inode,
+ struct file *filp
+)
+{
+ struct slave_i2c_dev_s *dev;
+ char name[40];
+ int minor_no;
+
+ dev = container_of(inode->i_cdev, struct slave_i2c_dev_s, cdev);
+ filp->private_data = dev;
+ minor_no = iminor(inode); /* get */
+
+ /* Create user name*/
+ memset(name, 0x0, 8);
+ sprintf(name, "slave-i2c%d", minor_no);
+ return 0;
+}
+
+static int slave_i2c_release(
+ struct inode *inode,
+ struct file *filp
+)
+{
+ struct slave_i2c_dev_s *dev;
+ int minor_no;
+
+ dev = container_of(inode->i_cdev, struct slave_i2c_dev_s, cdev);
+ minor_no = iminor(inode);
+
+ return 0;
+}
+
+static int slave_i2c_ioctl(
+ struct inode *inode,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg
+)
+{
+ int ret = 0;
+ struct i2c_slave_msg slave_msg[1];
+ unsigned char *data_ptr;
+ unsigned char __user *usr_ptr;
+ switch (cmd) {
+ case IOCTL_DO_TRANSFER:
+ if (copy_from_user(slave_msg, (struct i2c_slave_msg *)arg,
+ sizeof(struct i2c_slave_msg)))
+ return -EFAULT;
+
+ data_ptr = (unsigned char *)kmalloc(slave_msg->len*sizeof(unsigned char), GFP_KERNEL);
+ usr_ptr = (unsigned char __user *)slave_msg->buf;
+
+ if (copy_from_user(data_ptr, (unsigned char *)slave_msg->buf,
+ slave_msg->len*sizeof(unsigned char))) {
+ kfree(data_ptr);
+ return -EFAULT;
+ }
+ slave_msg->buf = data_ptr;
+
+ ret = wmt_i2cslave_transfer0((struct i2c_slave_msg)*slave_msg);
+
+ if (slave_msg->flags & I2C_M_RD) {
+ if (copy_to_user(
+ usr_ptr,
+ data_ptr,
+ slave_msg->len))
+ ret = -EFAULT;
+ }
+
+ kfree(data_ptr);
+ break;
+ case IOCTL_SET_ADDR:
+ if (copy_from_user(slave_msg, (struct i2c_slave_msg *)arg,
+ sizeof(struct i2c_slave_msg)))
+ return -EFAULT;
+ wmt_i2cslave_setaddr0((struct i2c_slave_msg) *slave_msg);
+ break;
+ case IOCTL_QUERY_DATA:
+ break;
+ case IOCTL_SET_SPEED_MODE:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+/*!*************************************************************************
+ driver file operations struct define
+****************************************************************************/
+static struct file_operations i2c_slave_fops = {
+ .owner = THIS_MODULE,
+ .open = slave_i2c_open,
+ .read = slave_i2c_read,
+ .write = slave_i2c_write,
+ .ioctl = slave_i2c_ioctl,
+ .release = slave_i2c_release,
+};
+
+static int slave_i2c_probe(
+ struct device *dev
+)
+{
+ int ret = 0;
+ dev_t dev_no;
+ struct cdev *cdev;
+ char name[40];
+ char buf[80];
+ unsigned int port_num;
+ int idx = 0;
+ char varname1[] = "wmt.bus.i2c.slave_port";
+ int ret_val = 0;
+ int varlen = 80;
+ memset(name, 0, 40);
+
+ dev_no = MKDEV(slave_i2c_dev_major, slave_i2c_dev_minor);
+
+ sprintf(name, "wmt_i2cslave%d",slave_i2c_dev_minor);
+ cdev = &slave_i2c_dev.cdev;
+ cdev_init(cdev, &i2c_slave_fops);
+ ret = cdev_add(cdev, dev_no, 8);
+ slave_i2c_dev.class_slave_i2c = class_create(THIS_MODULE, "wmt_i2cslave");
+ device_create(slave_i2c_dev.class_slave_i2c, NULL ,
+ MKDEV(slave_i2c_dev_major,slave_i2c_dev_minor),
+ NULL, name);
+ if (ret) {
+ printk(KERN_ALERT "*E* register char dev \n");
+ return ret;
+ }
+
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *res;
+
+ slave_i2c_proc = proc_mkdir("driver/wmt_i2cslave0", NULL);
+ /*
+ slave_i2c_proc->owner = THIS_MODULE;
+ */
+ res = create_proc_entry("registers", 0, slave_i2c_proc);
+ if (res) {
+ res->read_proc = slave_i2c_reg_read;
+ }
+
+ res = create_proc_entry("address", 0, slave_i2c_proc);
+ if (res) {
+ res->read_proc = slave_i2c_addr_read;
+ }
+#endif
+ slave_i2c_port.regs = (struct i2c_regs_s *)I2C0_BASE_ADDR;
+ slave_i2c_port.irq_no = IRQ_I2C0;
+ slave_i2c_port.i2c_mode = I2C_STANDARD_MODE;
+ slave_i2c_port.isr_nack = 0;
+ slave_i2c_port.isr_byte_end = 0;
+ slave_i2c_port.isr_timeout = 0;
+ slave_i2c_port.isr_int_pending = 0;
+ compat_sema_init(&slave_i2c_port.tx_sem, 0);
+ compat_sema_init(&slave_i2c_port.rx_sem, 0);
+ ret_val = wmt_getsyspara(varname1, buf, &varlen);
+ is_master = 1;
+ if (ret_val == 0) {
+ ret_val = sscanf(buf, "%x", &port_num);
+ while (ret_val) {
+ if (port_num != 0)
+ is_master = 1;
+ else {
+ is_master = 0;
+ break;
+ }
+ idx += ret_val;
+ ret_val = sscanf(buf + idx, ",%x", &port_num);
+ }
+ } else
+ is_master = 1;
+ /**/
+ /* hardware initial*/
+ /**/
+ if (is_master == 0) {
+ *(volatile unsigned int *)PMC_ClOCK_ENABLE_LOWER |= (BIT5);
+ *(volatile unsigned int *)CTRL_GPIO21 &= ~(BIT0 | BIT1);
+ *(volatile unsigned int *)PU_EN_GPIO21 |= (BIT0 | BIT1);
+ *(volatile unsigned int *)PU_CTRL_GPIO21 |= (BIT0 | BIT1);
+
+ /*set i2c slave register*/
+ slave_i2c_port.regs->cr_reg = 0;
+ slave_i2c_port.regs->scr_reg = 0;
+ slave_i2c_port.regs->cr_reg = (I2C_SLAV_MODE_SEL|I2C_CR_ENABLE);
+ slave_i2c_port.regs->sisr_reg = I2C_SISR_ALL_WRITE_CLEAR;
+
+ if (slave_i2c_port.i2c_mode == I2C_STANDARD_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else if (slave_i2c_port.i2c_mode == I2C_FAST_MODE)
+ slave_i2c_port.regs->scr_reg = slave_i2c_addr;
+ else
+ slave_i2c_port.regs->scr_reg = (slave_i2c_addr|I2C_SLAVE_HS_MODE);
+
+ slave_i2c_port.regs->simr_reg = I2C_SIMR_ALL_ENABLE;
+
+ slave_i2c_port.regs->cr_reg &= ~I2C_CR_ENABLE;
+
+ if (request_irq(slave_i2c_port.irq_no , &slave_i2c_isr, IRQF_DISABLED, "i2c-slave", 0) < 0) {
+ DPRINTK(KERN_INFO "I2C-SLAVE: Failed to register I2C-SLAVE irq %i\n", slave_i2c_port.irq_no);
+ return -ENODEV;
+ }
+ }
+
+ return ret;
+}
+
+static int slave_i2c_remove(
+ struct device *dev /*!<; // please add parameters description her*/
+)
+{
+ struct cdev *cdev;
+
+ cdev = &slave_i2c_dev.cdev;
+ cdev_del(cdev);
+
+ return 0;
+} /* End of spi_remove() */
+
+static void slave_i2c_backup(void)
+{
+ regs_backup.cr_reg = slave_i2c_port.regs->cr_reg;
+ regs_backup.tcr_reg = slave_i2c_port.regs->tcr_reg;
+ regs_backup.scr_reg = slave_i2c_port.regs->scr_reg;
+ regs_backup.simr_reg = slave_i2c_port.regs->simr_reg;
+ regs_backup.str_reg = slave_i2c_port.regs->str_reg;
+
+}
+
+static void slave_i2c_restore(void)
+{
+ slave_i2c_port.regs->cr_reg = 0;
+ slave_i2c_port.regs->cr_reg = regs_backup.cr_reg;
+ slave_i2c_port.regs->tcr_reg = regs_backup.tcr_reg;
+ slave_i2c_port.regs->scr_reg = regs_backup.scr_reg;
+ slave_i2c_port.regs->simr_reg = regs_backup.simr_reg;
+ slave_i2c_port.regs->str_reg = regs_backup.str_reg;
+}
+
+static int slave_i2c_suspend(
+ struct device *dev, /*!<; // please add parameters description her*/
+ pm_message_t state /*!<; // please add parameters description her*/
+)
+{
+ if (is_master == 1)
+ return 0;
+ slave_i2c_backup();
+ compat_sema_init(&slave_i2c_port.tx_sem, 0);
+ compat_sema_init(&slave_i2c_port.rx_sem, 0);
+ return 0;
+}
+
+
+static int slave_i2c_resume(
+ struct device *dev
+)
+{
+ if (is_master == 1)
+ return 0;
+ *(volatile unsigned int *)PMC_ClOCK_ENABLE_LOWER |= (BIT5);
+ *(volatile unsigned int *)CTRL_GPIO21 &= ~(BIT0 | BIT1);
+ *(volatile unsigned int *)PU_EN_GPIO21 |= (BIT0 | BIT1);
+ *(volatile unsigned int *)PU_CTRL_GPIO21 |= (BIT0 | BIT1);
+ slave_i2c_restore();
+ return 0;
+}
+
+/*!*************************************************************************
+ device driver struct define
+****************************************************************************/
+static struct device_driver slave_i2c_driver = {
+ .name = "wmt_i2c_slave_0", /* This name should equal to platform device name.*/
+ .bus = &platform_bus_type,
+ .probe = slave_i2c_probe,
+ .remove = slave_i2c_remove,
+ .suspend = slave_i2c_suspend,
+ .resume = slave_i2c_resume
+};
+
+static void slave_i2c_platform_release(
+ struct device *device
+)
+{
+}
+
+/*!*************************************************************************
+ platform device struct define
+****************************************************************************/
+
+static struct platform_device slave_i2c_device = {
+ .name = "wmt_i2c_slave_0",
+ .id = 0,
+ .dev = { .release = slave_i2c_platform_release,
+ },
+ .num_resources = 0,
+ .resource = NULL,
+};
+
+static int slave_i2c_init(void)
+{
+ int ret;
+ dev_t dev_no;
+ char dev_name[40];
+ memset(dev_name, 0, 40);
+ sprintf(dev_name, "wmt_i2c_slave%d", slave_i2c_device.id);
+
+ if (slave_i2c_dev_major) {
+ dev_no = MKDEV(slave_i2c_dev_major, slave_i2c_dev_minor);
+ ret = register_chrdev_region(dev_no, slave_i2c_dev_nr, dev_name);
+ } else {
+ ret = alloc_chrdev_region(&dev_no, slave_i2c_dev_minor, slave_i2c_dev_nr, dev_name);
+ slave_i2c_dev_major = MAJOR(dev_no);
+ }
+
+ if (ret < 0) {
+ printk(KERN_ALERT "*E* can't get major %d\n", slave_i2c_dev_major);
+ return ret;
+ }
+
+ platform_device_register(&slave_i2c_device);
+ ret = driver_register(&slave_i2c_driver);
+
+ return ret;
+}
+
+module_init(slave_i2c_init);
+
+static void slave_i2c_exit(void)
+{
+ dev_t dev_no;
+
+ driver_unregister(&slave_i2c_driver);
+ platform_device_unregister(&slave_i2c_device);
+ dev_no = MKDEV(slave_i2c_dev_major, slave_i2c_dev_minor);
+ unregister_chrdev_region(dev_no, slave_i2c_dev_nr);
+
+ return;
+}
+
+module_exit(slave_i2c_exit);
+
+MODULE_AUTHOR("WMT SW Team");
+MODULE_DESCRIPTION("WMT_slave_i2c device driver");
+MODULE_LICENSE("GPL");
+#undef WMT_I2C_SLAVE_C
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.h b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.h
new file mode 100755
index 00000000..485823db
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/wmt-i2c-slave-bus.h
@@ -0,0 +1,24 @@
+/*++
+Copyright (c) 2010 WonderMedia Technologies, 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, see http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#define SLAVE_I2C_MAJOR 191
+
+#define IOCTL_DO_TRANSFER 0xBF01
+#define IOCTL_SET_ADDR 0xBF02
+#define IOCTL_QUERY_DATA 0xBF03
+#define IOCTL_SET_SPEED_MODE 0xBF04
diff --git a/ANDROID_3.4.5/drivers/i2c/i2c-api.c b/ANDROID_3.4.5/drivers/i2c/i2c-api.c
new file mode 100755
index 00000000..d01335bb
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/i2c-api.c
@@ -0,0 +1,216 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#define I2C_API_FAKE_ADDR 0x7f
+#define I2C_MINORS 256
+
+struct i2c_api {
+ struct list_head list;
+ struct i2c_client *client;
+};
+
+static LIST_HEAD(i2c_api_list);
+static DEFINE_SPINLOCK(i2c_api_list_lock);
+
+static struct i2c_api *get_i2c_api(int bus_id)
+{
+ struct i2c_api *i2c_api;
+
+ spin_lock(&i2c_api_list_lock);
+ list_for_each_entry(i2c_api, &i2c_api_list, list) {
+ if (i2c_api->client->adapter->nr == bus_id)
+ goto found;
+ }
+ i2c_api = NULL;
+
+found:
+ spin_unlock(&i2c_api_list_lock);
+ return i2c_api;
+}
+
+static struct i2c_api *add_i2c_api(struct i2c_client *client)
+{
+ struct i2c_api *i2c_api;
+
+ if (client->adapter->nr >= I2C_MINORS) {
+ printk(KERN_ERR "i2c_api: Out of device minors (%d)\n",
+ client->adapter->nr);
+ return NULL;
+ }
+
+ i2c_api = kzalloc(sizeof(*i2c_api), GFP_KERNEL);
+ if (!i2c_api)
+ return NULL;
+ i2c_api->client = client;
+
+ spin_lock(&i2c_api_list_lock);
+ list_add_tail(&i2c_api->list, &i2c_api_list);
+ spin_unlock(&i2c_api_list_lock);
+ return i2c_api;
+}
+
+static void del_i2c_api(struct i2c_api *i2c_api)
+{
+ spin_lock(&i2c_api_list_lock);
+ list_del(&i2c_api->list);
+ spin_unlock(&i2c_api_list_lock);
+ kfree(i2c_api);
+}
+
+static int i2c_api_do_xfer(int bus_id, char chip_addr, char sub_addr, int mode,
+ char *buf, unsigned int size)
+{
+/** you could define more transfer mode here, implement it following. */
+#define I2C_API_XFER_MODE_SEND 0x0 /* standard send */
+#define I2C_API_XFER_MODE_RECV 0x1 /* standard receive */
+#define I2C_API_XFER_MODE_SEND_NO_SUBADDR 0x2 /* send without sub-address */
+#define I2C_API_XFER_MODE_RECV_NO_SUBADDR 0x3 /* receive without sub-address */
+
+ int ret = 0;
+ char *tmp;
+ struct i2c_api *i2c_api = get_i2c_api(bus_id);
+
+ if (!i2c_api)
+ return -ENODEV;
+
+ i2c_api->client->addr = chip_addr;
+ switch (mode) {
+ case I2C_API_XFER_MODE_SEND:
+ tmp = kmalloc(size + 1,GFP_KERNEL);
+ if (tmp == NULL)
+ return -ENOMEM;
+ tmp[0] = sub_addr;
+ memcpy(&tmp[1], buf, size);
+ ret = i2c_master_send(i2c_api->client, tmp, size + 1);
+ ret = (ret == size + 1) ? size : ret;
+ kfree(tmp);
+ break;
+
+ case I2C_API_XFER_MODE_RECV:
+ ret = i2c_master_send(i2c_api->client, &sub_addr, 1);
+ if (ret < 0)
+ return ret;
+ ret = i2c_master_recv(i2c_api->client, buf, size);
+ break;
+
+ case I2C_API_XFER_MODE_SEND_NO_SUBADDR:
+ ret = i2c_master_send(i2c_api->client, buf, size);
+ break;
+
+ case I2C_API_XFER_MODE_RECV_NO_SUBADDR:
+ ret = i2c_master_recv(i2c_api->client, buf, size);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+
+int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size)
+{
+ return i2c_api_do_xfer(bus_id, chip_addr, sub_addr, I2C_API_XFER_MODE_SEND, buf, size);
+}
+
+int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size)
+{
+ return i2c_api_do_xfer(bus_id, chip_addr, sub_addr, I2C_API_XFER_MODE_RECV, buf, size);
+}
+
+int i2c_api_do_send_without_subaddr(int bus_id, char chip_addr, char *buf, unsigned int size)
+{
+ return i2c_api_do_xfer(bus_id, chip_addr, 0, I2C_API_XFER_MODE_SEND_NO_SUBADDR, buf, size);
+}
+
+int i2c_api_do_recv_without_subaddr(int bus_id, char chip_addr, char *buf, unsigned int size)
+{
+ return i2c_api_do_xfer(bus_id, chip_addr, 0, I2C_API_XFER_MODE_RECV_NO_SUBADDR, buf, size);
+}
+
+int i2c_api_attach(struct i2c_adapter *adap)
+{
+ struct i2c_board_info info;
+ struct i2c_client *client;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "i2c_api", I2C_NAME_SIZE);
+ info.addr = I2C_API_FAKE_ADDR;
+ client = i2c_new_device(adap, &info);
+ if (client)
+ add_i2c_api(client);
+ printk(KERN_INFO "i2c_api_attach adap[%d]\n", adap->nr);
+ return 0;
+}
+
+int i2c_api_detach(struct i2c_adapter *adap)
+{
+ struct i2c_api *i2c_api;
+
+ i2c_api = get_i2c_api(adap->nr);
+ if (i2c_api)
+ del_i2c_api(i2c_api);
+ return 0;
+}
+
+static const unsigned short normal_addr[] = { I2C_API_FAKE_ADDR, I2C_CLIENT_END };
+static const unsigned short ignore[] = { I2C_CLIENT_END };
+/*static struct i2c_client_address_data addr_data =
+{
+ .normal_i2c = normal_addr,
+ .probe = ignore,
+ .ignore = ignore,
+ .forces = NULL,
+};*/
+
+static const struct i2c_device_id id[] = {
+ {"I2C-API", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, id);
+
+static struct i2c_driver i2c_api_driver = {
+ .id_table = id,
+ .attach_adapter = i2c_api_attach,
+ .detach_adapter = i2c_api_detach,
+ .command = NULL,
+ .driver = {
+ .name = "I2C-API",
+ .owner = THIS_MODULE,
+ },
+ //.address_data = &addr_data,
+};
+
+static int __init i2c_api_init(void)
+{
+ int ret = i2c_add_driver(&i2c_api_driver);
+
+ if (ret) {
+ printk(KERN_ERR "[%s] Driver registration failed, module not inserted.\n", __func__);
+ return ret;
+ }
+
+ return 0 ;
+}
+
+static void __exit i2c_api_exit(void)
+{
+ i2c_del_driver(&i2c_api_driver);
+}
+
+MODULE_AUTHOR("Loon, <Loonzhong@wondermedia.com.cn>");
+MODULE_DESCRIPTION("I2C i2c_api Driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_api_init);
+module_exit(i2c_api_exit);
+
+EXPORT_SYMBOL_GPL(i2c_api_do_send);
+EXPORT_SYMBOL_GPL(i2c_api_do_recv);
+EXPORT_SYMBOL_GPL(i2c_api_do_send_without_subaddr);
+EXPORT_SYMBOL_GPL(i2c_api_do_recv_without_subaddr);