[COMMON] i2c: busses: Added initial speedy driver.
authorJang JeongHoon <jnghn.jang@samsung.com>
Fri, 11 May 2018 03:51:44 +0000 (12:51 +0900)
committerJaehyoung Choi <jkkkkk.choi@samsung.com>
Fri, 11 May 2018 07:38:43 +0000 (16:38 +0900)
Change-Id: I7488199a94cff870f7595ca221c26ae64b30f67c
Signed-off-by: Jang JeongHoon <jnghn.jang@samsung.com>
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-speedy.c [new file with mode: 0644]

index 0f488bd7405329e39b5adfbda1bd36e1a7f915b9..851f7083053b9efc35185e1ea96a5a42a4f27ddc 100644 (file)
@@ -598,6 +598,14 @@ config I2C_SAMSUNG_HWACG
        suspend state only when I2C master is not in busy state.
        To support HWACG on I2C, this configuration should be selected.
 
+config EXYNOS_SPEEDY
+        tristate "SAMSUNG EXYNOS SPEEDY driver"
+        depends on ARCH_EXYNOS && OF
+        default y
+        help
+          Serial Protocol in an EffEctive Digital waY controller
+         on Exynos based Samsung SoCs.
+
 config I2C_GPIO
        tristate "GPIO-based bitbanging I2C"
        depends on GPIOLIB || COMPILE_TEST
index 2ce8576540a29a4abf80f4ca2767d9ca6448939d..ab329e739336fa149507b4baca0b29234b31c9a7 100644 (file)
@@ -58,6 +58,7 @@ obj-$(CONFIG_I2C_EFM32)               += i2c-efm32.o
 obj-$(CONFIG_I2C_EG20T)                += i2c-eg20t.o
 obj-$(CONFIG_I2C_EMEV2)                += i2c-emev2.o
 obj-$(CONFIG_I2C_EXYNOS5)      += i2c-exynos5.o
+obj-$(CONFIG_EXYNOS_SPEEDY)    += i2c-speedy.o
 obj-$(CONFIG_I2C_GPIO)         += i2c-gpio.o
 obj-$(CONFIG_I2C_HIGHLANDER)   += i2c-highlander.o
 obj-$(CONFIG_I2C_HIX5HD2)      += i2c-hix5hd2.o
