Просмотр исходного кода

bsp: k230: add i2c driver

        Requirement: The BSP for the k230 platform in the RT-Thread repository
        does not yet have an I2C driver.

        Solution: Provide I2C driver for the k230 platform in the RT-Thread
        repository.
        1. support i2c master mode

Signed-off-by: Ze-Hou <yingkezhou@qq.com>
Ze-Hou 2 месяцев назад
Родитель
Сommit
9e3127982d

+ 9 - 0
bsp/k230/.ci/attachconfig/ci.attachconfig.yml

@@ -0,0 +1,9 @@
+scons.args: &scons
+    scons_arg:
+      - '--strict'
+devices.i2c:
+    <<: *scons
+    kconfig:
+      - CONFIG_RT_USING_I2C=y
+      - CONFIG_BSP_USING_I2C=y
+      - CONFIG_BSP_USING_I2C0=y

+ 3 - 0
bsp/k230/.config

@@ -227,6 +227,7 @@ CONFIG_FINSH_THREAD_STACK_SIZE=8192
 CONFIG_FINSH_USING_HISTORY=y
 CONFIG_FINSH_HISTORY_LINES=5
 # CONFIG_FINSH_USING_WORD_OPERATION is not set
+# CONFIG_FINSH_USING_FUNC_EXT is not set
 CONFIG_FINSH_USING_SYMTAB=y
 CONFIG_FINSH_CMD_SIZE=80
 CONFIG_MSH_USING_BUILT_IN_COMMANDS=y
@@ -425,6 +426,7 @@ CONFIG_RT_USING_POSIX_TIMER=y
 #
 CONFIG_RT_USING_SAL=y
 CONFIG_SAL_INTERNET_CHECK=y
+CONFIG_SOCKET_TABLE_STEP_LEN=4
 
 #
 # Docking with protocol stacks
@@ -1617,6 +1619,7 @@ CONFIG_PKG_ZLIB_VER="latest"
 #
 # Drivers Configuration
 #
+# CONFIG_BSP_USING_I2C is not set
 # CONFIG_BSP_USING_RTC is not set
 # CONFIG_BSP_USING_ADC is not set
 # CONFIG_BSP_USING_TS is not set

+ 27 - 0
bsp/k230/board/Kconfig

@@ -1,4 +1,31 @@
 menu "Drivers Configuration"
+    menuconfig BSP_USING_I2C
+        bool "Enable I2C"
+        select RT_USING_I2C
+        default n
+
+        if BSP_USING_I2C
+            config BSP_USING_I2C0
+                bool "Enable I2C0"
+                default n
+
+            config BSP_USING_I2C1
+                bool "Enable I2C1"
+                default n
+
+            config BSP_USING_I2C2
+                bool "Enable I2C2"
+                default n
+
+            config BSP_USING_I2C3
+                bool "Enable I2C3"
+                default n
+
+            config BSP_USING_I2C4
+                bool "Enable I2C4"
+                default n
+
+        endif
 
     config BSP_USING_RTC
         bool "Enable RTC"

+ 11 - 0
bsp/k230/drivers/interdrv/i2c/SConscript

@@ -0,0 +1,11 @@
+# RT-Thread building script for I2C component
+
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('I2C', src, depend = ['BSP_USING_I2C'], CPPPATH = CPPPATH)
+
+Return('group')

+ 528 - 0
bsp/k230/drivers/interdrv/i2c/drv_i2c.c