diff --git a/drivers/i2c/busses/i2c-speedy.c b/drivers/i2c/busses/i2c-speedy.c
new file mode 100644 (file)
index 0000000..2c35c7f
--- /dev/null
@@ -0,0 +1,1080 @@
+/*
+ * Driver for Samsung SPEEDY(Serial Protocol in an EffEctive Digital waY)
+ *
+ * Copyright (C) 2015 Samsung Electronics Ltd.
+ *     Youngmin Nam <youngmin.nam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include "../../pinctrl/core.h"
+
+/* SPEEDY Register MAP */
+#define SPEEDY_CTRL                                    0x000
+#define SPEEDY_FIFO_CTRL                               0x004
+#define SPEEDY_CMD                                     0x008
+#define SPEEDY_INT_ENABLE                              0x00C
+#define SPEEDY_INT_STATUS                              0x010
+#define SPEEDY_FIFO_STATUS                             0x030
+#define SPEEDY_TX_DATA                                 0x034
+#define SPEEDY_RX_DATA                                 0x038
+#define SPEEDY_PACKET_GAP_TIME                         0x044
+#define SPEEDY_TIMEOUT_COUNT                           0x048
+#define SPEEDY_FIFO_DEBUG                              0x100
+#define SPEEDY_CTRL_STATUS                             0x104
+
+/* SPEEDY_CTRL Register bits */
+#define SPEEDY_ENABLE                                  (1 << 0)
+#define SPEEDY_TIMEOUT_CMD_DISABLE                     (1 << 1)
+#define SPEEDY_TIMEOUT_STANDBY_DISABLE                 (1 << 2)
+#define SPEEDY_TIMEOUT_DATA_DISABLE                    (1 << 3)
+#define SPEEDY_ALWAYS_PULLUP_EN                                (1 << 7)
+#define SPEEDY_DATA_WIDTH_8BIT                         (0 << 8)
+#define SPEEDY_REMOTE_RESET_REQ                                (1 << 30)
+#define SPEEDY_SW_RST                                  (1 << 31)
+
+/* SPEEDY_FIFO_CTRL Register bits */
+#define SPEEDY_RX_TRIGGER_LEVEL(x)                     ((x) << 0)
+#define SPEEDY_TX_TRIGGER_LEVEL(x)                     ((x) << 8)
+#define SPEEDY_FIFO_DEBUG_INDEX                                (0 << 24) // TODO : modify define
+#define SPEEDY_FIFO_RESET                              (1 << 31)
+
+/* SPEEDY_CMD Register bits */
+#define SPEEDY_BURST_LENGTH(x)                         ((x) << 0)
+#define SPEEDY_BURST_FIXED                             (0 << 5)
+#define SPEEDY_BURST_INCR                              (1 << 5)
+#define SPEEDY_BURST_EXTENSION                         (2 << 5)
+#define SPEEDY_ADDRESS(x)                              ((x & 0xFFF) << 7)
+#define SPEEDY_ACCESS_BURST                            (0 << 19)
+#define SPEEDY_ACCESS_RANDOM                           (1 << 19)
+#define SPEEDY_DIRECTION_READ                          (0 << 20)
+#define SPEEDY_DIRECTION_WRITE                         (1 << 20)
+
+/* SPEEDY_INT_ENABLE Register bits */
+#define SPEEDY_TRANSFER_DONE_EN                                (1 << 0)
+#define SPEEDY_TIMEOUT_CMD_EN                          (1 << 1)
+#define SPEEDY_TIMEOUT_STANDBY_EN                      (1 << 2)
+#define SPEEDY_TIMEOUT_DATA_EN                         (1 << 3)
+#define SPEEDY_FIFO_TX_ALMOST_EMPTY_EN                 (1 << 4)
+#define SPEEDY_FIFO_RX_ALMOST_FULL_EN                  (1 << 8)
+#define SPEEDY_RX_FIFO_INT_TRAILER_EN                  (1 << 9)
+#define SPEEDY_RX_MODEBIT_ERR_EN                       (1 << 16)
+#define SPEEDY_RX_GLITCH_ERR_EN                                (1 << 17)
+#define SPEEDY_RX_ENDBIT_ERR_EN                                (1 << 18)
+#define SPEEDY_TX_LINE_BUSY_ERR_EN                     (1 << 20)
+#define SPEEDY_TX_STOPBIT_ERR_EN                       (1 << 21)
+#define SPEEDY_REMOTE_RESET_REQ_EN                     (1 << 31)
+
+/* SPEEDY_INT_STATUS Register bits */
+#define SPEEDY_TRANSFER_DONE                           (1 << 0)
+#define SPEEDY_TIMEOUT_CMD                             (1 << 1)
+#define SPEEDY_TIMEOUT_STANDBY                         (1 << 2)
+#define SPEEDY_TIMEOUT_DATA                            (1 << 3)
+#define SPEEDY_FIFO_TX_ALMOST_EMPTY                    (1 << 4)
+#define SPEEDY_FIFO_RX_ALMOST_FULL                     (1 << 8)
+#define SPEEDY_RX_FIFO_INT_TRAILER                     (1 << 9)
+#define SPEEDY_RX_MODEBIT_ERR                          (1 << 16)
+#define SPEEDY_RX_GLITCH_ERR                           (1 << 17)
+#define SPEEDY_RX_ENDBIT_ERR                           (1 << 18)
+#define SPEEDY_TX_LINE_BUSY_ERR                                (1 << 20)
+#define SPEEDY_TX_STOPBIT_ERR                          (1 << 21)
+#define SPEEDY_REMOTE_RESET_REQ_STAT                   (1 << 31)
+
+/* SPEEDY_FIFO_STATUS Register bits */
+#define SPEEDY_VALID_DATA_CNT                          (0 << 0) // TODO : modify define
+#define SPEEDY_FIFO_FULL                               (1 << 5)
+#define SPEEDY_FIFO_EMPTY                              (1 << 6)
+
+/* SPEEDY_PACKET_GAP_TIME Register bits */
+#define SPEEDY_PULL_EN_CNT                             (0xF << 0) // TODO : modify define
+#define SPEEDY_PACKET_GAP_TIME_CNT                     (0 << 16) // TODO : modify define
+
+/* SPEEDY_CTRL_STATUS Register bits */
+#define SPEEDY_FSM_IDLE                                        (1 << 0)
+#define SPEEDY_FSM_INIT                                        (1 << 1)
+#define SPEEDY_FSM_TX_CMD                              (1 << 2)
+#define SPEEDY_FSM_STANDBY                             (1 << 3)
+#define SPEEDY_FSM_DATA                                        (1 << 4)
+#define SPEEDY_FSM_TIMEOUT                             (1 << 5)
+#define SPEEDY_FSM_TRANS_DONE                          (1 << 6)
+#define SPEEDY_FSM_IO_RX_STAT_MASK                     (3 << 7)
+#define SPEEDY_FSM_IO_TX_IDLE                          (1 << 9)
+#define SPEEDY_FSM_IO_TX_GET_PACKET                    (1 << 10)
+#define SPEEDY_FSM_IO_TX_PACKET                                (1 << 11)
+#define SPEEDY_FSM_IO_TX_DONE                          (1 << 12)
+
+/* IP_BATCHER Register MAP */
+#define IPBATCHER_CON                                  0x0500
+#define IPBATCHER_STATE                                        0x0504
+#define IPBATCHER_INT_EN                               0x0508
+#define IPBATCHER_FSM_UNEXPEN                          0x050C
+#define IPBATCHER_FSM_TXEN                             0x0510
+#define IPBATCHER_FSM_RXFIFO                           0x0514
+#define IPBATCHER_FSM_CON                              0x0518
+#define IP_FIFO_STATUS                                 0x051C
+#define IP_INT_STATUS                                  0x0520
+#define IP_INTR_UNEXP_STATE                            0x0524
+#define IP_INTR_TX_STATE                               0x0528
+#define IP_INTR_RX_STATE                               0x052C
+#define BATCHER_OPCODE                                 0x0600
+#define BATCHER_START_PAYLOAD                          0x1000
+#define BATCHER_END_PAYLOAD                            0x1060
+#define IPBATCHER_SEMA_REL                             0x0200
+
+/* IPBATCHER_CON Register bits */
+#define BATCHER_ENABLE                                 (1 << 0)
+#define DEDICATED_BATCHER_APB                          (1 << 1)
+#define START_BATCHER                                  (1 << 4)
+#define APB_RESP_CPU                                   (1 << 5)
+#define IP_SW_RST                                      (1 << 6)
+#define MP_APBSEMA_SW_RST                              (1 << 7)
+#define MP_APBSEMA_DISABLE                             (1 << 8)
+#define SW_RESET                                       (1 << 31)
+
+/* IPBATCHER_STATE Register bits */
+#define BATCHER_OPERATION_COMPLETE                     (1 << 0)
+#define UNEXPECTED_IP_INTR                             (1 << 1)
+#define BATCHER_FSM_STATE_IDLE                         (1 << 3)
+#define BATCHER_FSM_STATE_INIT                         (1 << 4)
+#define BATCHER_FSM_STATE_GET_SEMAPHORE                        (1 << 5)
+#define BATCHER_FSM_STATE_CONFIG                       (1 << 6)
+#define BATCHER_FSM_STATE_WAIT_INT                     (1 << 7)
+#define BATCHER_FSM_STATE_SW_RESET_IP                  (1 << 8)
+#define BATCHER_FSM_STATE_INTR_ROUTINE                 (1 << 9)
+#define BATCHER_FSM_STATE_WRITE_TX_DATA                        (1 << 10)
+#define BATCHER_FSM_STATE_READ_RX_DATA                 (1 << 11)
+#define BATCHER_FSM_STATE_STOP_I2C                     (1 << 12)
+#define BATCHER_FSM_STATE_CLEAN_INTR_STAT              (1 << 13)
+#define BATCHER_FSM_STATE_REL_SEMAPHORE                        (1 << 14)
+#define BATCHER_FSM_STATE_GEN_INT                      (1 << 15)
+#define BATCHER_FSM_STATE_UNEXPECTED_INT               (1 << 16)
+#define MP_APBSEMA_CH_LOCK_STATUS                      (1 << 20)
+#define MP_APBSEMA_DISABLE_STATUS                      (1 << 21)
+#define MP_APBSEMA_SW_RST_STATUS                       (1 << 22)
+
+/* IPBATCHER_INT_EN Register bits */
+#define BATCHER_INTERRUPT_ENABLE                       (1 << 0)
+
+/* IPBATCHER_FSM_CON Register bits */
+#define DISABLE_STOP_CMD                               (1 << 0)
+#define DISABLE_SEMAPHORE_RELEASE                      (1 << 1)
+
+#define EXYNOS_SPEEDY_TIMEOUT                          (msecs_to_jiffies(500))
+#define BATCHER_INIT_CMD                               0xFFFFFFFF
+
+#define ACCESS_BURST                                   0
+#define ACCESS_RANDOM                                  1
+#define DIRECTION_READ                                         0
+#define DIRECTION_WRITE                                        1
+
+#define SRP_COUNT                                      3
+#define EMULATOR
+
+struct exynos_speedy {
+       struct list_head        node;
+       struct i2c_adapter      adap;
+
+       struct i2c_msg          *msg;
+       unsigned int            msg_ptr;
+       unsigned int            msg_len;
+
+       unsigned int            irq;
+       void __iomem            *regs;
+       struct clk              *clk;
+       struct device           *dev;
+
+       unsigned int            cmd_buffer;
+       unsigned int            cmd_index;
+       unsigned int            cmd_pointer;
+       unsigned int            desc_pointer;
+       unsigned int            batcher_read_addr;
+
+       int                     always_intr_high;
+       unsigned int            int_en;
+};
+
+static void dump_speedy_register(struct exynos_speedy *speedy)
+{
+       dev_err(speedy->dev, "SPEEDY Register dump\n"
+               "       CTRL             0x%08x\n"
+               "       FIFO_CTRL        0x%08x\n"
+               "       CMD              0x%08x\n"
+               "       INT_ENABLE       0x%08x\n"
+               "       INT_STATUS       0x%08x\n"
+               "       FIFO_STATUS      0x%08x\n"
+               "       PACKET_GAP_TIME  0x%08x\n"
+               "       TIMEOUT_COUNT    0x%08x\n"
+               "       CTRL_STATUS      0x%08x\n"
+               , readl(speedy->regs + SPEEDY_CTRL)
+               , readl(speedy->regs + SPEEDY_FIFO_CTRL)
+               , readl(speedy->regs + SPEEDY_CMD)
+               , readl(speedy->regs + SPEEDY_INT_ENABLE)
+               , readl(speedy->regs + SPEEDY_INT_STATUS)
+               , readl(speedy->regs + SPEEDY_FIFO_STATUS)
+               , readl(speedy->regs + SPEEDY_PACKET_GAP_TIME)
+               , readl(speedy->regs + SPEEDY_TIMEOUT_COUNT)
+               , readl(speedy->regs + SPEEDY_CTRL_STATUS)
+       );
+}
+
+static void dump_batcher_register(struct exynos_speedy *speedy)
+{
+       int i = 0;
+       char buf_opcode[SZ_256];
+       char buf_payload[SZ_1K];
+       u32 len = 0;
+
+       dev_err(speedy->dev, "Batcher Register dump\n"
+               "       CON               0x%08x\n"
+               "       State             0x%08x\n"
+               "       INT_EN            0x%08x\n"
+               "       FSM_UNEXPEN       0x%08x\n"
+               "       FSM_TXEN          0x%08x\n"
+               "       FSM_RXFIFO        0x%08x\n"
+               "       FSM_CON           0x%08x\n"
+               "       FIFO_Status       0x%08x\n"
+               "       INT_Status        0x%08x\n"
+               "       INTR_UNEXP_state  0x%08x\n"
+               "       INTR_TX_state     0x%08x\n"
+               "       INTR_RX_state     0x%08x\n"
+               , readl(speedy->regs + IPBATCHER_CON)
+               , readl(speedy->regs + IPBATCHER_STATE)
+               , readl(speedy->regs + IPBATCHER_INT_EN)
+               , readl(speedy->regs + IPBATCHER_FSM_UNEXPEN)
+               , readl(speedy->regs + IPBATCHER_FSM_TXEN)
+               , readl(speedy->regs + IPBATCHER_FSM_RXFIFO)
+               , readl(speedy->regs + IPBATCHER_FSM_CON)
+               , readl(speedy->regs + IP_FIFO_STATUS)
+               , readl(speedy->regs + IP_INT_STATUS)
+               , readl(speedy->regs + IP_INTR_UNEXP_STATE)
+               , readl(speedy->regs + IP_INTR_TX_STATE)
+               , readl(speedy->regs + IP_INTR_RX_STATE)
+       );
+
+       len += snprintf(buf_opcode + len, sizeof(buf_opcode) - len,
+                       "Batcher OPCODE dump\n");
+
+       for (i = 0; i < 7; i++) {
+               len += snprintf(buf_opcode + len, sizeof(buf_opcode) - len,
+                       "OPCODE %d = 0x%08x\n",
+                       i, readl(speedy->regs + (BATCHER_OPCODE + (i * 4))));
+       }
+
+       dev_err(speedy->dev, "%s", buf_opcode);
+
+       len = 0;
+       len += snprintf(buf_payload + len, sizeof(buf_payload) - len,
+                       "Batcher PAYLOAD dump\n");
+
+       for (i = 0; i < 25; i++) {
+               len += snprintf(buf_payload + len, sizeof(buf_payload) - len,
+                       "PAYLOAD %02d = 0x%08x   ",
+                       i, readl(speedy->regs + (BATCHER_START_PAYLOAD + (i * 4))));
+               if (i % 5 == 4)
+                       len += snprintf(buf_payload + len,
+                                       sizeof(buf_payload) - len, "\n");
+       }
+
+       dev_err(speedy->dev, "%s", buf_payload);
+}
+
+static void write_batcher(struct exynos_speedy *speedy, unsigned int description,
+                       unsigned int opcode)
+{
+       if((BATCHER_START_PAYLOAD + (speedy->desc_pointer * 4)) <=
+               BATCHER_END_PAYLOAD) {
+
+               /* clear cmd_buffer */
+               speedy->cmd_buffer &= ~(0xFF << (8 * speedy->cmd_index));
+
+               /* write opcode to cmd_buffer */
+               speedy->cmd_buffer |= (opcode << (8 * speedy->cmd_index));
+
+               /* write opcode to OPCODE_TABLE register */
+               writel(speedy->cmd_buffer, speedy->regs + BATCHER_OPCODE +
+                       (speedy->cmd_pointer * 4));
+
+               /* write payload to PAYLOAD_FIELD register */
+               writel(description, speedy->regs + BATCHER_START_PAYLOAD +
+                       (speedy->desc_pointer * 4));
+
+               /* increase cmd_index for next opcode */
+               speedy->cmd_index++;
+
+               /* increase desc_pointer for next payload */
+               speedy->desc_pointer++;
+       } else {
+               /* Error handling for opcode overflow */
+               dev_err(speedy->dev, "fail to write speedy batcher\n");
+       }
+
+       /* If cmd_index is 4, we need to update cmd_index, cmd_pointer */
+       if(speedy->cmd_index == 4) {
+               /* initialize cmd_index to use OPCODE_TABLE from start point */
+               speedy->cmd_index = 0;
+               /* increase OPCODE_TABLE offset to use next OPCODE_TABLE register */
+               speedy->cmd_pointer++;
+               /* innitialize cmd_buffer */
+               speedy->cmd_buffer = BATCHER_INIT_CMD;
+       }
+}
+
+static void set_batcher_enable(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_con = readl(speedy->regs + IPBATCHER_CON);
+
+       ip_batcher_con |= BATCHER_ENABLE;
+       ip_batcher_con |= DEDICATED_BATCHER_APB;
+
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+}
+
+static void start_batcher(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_con = readl(speedy->regs + IPBATCHER_CON);
+
+       ip_batcher_con |= START_BATCHER;
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+}
+
+static void mp_apbsema_sw_rst(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_con = readl(speedy->regs + IPBATCHER_CON);
+
+       ip_batcher_con |= MP_APBSEMA_SW_RST;
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+
+       ip_batcher_con &= (~MP_APBSEMA_SW_RST);
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+}
+
+static void set_batcher_interrupt(struct exynos_speedy *speedy, int enable)
+{
+       u32 ip_batcher_int_en = readl(speedy->regs + IPBATCHER_INT_EN);
+
+       if (enable)
+               ip_batcher_int_en |= BATCHER_INTERRUPT_ENABLE;
+       else
+               ip_batcher_int_en &= (~BATCHER_INTERRUPT_ENABLE);
+
+       writel(ip_batcher_int_en, speedy->regs + IPBATCHER_INT_EN);
+}
+
+static void set_batcher_idle(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_con = 0;
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+}
+
+static void batcher_swreset(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_con = readl(speedy->regs + IPBATCHER_CON);
+
+       ip_batcher_con |= SW_RESET;
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+
+       ip_batcher_con &= (~SW_RESET);
+       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+
+       dev_err(speedy->dev, "batcher s/w reset was done\n");
+}
+
+static void program_batcher_fsm(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_fsm_unexpec_enable = 0;
+       u32 ip_batcher_fsm_tx_enable = 0;
+       u32 ip_batcher_fsm_rx_fifo = 0;
+       u32 ip_batcher_fsm_con = 0;
+
+       /* select unexpected interrupt of IP */
+       /* "1" in each bit will be handled as unexpected interrupt */
+       ip_batcher_fsm_unexpec_enable =
+                       (SPEEDY_TIMEOUT_CMD_EN | SPEEDY_TIMEOUT_STANDBY_EN |
+                        SPEEDY_TIMEOUT_DATA_EN | SPEEDY_RX_MODEBIT_ERR_EN |
+                        SPEEDY_RX_GLITCH_ERR_EN | SPEEDY_RX_ENDBIT_ERR_EN |
+                        SPEEDY_TX_LINE_BUSY_ERR_EN | SPEEDY_TX_STOPBIT_ERR_EN);
+       writel(ip_batcher_fsm_unexpec_enable, speedy->regs + IPBATCHER_FSM_UNEXPEN);
+
+       /* select Tx, Rx normal interrupt of IP */
+       /* "1" in each bit will be handled as Tx normal interrupt */
+       /* "0" in each bit will be handled as Rx normal interrupt */
+       ip_batcher_fsm_tx_enable =
+                       (SPEEDY_TRANSFER_DONE_EN | SPEEDY_FIFO_TX_ALMOST_EMPTY_EN);
+       writel(ip_batcher_fsm_tx_enable, speedy->regs + IPBATCHER_FSM_TXEN);
+
+       /* select Rx FIFO empty status check bit */
+       /* "1" in each bit will monitor IP's RXFIFO empty status */
+       ip_batcher_fsm_rx_fifo = SPEEDY_FIFO_EMPTY;
+       writel(ip_batcher_fsm_rx_fifo, speedy->regs + IPBATCHER_FSM_RXFIFO);
+
+       ip_batcher_fsm_con = DISABLE_STOP_CMD;
+       writel(ip_batcher_fsm_con, speedy->regs + IPBATCHER_FSM_CON);
+}
+
+static void release_semaphore(struct exynos_speedy *speedy)
+{
+       writel(0x01, speedy->regs + IPBATCHER_SEMA_REL);
+}
+
+static void speedy_swreset_directly(struct exynos_speedy *speedy)
+{
+       u32 speedy_ctl = readl(speedy->regs + SPEEDY_CTRL);
+
+       speedy_ctl |= SPEEDY_SW_RST;
+       writel(speedy_ctl, speedy->regs + SPEEDY_CTRL);
+       /* delay for speedy sw_rst */
+       udelay(10);
+
+       dev_err(speedy->dev, "speedy swreset directly was done\n");
+}
+
+static void speedy_swreset_with_batcher(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_state = readl(speedy->regs + IPBATCHER_STATE);
+       u32 ip_batcher_con;
+       unsigned long timeout;
+
+       if (ip_batcher_state & MP_APBSEMA_CH_LOCK_STATUS) {
+               dev_err(speedy->dev, "speedy reset is started with semaphore\n");
+
+               if (ip_batcher_state & BATCHER_FSM_STATE_WAIT_INT) {
+                       ip_batcher_con = readl(speedy->regs + IPBATCHER_CON);
+                       ip_batcher_con |= IP_SW_RST;
+                       writel(ip_batcher_con, speedy->regs + IPBATCHER_CON);
+                       /* delay for speedy sw_rst */
+                       udelay(10);
+                       dev_err(speedy->dev, "speedy swreset through batcher was done\n");
+               } else {
+                       /* SPEEDY SW reset directly */
+                       speedy_swreset_directly(speedy);
+               }
+
+               udelay(100);
+               ip_batcher_state = readl(speedy->regs + IPBATCHER_STATE);
+               if (!(ip_batcher_state & BATCHER_FSM_STATE_INIT)) {
+                       mp_apbsema_sw_rst(speedy);
+                       udelay(100);
+                       batcher_swreset(speedy);
+                       program_batcher_fsm(speedy);
+
+                       timeout = jiffies + EXYNOS_SPEEDY_TIMEOUT;
+
+                       /* Wait IDLE or INIT state of IPBATCHER */
+                       while (time_before(jiffies, timeout)) {
+                               ip_batcher_state = readl(speedy->regs + IPBATCHER_STATE);
+                               if ((ip_batcher_state & BATCHER_FSM_STATE_IDLE) ||
+                                   (ip_batcher_state & BATCHER_FSM_STATE_INIT)) {
+                                       timeout = 0;
+                                       break;
+                               } else
+                                       udelay(10);
+                       }
+                       if (timeout)
+                               dev_err(speedy->dev, "Timeout for waiting IDLE or INIT \n");
+               }
+               release_semaphore(speedy);
+       } else {
+               dev_err(speedy->dev, "speedy reset can't be done by no semaphore\n");
+               batcher_swreset(speedy);
+               program_batcher_fsm(speedy);
+       }
+
+       timeout = jiffies + EXYNOS_SPEEDY_TIMEOUT;
+
+       /* Check IDLE or INIT state of IPBATCHER */
+       while (time_before(jiffies, timeout)) {
+               ip_batcher_state = readl(speedy->regs + IPBATCHER_STATE);
+               if ((ip_batcher_state & BATCHER_FSM_STATE_IDLE) ||
+                   (ip_batcher_state & BATCHER_FSM_STATE_INIT)) {
+                       timeout = 0;
+                       break;
+               }
+               else
+                       udelay(10);
+       }
+       if (timeout)
+               dev_err(speedy->dev, "Timeout for waiting IDLE or INIT \n");
+
+       dev_err(speedy->dev, "speedy recovery is done\n");
+}
+
+static void speedy_set_cmd(struct exynos_speedy *speedy, int direction, u16 address,
+                       int random, int burst_length)
+{
+       u32 speedy_fifo_ctl = 0;
+       u32 speedy_int_en = 0;
+       u32 speedy_command = 0;
+
+       speedy_fifo_ctl |= SPEEDY_FIFO_RESET;
+       speedy_command |= SPEEDY_ADDRESS(address);
+
+       switch (random) {
+       case ACCESS_BURST:
+               speedy_command |= (SPEEDY_ACCESS_BURST | SPEEDY_BURST_INCR |
+                                  SPEEDY_BURST_LENGTH(burst_length-1));
+
+               /* To prevent batcher timeout, interrupt state should be set as high */
+               /* So, FIFO trigger level shoud be set to trigger interrupt always */
+               if (speedy->always_intr_high) {
+                       if (direction == DIRECTION_READ) {
+                               speedy_fifo_ctl |= (
+                                       SPEEDY_RX_TRIGGER_LEVEL(burst_length) |
+                                       SPEEDY_TX_TRIGGER_LEVEL(16)
+                               );
+                       } else {
+                               speedy_fifo_ctl |= (
+                                       SPEEDY_RX_TRIGGER_LEVEL(0) |
+                                       SPEEDY_TX_TRIGGER_LEVEL(1)
+                               );
+                       }
+               } else {
+                       speedy_fifo_ctl |= (
+                               SPEEDY_RX_TRIGGER_LEVEL(burst_length) |
+                               SPEEDY_TX_TRIGGER_LEVEL(1)
+                       );
+               }
+               break;
+
+       case ACCESS_RANDOM:
+               speedy_command |= SPEEDY_ACCESS_RANDOM;
+               speedy_fifo_ctl |= (SPEEDY_RX_TRIGGER_LEVEL(1) |
+                               SPEEDY_TX_TRIGGER_LEVEL(1));
+               break;
+       }
+
+       /* make opcode and payload to configure SPEEDY_FIFO_CTRL */
+       write_batcher(speedy, speedy_fifo_ctl, SPEEDY_FIFO_CTRL);
+
+       speedy_int_en |= (SPEEDY_TIMEOUT_CMD_EN | SPEEDY_TIMEOUT_STANDBY_EN |
+                       SPEEDY_TIMEOUT_DATA_EN);
+
+       switch (direction) {
+       case DIRECTION_READ:
+               speedy_command |= SPEEDY_DIRECTION_READ;
+               speedy_int_en |= (SPEEDY_FIFO_RX_ALMOST_FULL_EN |
+                               SPEEDY_RX_FIFO_INT_TRAILER_EN |
+                               SPEEDY_RX_MODEBIT_ERR_EN |
+                               SPEEDY_RX_GLITCH_ERR_EN |
+                               SPEEDY_RX_ENDBIT_ERR_EN);
+
+               /* To prevent batcher timeout, interrupt state should be set as high */
+               if (speedy->always_intr_high) {
+                       speedy_int_en |= SPEEDY_FIFO_TX_ALMOST_EMPTY_EN;
+               }
+
+               break;
+
+       case DIRECTION_WRITE:
+               speedy_command |= SPEEDY_DIRECTION_WRITE;
+               speedy_int_en |= (SPEEDY_TRANSFER_DONE_EN |
+                               SPEEDY_FIFO_TX_ALMOST_EMPTY_EN |
+                               SPEEDY_TX_LINE_BUSY_ERR_EN |
+                               SPEEDY_TX_STOPBIT_ERR_EN);
+
+               /* To prevent batcher timeout, interrupt state should be set as high */
+               if (speedy->always_intr_high) {
+                       speedy_int_en |= SPEEDY_FIFO_RX_ALMOST_FULL_EN;
+               }
+
+               break;
+       }
+
+       /* store speedy_interrupt_enable status for re-configuration later */
+       speedy->int_en = speedy_int_en;
+
+       /* clear speedy interrupt status */
+       write_batcher(speedy, 0xFFFFFFFF, SPEEDY_INT_STATUS);
+
+       /* make opcode and payload to configure SPEEDY_INT_ENABLE */
+       write_batcher(speedy, speedy_int_en, SPEEDY_INT_ENABLE);
+
+       /* make opcode and payload to configure SPEEDY_CMD */
+       write_batcher(speedy, speedy_command, SPEEDY_CMD);
+}
+
+static int speedy_batcher_wait_complete(struct exynos_speedy *speedy)
+{
+       u32 ip_batcher_state;
+       u32 ip_batcher_int_status;
+       int ret = -EBUSY;
+       unsigned long timeout;
+
+       timeout = jiffies + EXYNOS_SPEEDY_TIMEOUT;
+
+       while (time_before(jiffies, timeout)) {
+               ip_batcher_state = readl(speedy->regs + IPBATCHER_STATE);
+               ip_batcher_int_status = readl(speedy->regs + IP_INT_STATUS);
+
+               if (ip_batcher_state & BATCHER_OPERATION_COMPLETE) {
+                       if ((ip_batcher_int_status & SPEEDY_TIMEOUT_CMD) |
+                               (ip_batcher_int_status & SPEEDY_TIMEOUT_STANDBY) |
+                               (ip_batcher_int_status & SPEEDY_TIMEOUT_DATA) |
+                               (ip_batcher_int_status & SPEEDY_RX_MODEBIT_ERR) |
+                               (ip_batcher_int_status & SPEEDY_RX_GLITCH_ERR) |
+                               (ip_batcher_int_status & SPEEDY_RX_ENDBIT_ERR) |
+                               (ip_batcher_int_status & SPEEDY_TX_LINE_BUSY_ERR) |
+                               (ip_batcher_int_status & SPEEDY_TX_STOPBIT_ERR)) {
+                               ret = -EIO;
+                               break;
+                       } else {
+                               ret = 0;
+                               break;
+                       }
+               } else if (ip_batcher_state & UNEXPECTED_IP_INTR) {
+                       if ((ip_batcher_int_status & SPEEDY_TIMEOUT_CMD) |
+                               (ip_batcher_int_status & SPEEDY_TIMEOUT_STANDBY) |
+                               (ip_batcher_int_status & SPEEDY_TIMEOUT_DATA) |
+                               (ip_batcher_int_status & SPEEDY_RX_MODEBIT_ERR) |
+                               (ip_batcher_int_status & SPEEDY_RX_GLITCH_ERR) |
+                               (ip_batcher_int_status & SPEEDY_RX_ENDBIT_ERR) |
+                               (ip_batcher_int_status & SPEEDY_TX_LINE_BUSY_ERR) |
+                               (ip_batcher_int_status & SPEEDY_TX_STOPBIT_ERR)) {
+                               ret = -EIO;
+                               break;
+                       }
+               } else {
+                       udelay(10);
+               }
+       }
+
+       if (ret != 0) {
+               if (ret == -EIO)
+                       dev_err(speedy->dev,
+                               "speedy timeout or error is occurred ");
+               else
+                       dev_err(speedy->dev,
+                               "speedy batcher operation timeout is occurred ");
+       }
+
+       if (ip_batcher_state & BATCHER_OPERATION_COMPLETE) {
+               /* clear batcher operation complete */
+               ip_batcher_state |= BATCHER_OPERATION_COMPLETE;
+               writel(ip_batcher_state, speedy->regs + IPBATCHER_STATE);
+       }
+
+       return ret;
+}
+
+static void finalize_batcher(struct exynos_speedy *speedy)
+{
+       write_batcher(speedy, 0x00, 0xFF);
+
+       /* Initialize variables related opcode and payload of batcher */
+       speedy->cmd_buffer = BATCHER_INIT_CMD;
+       speedy->cmd_index = 0;
+       speedy->cmd_pointer = 0;
+       speedy->desc_pointer = 0;
+}
+
+static void speedy_set_srp(struct exynos_speedy *speedy)
+{
+       int ret;
+       int i;
+       u32 speedy_ctl;
+
+       for (i = 0; i < SRP_COUNT; i++) {
+               speedy_ctl = 0x30051;
+               /* set batcher IDLE state */
+               set_batcher_idle(speedy);
+
+               /* set batcher IDLE->INIT state */
+               set_batcher_enable(speedy);
+
+               speedy_set_cmd(speedy, DIRECTION_WRITE, 0x0, ACCESS_RANDOM, 0);
+
+               speedy_ctl |= SPEEDY_REMOTE_RESET_REQ;
+               write_batcher(speedy, speedy_ctl, SPEEDY_CTRL);
+
+               write_batcher(speedy, 0x00, SPEEDY_TX_DATA);
+
+               speedy_ctl &= (~SPEEDY_REMOTE_RESET_REQ);
+               write_batcher(speedy, speedy_ctl, SPEEDY_CTRL);
+
+               finalize_batcher(speedy);
+               /* TODO : for polling mode, need to enable batcher interrupt ? */
+               set_batcher_interrupt(speedy, 1);
+               start_batcher(speedy);
+               ret = speedy_batcher_wait_complete(speedy);
+               /* TODO : for polling mode, need to enable batcher interrupt ? */
+               set_batcher_interrupt(speedy, 0);
+               set_batcher_idle(speedy);
+
+               if (!ret) {
+                       dev_err(speedy->dev, "SRP was done successfully\n");
+                       break;
+               } else {
+                       dev_err(speedy->dev, "SRP timeout was occured\n");
+                       dump_speedy_register(speedy);
+                       dump_batcher_register(speedy);
+                       speedy_swreset_with_batcher(speedy);
+               }
+       }
+}
+
+static int exynos_speedy_xfer_batcher(struct exynos_speedy *speedy,
+                               struct i2c_msg *msgs)
+{
+       int i = 0;
+       int ret;
+
+       /* speedy read / write direction */
+       int direction;
+       /* speedy random(single) / burst access way */
+       int random;
+       unsigned char byte;
+       unsigned int speedy_int_en;
+
+       /* initialize as reset value of SPEEDY_CTRL */
+       u32 speedy_ctl = 0x30050;
+
+       speedy->msg = msgs;
+       speedy->msg_ptr = 0;
+
+       speedy->cmd_buffer = BATCHER_INIT_CMD;
+       speedy->cmd_index = 0;
+       speedy->cmd_pointer = 0;
+       speedy->desc_pointer = 0;
+
+       /* set batcher IDLE state */
+       set_batcher_idle(speedy);
+
+       /* set batcher IDLE->INIT state */
+       set_batcher_enable(speedy);
+
+       /* enable speedy master */
+       speedy_ctl |= SPEEDY_ENABLE;
+       write_batcher(speedy, speedy_ctl, SPEEDY_CTRL);
+
+       if (speedy->msg->flags & I2C_M_RD)
+               direction = DIRECTION_READ;
+       else
+               direction = DIRECTION_WRITE;
+
+       if (speedy->msg->len > 1)
+               random = ACCESS_BURST;
+       else
+               random = ACCESS_RANDOM;
+
+       speedy_set_cmd(speedy, direction, speedy->msg->addr, random, speedy->msg->len);
+
+       if (direction == DIRECTION_READ) {
+               speedy->batcher_read_addr = BATCHER_START_PAYLOAD +
+                                          ((speedy->desc_pointer) * 4);
+
+               for (i = 0; i < speedy->msg->len; i++)
+                       write_batcher(speedy, 0x77, SPEEDY_RX_DATA);
+       } else {
+               /* direction == DIRECTION_WRITE */
+               for (i = 0; i < speedy->msg->len; i++) {
+                       byte = speedy->msg->buf[i];
+                       write_batcher(speedy, byte, SPEEDY_TX_DATA);
+               }
+
+               /*
+                * To prevent interrupt pending by FIFO_TX_ALMOST_EMPTY
+                * We should disable FIFO_TX_ALMOST_EMPTY_EN after Tx
+                */
+               speedy_int_en = speedy->int_en & (~SPEEDY_FIFO_TX_ALMOST_EMPTY_EN);
+               write_batcher(speedy, speedy_int_en, SPEEDY_INT_ENABLE);
+       }
+
+       finalize_batcher(speedy);
+
+       /* TODO : for polling mode, need to enable batcher interrupt ? */
+       set_batcher_interrupt(speedy, 1);
+
+       start_batcher(speedy);
+
+       ret = speedy_batcher_wait_complete(speedy);
+
+       /* TODO : for polling mode, need to enable batcher interrupt ? */
+       set_batcher_interrupt(speedy, 0);
+
+       if (!ret) {
+               if (direction == DIRECTION_READ) {
+                       for (i = 0; i < speedy->msg->len; i++) {
+                               byte  = (unsigned char)readl(speedy->regs +
+                                       speedy->batcher_read_addr + (i * 4));
+                               speedy->msg->buf[i] = byte;
+                       }
+               }
+               set_batcher_idle(speedy);
+       } else {
+               set_batcher_idle(speedy);
+               if (direction == DIRECTION_READ)
+                       dev_err(speedy->dev, "at Read\n");
+               else
+                       dev_err(speedy->dev, "at Write\n");
+
+               dump_speedy_register(speedy);
+               dump_batcher_register(speedy);
+
+               speedy_swreset_with_batcher(speedy);
+               speedy_set_srp(speedy);
+               udelay(1);
+               ret = -EAGAIN;
+       }
+       return ret;
+}
+#if 0
+static irqreturn_t exynos_speedy_irq_batcher(int irqno, void *dev_id)
+{
+       /* TODO : implementation is needed more */
+       /* In ISR, we will only handle error situation */
+
+       struct exynos_speedy *speedy = dev_id;
+       u32 ip_batcher_state;
+       u32 ip_batcher_int_status;
+
+       ip_batcher_state = readl(speedy->regs + IPBATCHER_STATE);
+       ip_batcher_int_status = readl(speedy->regs + IP_INT_STATUS);
+
+       if (ip_batcher_int_status & SPEEDY_REMOTE_RESET_REQ_STAT) {
+               dev_err(speedy->dev, "remote_reset_req is occured\n");
+       }
+
+       if (ip_batcher_state & UNEXPECTED_IP_INTR) {
+               dev_err(speedy->dev, "unexpected interrupt is occured\n");
+
+               if (ip_batcher_int_status & SPEEDY_TIMEOUT_CMD)
+                       dev_err(speedy->dev, "timout_cmd is occured\n");
+               if (ip_batcher_int_status & SPEEDY_TIMEOUT_STANDBY)
+                       dev_err(speedy->dev, "timeout_standby is occured\n");
+               if (ip_batcher_int_status & SPEEDY_TIMEOUT_DATA)
+                       dev_err(speedy->dev, "timeout_data is occured\n");
+               if (ip_batcher_int_status & SPEEDY_RX_MODEBIT_ERR)
+                       dev_err(speedy->dev, "rx_modebit_err is occured\n");
+               if (ip_batcher_int_status & SPEEDY_RX_GLITCH_ERR)
+                       dev_err(speedy->dev, "rx_glitch_err is occured\n");
+               if (ip_batcher_int_status & SPEEDY_RX_ENDBIT_ERR)
+                       dev_err(speedy->dev, "rx_endbit_err interrupt is occured\n");
+               if (ip_batcher_int_status & SPEEDY_TX_LINE_BUSY_ERR)
+                       dev_err(speedy->dev, "tx_line_busy_err interrupt is occured\n");
+               if (ip_batcher_int_status & SPEEDY_TX_STOPBIT_ERR)
+                       dev_err(speedy->dev, "tx_stopbit_err interrupt is occured\n");
+       }
+
+       if (ip_batcher_state & BATCHER_OPERATION_COMPLETE) {
+               dev_err(speedy->dev, "batcher operation is completed\n");
+
+               /* clear batcher operation complete */
+               ip_batcher_state |= BATCHER_OPERATION_COMPLETE;
+               writel(BATCHER_OPERATION_COMPLETE, speedy->regs + IPBATCHER_STATE);
+       }
+
+       return IRQ_HANDLED;
+}
+#endif
+
+static int exynos_speedy_xfer(struct i2c_adapter *adap,
+                         struct i2c_msg *msgs, int num)
+{
+       struct exynos_speedy *speedy = (struct exynos_speedy *)adap->algo_data;
+       struct i2c_msg *msgs_ptr = msgs;
+
+       int retry, i = 0;
+       int ret = 0;
+
+       for (retry = 0; retry < adap->retries; retry++) {
+               for (i = 0; i < num; i++) {
+                       ret = exynos_speedy_xfer_batcher(speedy, msgs_ptr);
+
+                       msgs_ptr++;
+
+                       if (ret == -EAGAIN) {
+                               msgs_ptr = msgs;
+                               break;
+                       } else if (ret < 0) {
+                               goto out;
+                       }
+               }
+
+               if ((i == num) && (ret != -EAGAIN))
+                       break;
+
+               dev_err(speedy->dev, "retrying transfer (%d)\n", retry);
+
+               udelay(100);
+       }
+
+       if (i == num) {
+               ret = num;
+       } else {
+               ret = -EREMOTEIO;
+               dev_err(speedy->dev, "xfer message failed\n");
+       }
+
+ out:
+       return ret;
+}
+
+static u32 exynos_speedy_func(struct i2c_adapter *adap)
+{
+        return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm exynos_speedy_algorithm = {
+        .master_xfer            = exynos_speedy_xfer,
+        .functionality          = exynos_speedy_func,
+};
+
+static int exynos_speedy_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct exynos_speedy *speedy;
+       struct resource *mem;
+       int ret;
+
+       dev_info(&pdev->dev, "speedy driver probe started\n");
+
+       if (!np) {
+               dev_err(&pdev->dev, "no device node\n");
+               return -ENOENT;
+       }
+
+       speedy = devm_kzalloc(&pdev->dev, sizeof(struct exynos_speedy), GFP_KERNEL);
+       if (!speedy) {
+               dev_err(&pdev->dev, "no memory for driver data\n");
+               return -ENOMEM;
+       }
+
+       if (of_get_property(np, "samsung,always-interrupt-high", NULL))
+               speedy->always_intr_high = 1;
+       else
+               speedy->always_intr_high = 0;
+
+       strlcpy(speedy->adap.name, "exynos-speedy", sizeof(speedy->adap.name));
+       speedy->adap.owner   = THIS_MODULE;
+       speedy->adap.algo    = &exynos_speedy_algorithm;
+       speedy->adap.retries = 2;
+       speedy->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+
+       speedy->dev = &pdev->dev;
+#if 0
+       speedy->clk = devm_clk_get(&pdev->dev, "gate_speedy");
+       if (IS_ERR(speedy->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               return -ENOENT;
+       }
+#endif
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       speedy->regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (speedy->regs == NULL) {
+               dev_err(&pdev->dev, "cannot map speedy SFR register\n");
+               ret = PTR_ERR(speedy->regs);
+               goto err_probe;
+       }
+
+       speedy->adap.dev.of_node = np;
+       speedy->adap.algo_data = speedy;
+       speedy->adap.dev.parent = &pdev->dev;
+
+       speedy->irq = irq_of_parse_and_map(np, 0);
+       if(speedy->irq <= 0) {
+               dev_err(&pdev->dev, "cannot find speedy IRQ\n");
+               ret = -EINVAL;
+               goto err_probe;
+       }
+       platform_set_drvdata(pdev, speedy);
+
+#if 0
+       /* clear speedy interrupt status */
+       writel(0xFFFFFFFF, speedy->regs + SPEEDY_INT_STATUS);
+
+       /* reset speedy ctrl SFR. It may be used by bootloader */
+       speedy_swreset_directly(speedy);
+
+       /* Do we need to register ISR for batcher polling mode? */
+       ret = devm_request_irq(&pdev->dev, speedy->irq,
+               exynos_speedy_irq_batcher, 0, dev_name(&pdev->dev), speedy);
+
+       disable_irq(speedy->irq);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "cannot request speedy IRQ %d\n", speedy->irq);
+               goto err_probe;
+       }
+       /* release semaphore after direct SPEEDY SFR access */
+       release_semaphore(speedy);
+
+       /* reset batcher */
+       batcher_swreset(speedy);
+       /* select bitfield to monitor interrupt and status by batcher */
+       program_batcher_fsm(speedy);
+#endif
+
+       speedy->adap.nr = -1;
+       ret = i2c_add_numbered_adapter(&speedy->adap);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+               goto err_probe;
+       }
+
+       dev_info(&pdev->dev, "speedy driver probe was succeeded\n");
+
+       return 0;
+
+ err_probe:
+       dev_err(&pdev->dev, "speedy driver probe failed\n");
+       return ret;
+}
+
+static const struct of_device_id exynos_speedy_match[] = {
+       { .compatible = "samsung,exynos-speedy" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, exynos_speedy_match);
+
+static struct platform_driver exynos_speedy_driver = {
+       .probe          = exynos_speedy_probe,
+       .driver         = {
+               .name   = "exynos-speedy",
+               .owner  = THIS_MODULE,
+               .of_match_table = exynos_speedy_match,
+       },
+};
+
+static int __init exynos_speedy_init(void)
+{
+       return platform_driver_register(&exynos_speedy_driver);
+}
+subsys_initcall(exynos_speedy_init);
+
+static void __exit exynos_speedy_exit(void)
+{
+       platform_driver_unregister(&exynos_speedy_driver);
+}
+module_exit(exynos_speedy_exit);
+
+MODULE_DESCRIPTION("Exynos SPEEDY driver");
+MODULE_AUTHOR("Youngmin Nam, <youngmin.nam@samsung.com>");
+MODULE_LICENSE("GPL v2");