@@ -0,0 +1,528 @@
+/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <rtdevice.h>
+#include <riscv_io.h>
+#include <ioremap.h>
+#include "board.h"
+#include "drv_i2c.h"
+#include "sysctl_clk.h"
+
+#undef DBG_TAG
+#undef DBG_LVL
+#define DBG_TAG     "drv_i2c"
+#define DBG_LVL     DBG_INFO
+#include <rtdbg.h>
+
+struct _i2c_speed_cfg
+{
+    rt_uint16_t hcnt;
+    rt_uint16_t lcnt;
+    rt_uint16_t spklen;
+};
+
+struct k230_i2c_dev
+{
+    struct rt_i2c_bus_device dev;
+    const char *name;
+    rt_ubase_t base;
+    size_t size;
+    int vector;
+    rt_uint32_t clock;
+    struct rt_i2c_msg *msg;
+    struct _i2c_speed_cfg speed_cfg;
+};
+
+static rt_size_t k230_i2c_get_timer(rt_size_t base)
+{
+    return rt_tick_get() - base ;
+}
+
+static void k230_i2c_enable(struct k230_i2c_dev *dev, rt_bool_t enable)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_uint32_t en_value = enable ? 1 : 0;
+    int timeout = 100;
+
+    do
+    {
+        i2c->enable.enable = en_value;
+        if(i2c->enable_status.en == en_value)
+        {
+            return;
+        }
+
+        /*
+         * Wait 10 times the signaling period of the highest I2C
+         * transfer supported by the driver (for 400KHz this is
+         * 25us) as described in the DesignWare I2C databook.
+         */
+        rt_hw_us_delay(25);
+    }while(timeout--);
+
+    LOG_E("timeout in %s i2c\n", enable ? "enable" : "disable");
+}
+
+static void k230_i2c_set_bus_timeout(struct k230_i2c_dev *dev, rt_uint32_t timeout)
+{
+    float tick = 0;
+
+    tick = RT_TICK_PER_SECOND / 1000.0f; /* ms to tick */
+    dev->dev.timeout = (rt_uint32_t)(timeout * tick);
+}
+
+static int k230_i2c_set_bus_speed(struct k230_i2c_dev *dev, rt_uint32_t speed)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_uint32_t i2c_spd, period, spklen, ft;
+
+    /*
+     * Calculate clock counts for I2C speed
+     * hcnt + lcnt + spklen + 7 + 1 + fall_time * clk = clk / speed
+     * fall_time = 10ns
+     * spklen = 0~50ns
+     */
+
+    spklen = dev->clock * 10 / 1e9;
+    ft = dev->clock * 10 / 1e9;
+    period = dev->clock / speed;
+    period = period - spklen - 7 - 1 - ft;
+    dev->speed_cfg.lcnt = period / 2;
+    dev->speed_cfg.hcnt = period - dev->speed_cfg.lcnt;
+    dev->speed_cfg.spklen = spklen;
+
+    if(speed <= I2C_STANDARD_SPEED_UP)
+    {
+        i2c_spd = I2C_SPEED_MODE_STANDARD;
+    }
+    else if(speed <= I2C_FAST_SPEED_UP)
+    {
+        i2c_spd = I2C_SPEED_MODE_FAST;
+    }
+    else if(speed <= I2C_MAX_SPEED_UP)
+    {
+        i2c_spd = I2C_SPEED_MODE_MAX;
+    }
+    else
+    {
+        return -RT_EINVAL;
+    }
+
+    /* to set speed cltr must be disabled */
+    k230_i2c_enable(dev, RT_FALSE);
+
+    switch(i2c_spd)
+    {
+        case I2C_SPEED_MODE_STANDARD:
+            i2c->ss_ufm_scl_hcnt.cnt = dev->speed_cfg.hcnt;
+            i2c->ss_ufm_scl_lcnt.cnt = dev->speed_cfg.lcnt;
+            i2c->fs_ufm_spklen.spklen = dev->speed_cfg.spklen;
+            break;
+
+        case I2C_SPEED_MODE_FAST:
+            i2c->fs_scl_hcnt_ufm_tbuf_cnt.cnt = dev->speed_cfg.hcnt;
+            i2c->fs_scl_lcnt.cnt = dev->speed_cfg.lcnt;
+            i2c->fs_ufm_spklen.spklen = dev->speed_cfg.spklen;
+            break;
+
+        case I2C_SPEED_MODE_MAX:
+            i2c->hs_scl_hcnt.cnt = dev->speed_cfg.hcnt;
+            i2c->hs_scl_lcnt.cnt = dev->speed_cfg.lcnt;
+            i2c->hs_spklen.spklen = dev->speed_cfg.spklen;
+            break;
+
+        default: break;
+    }
+
+    i2c->con.speed = i2c_spd;
+
+    /* Enable back i2c now speed set */
+    k230_i2c_enable(dev, RT_TRUE);
+
+    return RT_EOK;
+}
+
+static void k230_i2c_set_addr(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_uint16_t i2c_addr = dev->msg->addr;
+
+    /* Disable i2c */
+    k230_i2c_enable(dev, RT_FALSE);
+
+    if(dev->msg->flags & RT_I2C_ADDR_10BIT || dev->dev.flags & RT_I2C_ADDR_10BIT)
+    {
+        i2c->tar.master_10bit_addr = 1;
+        i2c_addr &= 0x3FF;
+    }
+    else
+    {
+        i2c->tar.master_10bit_addr = 0;
+        i2c_addr &= 0x7F;
+    }
+
+    i2c->tar.tar = i2c_addr;
+
+    /* Enable i2c */
+    k230_i2c_enable(dev, RT_TRUE);
+}
+
+static void k230_i2c_flush_rxfifo(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+
+    while(i2c->status.rfne)
+    {
+        readl(&i2c->data_cmd);
+    }
+}
+
+static int k230_i2c_wait_for_bus_busy(struct k230_i2c_dev *dev)
+{
+    rt_size_t start_time = k230_i2c_get_timer(0);
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+
+    while((i2c->status.mst_activity) || !(i2c->status.tfe))
+    {
+        /* Evaluate timeout */
+        if(k230_i2c_get_timer(start_time) > (rt_size_t)dev->dev.timeout * I2C_TX_FIFO_SIZE)
+        {
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    return RT_EOK;
+}
+
+static int k230_i2c_xfer_init(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_uint8_t addr = 0;
+
+    if(k230_i2c_wait_for_bus_busy(dev) != RT_EOK)
+    {
+        return -RT_EBUSY;
+    }
+
+    k230_i2c_set_addr(dev);
+
+    return RT_EOK;
+}
+
+static int k230_i2c_xfer_finish(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_uint32_t start_stop_det = k230_i2c_get_timer(0);
+
+    while (1)
+    {
+        if(i2c->raw_intr_stat.stop_det)
+        {
+            readl(&i2c->clr_stop_det);
+            break;
+        }
+
+        else if (k230_i2c_get_timer(start_stop_det) > dev->dev.timeout)
+        {
+            break;
+        }
+    }
+
+    if (k230_i2c_wait_for_bus_busy(dev) != RT_EOK)
+    {
+        return -RT_EBUSY;
+    }
+
+    k230_i2c_flush_rxfifo(dev);
+
+    return RT_EOK;
+}
+
+static int _k230_i2c_read(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_size_t start_time_rx = 0;
+    rt_uint32_t recv_len = dev->msg->len;
+    rt_uint32_t tran_len = dev->msg->len;
+    rt_uint8_t *buffer = dev->msg->buf;
+    rt_uint32_t cmd = 0;
+
+    /* If no start condition is sent before reading, then send a repeated start. */
+    if(dev->msg->flags & RT_I2C_NO_START)
+    {
+        cmd |= I2C_DATA_CMD_RESTART;
+    }
+    else
+    {
+        if(k230_i2c_xfer_init(dev) != RT_EOK)
+        {
+            return -RT_EBUSY;
+        }
+    }
+
+    start_time_rx = k230_i2c_get_timer(0);
+    while(recv_len || tran_len)
+    {
+        if (tran_len)
+        {
+            while(i2c->status.tfnf == 0);
+            /* Write stop when the last byte */
+            cmd = tran_len == 1 ? cmd | I2C_DATA_CMD_STOP : cmd;
+            /* Write to data cmd register to trigger i2c */
+            writel(cmd | I2C_DATA_CMD_READ, &i2c->data_cmd);
+            cmd = 0;
+            tran_len--;
+        }
+
+        if(i2c->status.rfne)
+        {
+            *buffer++ = i2c->data_cmd.dat;
+            recv_len--;
+            start_time_rx = k230_i2c_get_timer(0);
+        }
+        else if(k230_i2c_get_timer(start_time_rx) > dev->dev.timeout)
+        {
+            return -RT_ETIMEOUT;
+        }
+    }
+    return k230_i2c_xfer_finish(dev);
+}
+
+static int _k230_i2c_write(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+    rt_size_t start_time_tx = 0;
+    rt_uint32_t tran_len = dev->msg->len;
+    rt_uint8_t *buffer = dev->msg->buf;
+    rt_uint32_t cmd = 0;
+    rt_uint32_t cut = 0;
+
+    if (k230_i2c_xfer_init(dev) != RT_EOK)
+    {
+        return -RT_EBUSY;
+    }
+
+    start_time_tx = k230_i2c_get_timer(0);
+    while(tran_len)
+    {
+        if(i2c->status.tfnf)
+        {
+            /* If there is no stop flag, the stop condition will not be sent at the last byte. */
+            if(tran_len == 1 && !(dev->msg->flags & RT_I2C_NO_STOP))
+            {
+                cmd |= I2C_DATA_CMD_STOP;
+            }
+            else
+            {
+                cmd &= ~I2C_DATA_CMD_STOP;
+            }
+            cmd |= *buffer++;
+            writel(cmd, &i2c->data_cmd);
+            cmd = 0;
+            tran_len--;
+            start_time_tx = k230_i2c_get_timer(0);
+        }
+        else if(k230_i2c_get_timer(start_time_tx) > dev->dev.timeout)
+        {
+            return -RT_ETIMEOUT;
+        }
+    }
+
+    if (dev->msg->flags & RT_I2C_NO_STOP)
+    {
+        return RT_EOK;
+    }
+
+    if (k230_i2c_wait_for_bus_busy(dev) != RT_EOK)
+    {
+        return -RT_EBUSY;
+    }
+
+    return RT_EOK;
+}
+
+static rt_ssize_t k230_i2c_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
+{
+    struct k230_i2c_dev *i2c_dev = rt_container_of(bus, struct k230_i2c_dev, dev);
+    volatile i2c_t *i2c = (i2c_t *)i2c_dev->base;
+    int ret;
+    rt_ssize_t send_mesgs = num;
+
+    for (; num > 0; num--, msgs++)
+    {
+        i2c_dev->msg = msgs;
+
+        if(msgs->flags & RT_I2C_RD)
+        {
+            ret = _k230_i2c_read(i2c_dev);
+        }
+        else
+        {
+            ret = _k230_i2c_write(i2c_dev);
+        }
+        if (ret != RT_EOK)
+        {
+            return -RT_EIO;
+        }
+    }
+
+    return send_mesgs;
+}
+
+static rt_err_t k230_i2c_control(struct rt_i2c_bus_device *bus, int cmd, void *args)
+{
+    struct k230_i2c_dev *i2c_dev = rt_container_of(bus, struct k230_i2c_dev, dev);
+    rt_uint32_t arg = *(rt_uint32_t *)args;
+    rt_err_t ret;
+
+    RT_ASSERT(bus != RT_NULL);
+
+    switch (cmd)
+    {
+        /* set 10-bit addr mode */
+        case RT_I2C_DEV_CTRL_10BIT:
+            if(arg & RT_I2C_ADDR_10BIT)
+            {
+                i2c_dev->dev.flags |= RT_I2C_ADDR_10BIT;
+            }
+            else
+            {
+                i2c_dev->dev.flags &= ~RT_I2C_ADDR_10BIT;
+            }
+            break;
+
+        case RT_I2C_DEV_CTRL_TIMEOUT:
+            k230_i2c_set_bus_timeout(i2c_dev, arg);
+            break;
+
+        case RT_I2C_DEV_CTRL_CLK:
+            ret = k230_i2c_set_bus_speed(i2c_dev, arg);
+            if (ret != RT_EOK)
+            {
+                return -RT_EIO;
+            }
+            break;
+
+        default: break;
+    }
+
+    return RT_EOK;
+}
+
+static void k230_i2c_master_init(struct k230_i2c_dev *dev)
+{
+    volatile i2c_t *i2c = (i2c_t *)dev->base;
+
+    /* Disable i2c */
+    k230_i2c_enable(dev, RT_FALSE);
+
+    i2c->con.slave_disable = 1;
+    i2c->con.restart_en = 1;
+    i2c->con.master_mode = 1;
+    i2c->tx_tl.tl = I2C_TX_TL;
+    i2c->rx_tl.tl = I2C_RX_TL;
+    i2c->intr_mask.m_stop_det = 1;
+
+    /* Enable i2c */
+    k230_i2c_enable(dev, RT_TRUE);
+}
+
+static const struct rt_i2c_bus_device_ops k230_i2c_ops =
+{
+    .master_xfer = k230_i2c_xfer,
+    .i2c_bus_control = k230_i2c_control,
+};
+
+static struct k230_i2c_dev k230_i2c_devs[] =
+{
+#ifdef BSP_USING_I2C0
+    {
+        .name = "i2c0",
+        .base = I2C0_BASE_ADDR,
+        .size = I2C0_IO_SIZE,
+        .vector = K230_IRQ_I2C0,
+    },
+#endif
+#ifdef BSP_USING_I2C1
+    {
+        .name = "i2c1",
+        .base = I2C1_BASE_ADDR,
+        .size = I2C1_IO_SIZE,
+        .vector = K230_IRQ_I2C1,
+    },
+#endif
+#ifdef BSP_USING_I2C2
+    {
+        .name = "i2c2",
+        .base = I2C2_BASE_ADDR,
+        .size = I2C2_IO_SIZE,
+        .vector = K230_IRQ_I2C2,
+    },
+#endif
+#ifdef BSP_USING_I2C3
+    {
+        .name = "i2c3",
+        .base = I2C3_BASE_ADDR,
+        .size = I2C3_IO_SIZE,
+        .vector = K230_IRQ_I2C3,
+    },
+#endif
+#ifdef BSP_USING_I2C4
+    {
+        .name = "i2c4",
+        .base = I2C4_BASE_ADDR,
+        .size = I2C4_IO_SIZE,
+        .vector = K230_IRQ_I2C4,
+    },
+#endif
+};
+
+int rt_hw_i2c_init(void)
+{
+    int i;
+
+    for (i = 0; i < sizeof(k230_i2c_devs) / sizeof(k230_i2c_devs[0]); i++)
+    {
+        k230_i2c_devs[i].base = (rt_ubase_t)rt_ioremap((void *)k230_i2c_devs[i].base, k230_i2c_devs[i].size);
+        k230_i2c_devs[i].dev.ops = &k230_i2c_ops;
+        k230_i2c_devs[i].clock = sysctl_clk_get_leaf_freq(SYSCTL_CLK_I2C0_CORE + i);
+
+        k230_i2c_master_init(&k230_i2c_devs[i]);
+        k230_i2c_set_bus_timeout(&k230_i2c_devs[i], I2C_DEFAULT_TIMEOUT);
+        k230_i2c_set_bus_speed(&k230_i2c_devs[i], I2C_DEFAULT_SPEED);
+        rt_i2c_bus_device_register(&k230_i2c_devs[i].dev, k230_i2c_devs[i].name);
+        LOG_I("i2c%d master mode, i2c%d clock=%dHz\n", i, i, k230_i2c_devs[i].clock);
+    }
+
+    return RT_EOK;
+}
+INIT_DEVICE_EXPORT(rt_hw_i2c_init);

+ 704 - 0
bsp/k230/drivers/interdrv/i2c/drv_i2c.h

@@ -0,0 +1,704 @@
+/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __DRV_I2C_H__
+#define __DRV_I2C_H__
+#include <stdint.h>
+
+#define BIT(x)              (1<<(x))
+
+/* Speed Selection */
+#define I2C_SPEED_MODE_STANDARD      1
+#define I2C_SPEED_MODE_FAST          2
+#define I2C_SPEED_MODE_MAX           3
+
+#define I2C_MAX_SPEED_UP            3400000
+#define I2C_FAST_SPEED_UP           1000000
+#define I2C_STANDARD_SPEED_UP       100000
+#define I2C_DEFAULT_SPEED           400000
+#define I2C_DEFAULT_TIMEOUT         8       /* 8ms */
+
+/* i2c data cmd definition */
+#define I2C_DATA_CMD_READ            BIT(8)
+#define I2C_DATA_CMD_STOP            BIT(9)
+#define I2C_DATA_CMD_RESTART         BIT(10)
+#define I2C_DATA_CMD_FIRST_DATA_BYTE BIT(11)
+
+/* i2c fifo size */
+#define I2C_TX_FIFO_SIZE    32       /* 32 * 32bit */
+#define I2C_RX_FIFO_SIZE    32       /* 64 * 8bit */
+
+/* fifo threshold register definitions */
+#define I2C_TL0          0x00
+#define I2C_TL1          0x01
+#define I2C_TL2          0x02
+#define I2C_TL3          0x03
+#define I2C_TL4          0x04
+#define I2C_TL5          0x05
+#define I2C_TL6          0x06
+#define I2C_TL7          0x07
+#define I2C_RX_TL        I2C_TL0
+#define I2C_TX_TL        I2C_TL0
+
+/* i2c control register(offset address 0x00) */
+typedef struct _i2c_ic_con
+{
+    uint32_t master_mode                    : 1;
+    uint32_t speed                          : 2;
+    uint32_t slave_10bit_addr               : 1;
+    uint32_t master_10bit_addr              : 1;
+    uint32_t restart_en                     : 1;
+    uint32_t slave_disable                  : 1;
+    uint32_t stop_det_ifaddressed           : 1;
+    uint32_t tx_empty_ctrl                  : 1;
+    uint32_t rx_fifo_full_hld_ctrl          : 1;
+    uint32_t stop_det_if_master_active      : 1;
+    uint32_t bus_clear_feature_ctrl         : 1;
+    uint32_t rsvd_1                         : 4;    /* reserved */
+    uint32_t optional_sar_ctrl              : 1;
+    uint32_t smbus_slave_quick_en           : 1;
+    uint32_t smbus_arp_en                   : 1;
+    uint32_t smbus_persisent_slv_addr_en    : 1;
+    uint32_t rsvd_2                         : 12;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_con_t;
+
+/* i2c target address register(offset address 0x04) */
+typedef struct _i2c_ic_tar
+{
+    uint32_t tar               : 10;
+    uint32_t gc_or_start       : 1;
+    uint32_t special           : 1;
+    uint32_t master_10bit_addr : 1;
+    uint32_t device_id         : 1;
+    uint32_t rsvd_1            : 2;     /* reserved */
+    uint32_t smbus_quick_cmd   : 1;
+    uint32_t rsvd_2            : 15;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_tar_t;
+
+/* i2c slave address register(offset address 0x08) */
+typedef struct _i2c_ic_sar
+{
+    uint32_t sar  : 10;
+    uint32_t rsvd : 22; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_sar_t;
+
+/* i2c high speed master mode code address register(offset address 0x0c) */
+typedef struct _i2c_ic_hs_maddr
+{
+    uint32_t mar  : 3;
+    uint32_t rsvd : 29; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_hs_maddr_t;
+
+/* i2c rx/tx data buffer and command register(offset address 0x10) */
+typedef struct _i2c_ic_data_cmd
+{
+    uint32_t dat             : 8;
+    uint32_t cmd             : 1;
+    uint32_t stop            : 1;
+    uint32_t restart         : 1;
+    uint32_t first_data_byte : 1;
+    uint32_t rsvd            : 20;  /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_data_cmd_t;
+
+/* i2c standard/ultra-fast speed clock scl high count register(offset address 0x14) */
+typedef struct _i2c_ic_ss_ufm_scl_hcnt
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_ss_ufm_scl_hcnt_t;
+
+/* i2c standard/ultra-fast speed clock scl low count register(offset address 0x18) */
+typedef struct _i2c_ic_ss_ufm_scl_lcnt
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_ss_ufm_scl_lcnt_t;
+
+/* i2c fast mode speed clock scl low count/ultra-fast mode speed tbuf idle count register(offset address 0x1c) */
+typedef struct _i2c_ic_fs_scl_hcnt_ufm_tbuf_cnt
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_fs_scl_hcnt_ufm_tbuf_cnt_t;
+
+/* i2c fast mode clock scl low count register(offset address 0x20) */
+typedef struct _i2c_ic_fs_scl_lcnt
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_fs_scl_lcnt_t;
+
+/* i2c high speed mode clock scl high count register(offset address 0x24) */
+typedef struct _i2c_ic_hs_scl_hcnt
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_hs_scl_hcnt_t;
+
+/* i2c high speed mode clock scl low count register(offset address 0x28) */
+typedef struct _i2c_ic_hs_scl_lcnt
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_hs_scl_lcnt_t;
+
+/* i2c interrupt status register(offset address 0x2c) */
+typedef struct _i2c_ic_intr_stat
+{
+    uint32_t r_rx_under         : 1;
+    uint32_t r_rx_over          : 1;
+    uint32_t r_rx_full          : 1;
+    uint32_t r_tx_over          : 1;
+    uint32_t r_tx_empty         : 1;
+    uint32_t r_rd_req           : 1;
+    uint32_t r_tx_abrt          : 1;
+    uint32_t r_rx_done          : 1;
+    uint32_t r_activity         : 1;
+    uint32_t r_stop_det         : 1;
+    uint32_t r_start_det        : 1;
+    uint32_t r_gen_call         : 1;
+    uint32_t r_restart_det      : 1;
+    uint32_t r_master_on_hold   : 1;
+    uint32_t r_slc_stuck_at_low : 1;
+    uint32_t rsvd               : 17;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_intr_stat_t;
+
+/* i2c interrupt mask register(offset address 0x30) */
+typedef struct _i2c_ic_intr_mask
+{
+    uint32_t m_rx_under         : 1;
+    uint32_t m_rx_over          : 1;
+    uint32_t m_rx_full          : 1;
+    uint32_t m_tx_over          : 1;
+    uint32_t m_tx_empty         : 1;
+    uint32_t m_rd_req           : 1;
+    uint32_t m_tx_abrt          : 1;
+    uint32_t m_rx_done          : 1;
+    uint32_t m_activity         : 1;
+    uint32_t m_stop_det         : 1;
+    uint32_t m_start_det        : 1;
+    uint32_t m_gen_call         : 1;
+    uint32_t m_restart_det      : 1;
+    uint32_t m_master_on_hold   : 1;
+    uint32_t m_slc_stuck_at_low : 1;
+    uint32_t rsvd               : 17;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_intr_mask_t;
+
+/* i2c raw interrupt status register(offset address 0x34) */
+typedef struct _i2c_ic_raw_intr_stat
+{
+    uint32_t rx_under           : 1;
+    uint32_t rx_over            : 1;
+    uint32_t rx_full            : 1;
+    uint32_t tx_over            : 1;
+    uint32_t tx_empty           : 1;
+    uint32_t rd_req             : 1;
+    uint32_t tx_abrt            : 1;
+    uint32_t rx_done            : 1;
+    uint32_t activity           : 1;
+    uint32_t stop_det           : 1;
+    uint32_t start_det          : 1;
+    uint32_t gen_call           : 1;
+    uint32_t restart_det        : 1;
+    uint32_t master_on_hold     : 1;
+    uint32_t scl_stuck_at_low   : 1;
+    uint32_t rsvd               : 17;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_raw_intr_stat_t;
+
+/* i2c receive FIFO threshold register(offset address 0x38) */
+typedef struct _i2c_ic_rx_tl
+{
+    uint32_t tl   : 8;
+    uint32_t rsvd : 24;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_rx_tl_t;
+
+/* i2c transmit FIFO threshold register(offset address 0x3c) */
+typedef struct _i2c_ic_tx_tl
+{
+    uint32_t tl   : 8;
+    uint32_t rsvd : 24; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_tx_tl_t;
+
+/* i2c clear combined and individual interrupt register(offset address 0x40) */
+typedef struct _i2c_ic_clr_intr
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_intr_t;
+
+/* i2c clear rx under interrupt register(offset address 0x44) */
+typedef struct _i2c_ic_clr_rx_under
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_rx_under_t;
+
+/* i2c clear rx over interrupt register(offset address 0x48) */
+typedef struct _i2c_ic_clr_rx_over
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_rx_over_t;
+
+/* i2c clear tx over interrupt register(offset address 0x4c) */
+typedef struct _i2c_ic_clr_tx_over
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_tx_over_t;
+
+/* i2c clear rd req interrupt register(offset address 0x50) */
+typedef struct _i2c_ic_clr_rd_req
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_rd_req_t;
+
+/* i2c clear tx abrt interrupt register(offset address 0x54) */
+typedef struct _i2c_ic_clr_tx_abrt
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_tx_abrt_t;
+
+/* i2c clear rx done interrupt register(offset address 0x58) */
+typedef struct _i2c_ic_clr_rx_done
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_rx_done_t;
+
+/* i2c clear activity interrupt register(offset address 0x5c) */
+typedef struct _i2c_ic_clr_activity
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_activity_t;
+
+/* i2c clear stop det interrupt register(offset address 0x60) */
+typedef struct _i2c_clr_stop_det
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_stop_det_t;
+
+/* i2c clear start det interrupt register(offset address 0x64) */
+typedef struct _i2c_ic_clr_start_det
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_start_det_t;
+
+/* i2c clear gen call interrupt register(offset address 0x68) */
+typedef struct _i2c_ic_clr_gen_call
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_gen_call_t;
+
+/* i2c enable register(offset address 0x6c) */
+typedef struct _i2c_ic_enable
+{
+    uint32_t enable                    : 1;
+    uint32_t abort                     : 1;
+    uint32_t tx_cmd_block              : 1;
+    uint32_t sda_stuck_recovery_enable : 1;
+    uint32_t rsvd_1                    : 12;    /* reserved */
+    uint32_t smbus_clk_reset           : 1;
+    uint32_t smbus_suspned_en          : 1;
+    uint32_t smbus_alert_en            : 1;
+    uint32_t rsvd_2                    : 13;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_enable_t;
+
+/* i2c status register(offset address 0x70) */
+typedef struct _i2c_ic_status
+{
+    uint32_t activity                  : 1;
+    uint32_t tfnf                      : 1;
+    uint32_t tfe                       : 1;
+    uint32_t rfne                      : 1;
+    uint32_t rff                       : 1;
+    uint32_t mst_activity              : 1;
+    uint32_t slv_activity              : 1;
+    uint32_t mst_hold_tx_fifo_empty    : 1;
+    uint32_t mst_hold_rx_fifo_full     : 1;
+    uint32_t slv_hold_tx_fifo_empty    : 1;
+    uint32_t slv_hold_rx_fifo_full     : 1;
+    uint32_t sda_stuck_not_recovered   : 1;
+    uint32_t rsvd_1                    : 4;     /* reserved */
+    uint32_t smbus_quick_cmd_bit       : 1;
+    uint32_t smbus_slave_addr_valid    : 1;
+    uint32_t smbus_slave_addr_resolved : 1;
+    uint32_t smbus_suspend_status      : 1;
+    uint32_t smbus_alert               : 1;
+    uint32_t rsvd_2                    : 11;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_status_t;
+
+/* i2c transmit fifo level register(offset address 0x74) */
+typedef struct _i2c_ic_txflr
+{
+    uint32_t txflr : 5;
+    uint32_t rsvd  : 27;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_txflr_t;
+
+/* i2c receive fifo level register(offset address 0x78) */
+typedef struct _i2c_ic_rxflr
+{
+    uint32_t rxflr : 5;
+    uint32_t rsvd  : 27;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_rxflr_t;
+
+/* i2c sda hold time length register(offset address 0x7c) */
+typedef struct _i2c_ic_sda_hold
+{
+    uint32_t tx_hold : 16;
+    uint32_t rx_hold : 8;
+    uint32_t rsvd    : 8;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_sda_hold_t;
+
+/* i2c transmit abort source register(offset address 0x80) */
+typedef struct _i2c_ic_tx_abrt_source
+{
+    uint32_t abrt_7b_addr_noack        : 1;
+    uint32_t abrt_10addr1_noack        : 1;
+    uint32_t abrt_10addr2_noack        : 1;
+    uint32_t abrt_txdata_noack         : 1;
+    uint32_t abrt_gcall_noack          : 1;
+    uint32_t abrt_gcall_read           : 1;
+    uint32_t abrt_hs_ackdet            : 1;
+    uint32_t abrt_sbyte_ackdet         : 1;
+    uint32_t abrt_hs_norstrt           : 1;
+    uint32_t abrt_sbyte_norstrt        : 1;
+    uint32_t abrt_10b_rd_norstrt       : 1;
+    uint32_t abrt_master_dis           : 1;
+    uint32_t abrt_lost                 : 1;
+    uint32_t abrt_slvflush_txfifo      : 1;
+    uint32_t abrt_slv_arblost          : 1;
+    uint32_t abrt_slvrd_intx           : 1;
+    uint32_t abrt_user_abrt            : 1;
+    uint32_t abrt_sda_stuck_at_low     : 1;
+    uint32_t abrt_device_noack         : 1;
+    uint32_t abrt_device_slvaddr_noack : 1;
+    uint32_t abrt_device_write         : 1;
+    uint32_t rsvd                      : 2; /* reserved */
+    uint32_t tx_flush_cnt              : 9;
+} __attribute__((packed, aligned(4))) i2c_ic_tx_abrt_source_t;
+
+/* i2c generate slave data nack register(offset address 0x84) */
+typedef struct _i2c_ic_slv_data_nack_only
+{
+    uint32_t nack : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_slv_data_nack_only_t;
+
+/* i2c dma control register(offset address 0x88) */
+typedef struct _i2c_ic_dma_cr
+{
+    uint32_t rdmae : 1;
+    uint32_t tdmae : 1;
+    uint32_t rsvd  : 30;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_dma_cr_t;
+
+/* i2c dma transmit data level register(offset address 0x8c) */
+typedef struct _i2c_ic_dma_tdlr
+{
+    uint32_t dmatdl : 5;
+    uint32_t rsvd   : 27;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_dma_tdlr_t;
+
+/* i2c dma receive data level register(offset address 0x90) */
+typedef struct _i2c_ic_dma_rdlr
+{
+    uint32_t dmardl : 5;
+    uint32_t rsvd   : 27;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_dma_rdlr_t;
+
+/* i2c sda setup register(offset address 0x94) */
+typedef struct _i2c_ic_sda_setup
+{
+    uint32_t setup : 8;
+    uint32_t rsvd  : 24;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_sda_setup_t;
+
+/* i2c ack general call register(offset address 0x98) */
+typedef struct _i2c_ic_ack_general_call
+{
+    uint32_t ask  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_ack_general_call_t;
+
+/* i2c enable status register(offset address 0x9c) */
+typedef struct _i2c_ic_enable_status
+{
+    uint32_t en                      : 1;
+    uint32_t slv_disabled_while_busy : 1;
+    uint32_t slv_rx_data_lost        : 1;
+    uint32_t rsvd                    : 29;  /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_enable_status_t;
+
+/* i2c ss, fs, or fm+/ufm spike suppression limit register(offset address 0xa0) */
+typedef struct _i2c_ic_fs_ufm_spklen
+{
+    uint32_t spklen : 8;
+    uint32_t rsvd   : 24;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_fs_ufm_spklen_t;
+
+/* i2c hs spike suppression limit register(offset address 0xa4) */
+typedef struct _i2c_ic_hs_spklen
+{
+    uint32_t spklen : 8;
+    uint32_t rsvd   : 24;   /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_hs_spklen_t;
+
+/* i2c clear restart det interrupt register(offset address 0xa8) */
+typedef struct _i2c_ic_clr_restart_det
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_restart_det_t;
+
+/* i2c scl stuck at low timeout register(offset address 0xac) */
+typedef struct _i2c_ic_scl_stuck_at_low_timeout
+{
+    uint32_t timeout  : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_scl_stuck_at_low_timeout_t;
+
+/* i2c sda stuck at low timeout register(offset address 0xb0) */
+typedef struct _i2c_ic_sda_stuck_at_low_timeout
+{
+    uint32_t timeout  : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_sda_stuck_at_low_timeout_t;
+
+/* i2c clear scl stuck at low detect interrupt register(offset address 0xb4) */
+typedef struct _i2c_ic_clr_slc_stuck_det
+{
+    uint32_t clr  : 1;
+    uint32_t rsvd : 31; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_slc_stuck_det_t;
+
+/* i2c device id register(offset address 0xb8) */
+typedef struct _i2c_ic_device_id
+{
+    uint32_t device_id : 24;
+    uint32_t rsvd      : 8; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_device_id_t;
+
+/* i2c smbus slave clock extend timeout register(offset address 0xbc) */
+typedef struct _i2c_ic_smbus_clk_low_sext
+{
+    uint32_t timeout : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_clk_low_sext_t;
+
+/* i2c smbus master clock extend timeout register(offset address 0xc0) */
+typedef struct _i2c_ic_smbus_clk_low_mext
+{
+    uint32_t timeout : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_clk_low_mext_t;
+
+/* i2c smbus master thigh max bus-idle count register(offset address 0xc4) */
+typedef struct _i2c_ic_smbus_thigh_max_idle_count
+{
+    uint32_t cnt  : 16;
+    uint32_t rsvd : 16; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_thigh_max_idle_count_t;
+
+/* i2c smbus interrupt status register(offset address 0xc8) */
+typedef struct _i2c_ic_smbus_intr_stat
+{
+    uint32_t r_slv_clock_extnd_timeout : 1;
+    uint32_t r_mst_clock_extnd_timeout : 1;
+    uint32_t r_quick_cmd_det           : 1;
+    uint32_t r_host_notify_mst_det     : 1;
+    uint32_t r_arp_prepare_cmd_det     : 1;
+    uint32_t r_arp_rst_cmd_det         : 1;
+    uint32_t r_arp_get_udid_cmd_det    : 1;
+    uint32_t r_arp_assgn_addr_cmd_det  : 1;
+    uint32_t r_slv_rx_pec_nack         : 1;
+    uint32_t r_smbus_suspend_det       : 1;
+    uint32_t r_smbus_alert_det         : 1;
+    uint32_t rsvd                      : 21;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_intr_stat_t;
+
+/* i2c smbus interrupt mask register(offset address 0xcc) */
+typedef struct _i2c_ic_smbus_intr_mask
+{
+    uint32_t m_slv_clock_extnd_timeout : 1;
+    uint32_t m_mst_clock_extnd_timeout : 1;
+    uint32_t m_quick_cmd_det           : 1;
+    uint32_t m_host_notify_mst_det     : 1;
+    uint32_t m_arp_prepare_cmd_det     : 1;
+    uint32_t m_arp_rst_cmd_det         : 1;
+    uint32_t m_arp_get_udid_cmd_det    : 1;
+    uint32_t m_arp_assgn_addr_cmd_det  : 1;
+    uint32_t m_slv_rx_pec_nack         : 1;
+    uint32_t m_smbus_suspend_det       : 1;
+    uint32_t m_smbus_alert_det         : 1;
+    uint32_t rsvd                      : 21;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_intr_mask_t;
+
+/* i2c smbus raw interrupt status register(offset address 0xd0) */
+typedef struct _i2c_ic_smbus_raw_intr_stat
+{
+    uint32_t slv_clock_extnd_timeout : 1;
+    uint32_t mst_clock_extnd_timeout : 1;
+    uint32_t quick_cmd_det           : 1;
+    uint32_t host_notify_mst_det     : 1;
+    uint32_t arp_prepare_cmd_det     : 1;
+    uint32_t arp_rst_cmd_det         : 1;
+    uint32_t arp_get_udid_cmd_det    : 1;
+    uint32_t arp_assgn_addr_cmd_det  : 1;
+    uint32_t slv_rx_pec_nack         : 1;
+    uint32_t smbus_suspend_det       : 1;
+    uint32_t smbus_alert_det         : 1;
+    uint32_t rsvd                    : 21;  /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_raw_intr_stat_t;
+
+/* i2c smbus clear interrupt register(offset address 0xd4) */
+typedef struct _i2c_ic_clr_smbus_intr
+{
+    uint32_t slv_clock_extnd_timeout : 1;
+    uint32_t mst_clock_extnd_timeout : 1;
+    uint32_t quick_cmd_det           : 1;
+    uint32_t host_notify_mst_det     : 1;
+    uint32_t arp_prepare_cmd_det     : 1;
+    uint32_t arp_rst_cmd_det         : 1;
+    uint32_t arp_get_udid_cmd_det    : 1;
+    uint32_t arp_assgn_addr_cmd_det  : 1;
+    uint32_t slv_rx_pec_nack         : 1;
+    uint32_t smbus_suspend_det       : 1;
+    uint32_t smbus_alert_det         : 1;
+    uint32_t rsvd                    : 21;  /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_clr_smbus_intr_t;
+
+/* i2c optional slave address register(offset address 0xd8) */
+typedef struct _i2c_ic_optional_sar
+{
+    uint32_t sar  : 7;
+    uint32_t rsvd : 25; /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_optional_sar_t;
+
+/* i2c smbus udid lsb register(offset address 0xdc) */
+typedef struct _i2c_ic_smbus_udid_lsb
+{
+    uint32_t udid_lsb : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_smbus_udid_lsb_t;
+
+/* i2c component parameter 1 register(offset address 0xf4) */
+typedef struct _i2c_ic_comp_param_1
+{
+    uint32_t apb_data_width     : 2;
+    uint32_t max_speed_mode     : 2;
+    uint32_t hc_count_values    : 1;
+    uint32_t intr_io            : 1;
+    uint32_t has_dma            : 1;
+    uint32_t add_encoded_params : 1;
+    uint32_t rx_buffer_depth    : 8;
+    uint32_t tx_buffer_depth    : 8;
+    uint32_t rsvd               : 8;    /* reserved */
+} __attribute__((packed, aligned(4))) i2c_ic_comp_param_1_t;
+
+/* i2c component version register(offset address 0xf8) */
+typedef struct _i2c_ic_comp_version
+{
+    uint32_t version : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_comp_version_t;
+
+/* i2c component type register(offset address 0xfc) */
+typedef struct _i2c_ic_comp_type
+{
+    uint32_t type : 32;
+} __attribute__((packed, aligned(4))) i2c_ic_comp_type_t;
+
+/* i2c register */
+typedef struct _i2c
+{
+    i2c_ic_con_t                        con;                        /* 0x00 */
+    i2c_ic_tar_t                        tar;                        /* 0x04 */
+    i2c_ic_sar_t                        sar;                        /* 0x08 */
+    i2c_ic_hs_maddr_t                   hs_maddr;                   /* 0x0c */
+    i2c_ic_data_cmd_t                   data_cmd;                   /* 0x10 */
+    i2c_ic_ss_ufm_scl_hcnt_t            ss_ufm_scl_hcnt;            /* 0x14 */
+    i2c_ic_ss_ufm_scl_lcnt_t            ss_ufm_scl_lcnt;            /* 0x18 */
+    i2c_ic_fs_scl_hcnt_ufm_tbuf_cnt_t   fs_scl_hcnt_ufm_tbuf_cnt;   /* 0x1c */
+    i2c_ic_fs_scl_lcnt_t                fs_scl_lcnt;                /* 0x20 */
+    i2c_ic_hs_scl_hcnt_t                hs_scl_hcnt;                /* 0x24 */
+    i2c_ic_hs_scl_lcnt_t                hs_scl_lcnt;                /* 0x28 */
+    i2c_ic_intr_stat_t                  intr_stat;                  /* 0x2c */
+    i2c_ic_intr_mask_t                  intr_mask;                  /* 0x30 */
+    i2c_ic_raw_intr_stat_t              raw_intr_stat;              /* 0x34 */
+    i2c_ic_rx_tl_t                      rx_tl;                      /* 0x38 */
+    i2c_ic_tx_tl_t                      tx_tl;                      /* 0x3c */
+    i2c_ic_clr_intr_t                   clr_intr;                   /* 0x40 */
+    i2c_ic_clr_rx_under_t               clr_rx_under;               /* 0x44 */
+    i2c_ic_clr_rx_over_t                clr_rx_over;                /* 0x48 */
+    i2c_ic_clr_tx_over_t                clr_tx_over;                /* 0x4c */
+    i2c_ic_clr_rd_req_t                 clr_rd_req;                 /* 0x50 */
+    i2c_ic_clr_tx_abrt_t                clr_tx_abrt;                /* 0x54 */
+    i2c_ic_clr_rx_done_t                clr_rx_done;                /* 0x58 */
+    i2c_ic_clr_activity_t               clr_activity;               /* 0x5c */
+    i2c_ic_clr_stop_det_t               clr_stop_det;               /* 0x60 */
+    i2c_ic_clr_start_det_t              clr_start_det;              /* 0x64 */
+    i2c_ic_clr_gen_call_t               clr_gen_call;               /* 0x68 */
+    i2c_ic_enable_t                     enable;                     /* 0x6c */
+    i2c_ic_status_t                     status;                     /* 0x70 */
+    i2c_ic_txflr_t                      txflr;                      /* 0x74 */
+    i2c_ic_rxflr_t                      rxflr;                      /* 0x78 */
+    i2c_ic_sda_hold_t                   sda_hold;                   /* 0x7c */
+    i2c_ic_tx_abrt_source_t             tx_abrt_source;             /* 0x80 */
+    i2c_ic_slv_data_nack_only_t         slv_data_nack_only;         /* 0x84 */
+    i2c_ic_dma_cr_t                     dma_cr;                     /* 0x88 */
+    i2c_ic_dma_tdlr_t                   dma_tdlr;                   /* 0x8c */
+    i2c_ic_dma_rdlr_t                   dma_rdlr;                   /* 0x90 */
+    i2c_ic_sda_setup_t                  sda_setup;                  /* 0x94 */
+    i2c_ic_ack_general_call_t           ack_general_call;           /* 0x98 */
+    i2c_ic_enable_status_t              enable_status;              /* 0x9c */
+    i2c_ic_fs_ufm_spklen_t              fs_ufm_spklen;              /* 0xa0 */
+    i2c_ic_hs_spklen_t                  hs_spklen;                  /* 0xa4 */
+    i2c_ic_clr_restart_det_t            clr_restart_det;            /* 0xa8 */
+    i2c_ic_scl_stuck_at_low_timeout_t   scl_stuck_at_low_timeout;   /* 0xac */
+    i2c_ic_sda_stuck_at_low_timeout_t   sda_stuck_at_low_timeout;   /* 0xb0 */
+    i2c_ic_clr_slc_stuck_det_t          clr_slc_stuck_det;          /* 0xb4 */
+    i2c_ic_device_id_t                  device_id;                  /* 0xb8 */
+    i2c_ic_smbus_clk_low_sext_t         smbus_clk_low_sext;         /* 0xbc */
+    i2c_ic_smbus_clk_low_mext_t         smbus_clk_low_mext;         /* 0xc0 */
+    i2c_ic_smbus_thigh_max_idle_count_t smbus_thigh_max_idle_count; /* 0xc4 */
+    i2c_ic_smbus_intr_stat_t            smbus_intr_stat;            /* 0xc8 */
+    i2c_ic_smbus_intr_mask_t            smbus_intr_mask;            /* 0xcc */
+    i2c_ic_smbus_raw_intr_stat_t        smbus_raw_intr_stat;        /* 0xd0 */
+    i2c_ic_clr_smbus_intr_t             clr_smbus_intr;             /* 0xd4 */
+    i2c_ic_optional_sar_t               optional_sar;               /* 0xd8 */
+    i2c_ic_smbus_udid_lsb_t             smbus_udid_lsb;             /* 0xdc */
+    uint32_t                            rsvd_1[5];                  /* 0xe0-0xf0 reserved */
+    i2c_ic_comp_param_1_t               comp_param_1;               /* 0xf4 */
+    i2c_ic_comp_version_t               comp_version;               /* 0xf8 */
+    i2c_ic_comp_type_t                  comp_type;                  /* 0xfc */
+} __attribute__((packed, aligned(4))) i2c_t;
+
+#endif /* __DRV_I2C_H__ */

+ 4 - 1
bsp/k230/drivers/utest/SConscript

@@ -29,7 +29,10 @@ if GetDepend('BSP_UTEST_DRIVERS'):
 
     if GetDepend('BSP_USING_RTC'):
         src += ['test_rtc.c']
-        
+
+    if GetDepend('BSP_USING_I2C'):
+        src += ['test_i2c.c']
+
 group = DefineGroup('utestcases', src, depend = [''])
 
 Return('group')

+ 204 - 0
bsp/k230/drivers/utest/test_i2c.c

@@ -0,0 +1,204 @@
+/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <utest.h>
+#include <string.h>
+#include "drv_i2c.h"
+#include "drv_pinctrl.h"
+#include "drv_gpio.h"
+
+/*
+ * 测试K230 I2C的主从机通信,在这里采用I2C0作为测试对象
+ *
+ * 硬件平台:
+ * 测试的硬件平台为庐山派开发板,使用的I2C0引脚是GPIO048(SCL)
+ * 和GPIO049(SDA)。
+ *
+ * 测试说明:
+ * 1. 测试I2C0主机模式
+ *     主机模式下,主机向从机发送16字节数据(不包括写读地址),
+ *     然后再读取回来进行校验,共执行两次,分别是400kHz和1MHz速率。
+ *     注:使用的从机为AT24C08 EEPROM,设备地址为0x50。
+ */
+
+#define I2C_NAME            "i2c0"
+#define TARGET_ADDR         0x50
+
+#define TEST_BUFFER_SIZE    16
+
+#define I2C_SCL_PIN         48
+#define I2C_SDA_PIN         49
+#define I2C_SCL_PIN_AF      IOMUX_FUNC4
+#define I2C_SDA_PIN_AF      IOMUX_FUNC4
+
+static void test_i2c0_deinit_pin(void)
+{
+    k230_pinctrl_set_function(I2C_SCL_PIN, IOMUX_FUNC1);
+    k230_pinctrl_set_function(I2C_SDA_PIN, IOMUX_FUNC1);
+    k230_pinctrl_set_oe(I2C_SCL_PIN, 0);
+    k230_pinctrl_set_oe(I2C_SDA_PIN, 0);
+    k230_pinctrl_set_ie(I2C_SCL_PIN, 1);
+    k230_pinctrl_set_ie(I2C_SDA_PIN, 1);
+
+    kd_pin_mode(I2C_SCL_PIN, GPIO_DM_INPUT);
+    kd_pin_mode(I2C_SDA_PIN, GPIO_DM_INPUT);
+}
+
+static void test_i2c0_init_pin(void)
+{
+    k230_pinctrl_set_function(I2C_SCL_PIN, I2C_SCL_PIN_AF); // I2C0_SCL
+    k230_pinctrl_set_function(I2C_SDA_PIN, I2C_SDA_PIN_AF); // I2C0_SDA
+    k230_pinctrl_set_oe(I2C_SCL_PIN, 1);
+    k230_pinctrl_set_oe(I2C_SDA_PIN, 1);
+    k230_pinctrl_set_ie(I2C_SCL_PIN, 1);
+    k230_pinctrl_set_ie(I2C_SDA_PIN, 1);
+}
+
+static int test_i2c_check_pin(void)
+{
+    test_i2c0_deinit_pin();
+
+    if(kd_pin_read(I2C_SCL_PIN) != 1 || kd_pin_read(I2C_SDA_PIN) != 1)
+    {
+        LOG_W("i2c bus is not idle, try to recover it.");
+        k230_pinctrl_set_oe(I2C_SCL_PIN, 1);
+        kd_pin_mode(I2C_SCL_PIN, GPIO_DM_OUTPUT);
+        for(rt_uint8_t i = 0; i < 9; i++)
+        {
+            kd_pin_write(I2C_SCL_PIN, 0);
+            rt_hw_us_delay(2);
+            kd_pin_write(I2C_SCL_PIN, 1);
+            rt_hw_us_delay(2);
+        }
+        k230_pinctrl_set_oe(I2C_SCL_PIN, 0);
+        kd_pin_mode(I2C_SCL_PIN, GPIO_DM_INPUT);
+    }
+
+    if(kd_pin_read(I2C_SCL_PIN) != 1 || kd_pin_read(I2C_SDA_PIN) != 1)
+    {
+        LOG_E("i2c bus recover failed");
+        return -RT_ERROR;
+    }
+
+    LOG_I("i2c bus(pin: %u, %u) is idle, init i2c bus pin", I2C_SCL_PIN, I2C_SDA_PIN);
+    test_i2c0_init_pin();
+
+    return RT_EOK;
+}
+
+static void _test_i2c0_master(rt_uint8_t *buffer_w, rt_uint8_t *buffer_r, rt_uint32_t size, rt_uint32_t speed)
+{
+    rt_err_t ret = RT_EOK;
+    struct rt_i2c_bus_device *dev;
+    struct rt_i2c_msg msgs[2];
+
+    dev = rt_i2c_bus_device_find(I2C_NAME);
+    uassert_not_null(dev);
+    rt_i2c_control(dev, RT_I2C_DEV_CTRL_CLK, (void *)&speed);
+
+    msgs[0].addr  = TARGET_ADDR;
+    msgs[0].flags = RT_I2C_WR;
+    msgs[0].buf   = buffer_w;
+    msgs[0].len   = size + 1;
+
+    if(rt_i2c_transfer(dev, msgs, 1) != 1)
+    {
+        LOG_E("i2c transfer failed");
+        uassert_true(0);
+    }
+
+    rt_thread_mdelay(10);
+
+    msgs[0].addr  = TARGET_ADDR;
+    msgs[0].flags = RT_I2C_WR | RT_I2C_NO_STOP;
+    msgs[0].buf   = &buffer_r[0];
+    msgs[0].len   = 1;
+
+    msgs[1].addr  = TARGET_ADDR;
+    msgs[1].flags = RT_I2C_RD | RT_I2C_NO_START;
+    msgs[1].buf   = &buffer_r[1];
+    msgs[1].len   = size;
+
+    if(rt_i2c_transfer(dev, msgs, 2) != 2)
+    {
+        LOG_E("i2c transfer failed");
+        uassert_true(0);
+    }
+
+    LOG_I("Read data:\n");
+    for(rt_uint8_t i = 1; i < size + 1; i++)
+    {
+        LOG_I("0x%02X ", buffer_r[i]);
+    }
+    uassert_buf_equal(buffer_w + 1, buffer_r + 1, size);
+}
+
+static void test_i2c0_master(void)
+{
+    rt_uint8_t buffer_w[TEST_BUFFER_SIZE + 1];
+    rt_uint8_t buffer_r[TEST_BUFFER_SIZE + 1];
+    rt_uint32_t size = TEST_BUFFER_SIZE;
+    rt_uint32_t speed = 400000; // 400kHz
+
+    memset(buffer_w + 1, 0xAA, TEST_BUFFER_SIZE);
+    buffer_w[0] = 0x00; // memory address
+    memset(buffer_r, 0x00, TEST_BUFFER_SIZE + 1);
+
+    _test_i2c0_master(buffer_w, buffer_r, size, speed);
+
+    speed = 1000000; // 1MHz
+    memset(buffer_w + 1, 0x55, TEST_BUFFER_SIZE);
+    buffer_w[0] = 0x00; // memory address
+    memset(buffer_r, 0x00, TEST_BUFFER_SIZE + 1);
+
+    _test_i2c0_master(buffer_w, buffer_r, size, speed);
+}
+
+static void testcase(void)
+{
+    LOG_I("This is a i2c test case.\n");
+    UTEST_UNIT_RUN(test_i2c0_master);
+}
+
+static rt_err_t utest_tc_init(void)
+{
+    return test_i2c_check_pin();
+}
+
+static rt_err_t utest_tc_cleanup(void)
+{
+    LOG_I("i2c bus pin deinit.\n");
+    test_i2c0_deinit_pin();
+    return RT_EOK;
+}
+UTEST_TC_EXPORT(testcase, "bsp.k230.drivers.i2c", utest_tc_init, utest_tc_cleanup, 100);

+ 1 - 0
bsp/k230/rtconfig.h

@@ -276,6 +276,7 @@
 
 #define RT_USING_SAL
 #define SAL_INTERNET_CHECK
+#define SOCKET_TABLE_STEP_LEN 4
 
 /* Docking with protocol stacks */