diff --git a/bsp/k230/.ci/attachconfig/ci.attachconfig.yml b/bsp/k230/.ci/attachconfig/ci.attachconfig.yml new file mode 100644 index 00000000000..7c483f0c22c --- /dev/null +++ b/bsp/k230/.ci/attachconfig/ci.attachconfig.yml @@ -0,0 +1,21 @@ +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 +devices.i2c.master: + <<: *scons + depends: + - devices.i2c + kconfig: + - CONFIG_BSP_USING_I2C0_MASTER=y +devices.i2c.slave: + <<: *scons + depends: + - devices.i2c + kconfig: + - CONFIG_BSP_USING_I2C0_SLAVE=y \ No newline at end of file diff --git a/bsp/k230/.config b/bsp/k230/.config index 2031a0ba16a..60b963235dc 100644 --- a/bsp/k230/.config +++ b/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 @@ -313,7 +314,11 @@ CONFIG_RT_USING_SERIAL_BYPASS=y CONFIG_RT_USING_CPUTIME=y CONFIG_RT_USING_CPUTIME_RISCV=y CONFIG_CPUTIME_TIMER_FREQ=25000000 -# CONFIG_RT_USING_I2C is not set +CONFIG_RT_USING_I2C=y +# CONFIG_RT_I2C_DEBUG is not set +CONFIG_RT_USING_I2C_BITOPS=y +# CONFIG_RT_I2C_BITOPS_DEBUG is not set +# CONFIG_RT_USING_SOFT_I2C is not set # CONFIG_RT_USING_PHY is not set # CONFIG_RT_USING_PHY_V2 is not set # CONFIG_RT_USING_ADC is not set @@ -425,6 +430,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 +1623,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 diff --git a/bsp/k230/board/Kconfig b/bsp/k230/board/Kconfig index 3604e5ad81e..47d9c41eff3 100644 --- a/bsp/k230/board/Kconfig +++ b/bsp/k230/board/Kconfig @@ -1,4 +1,110 @@ menu "Drivers Configuration" + menuconfig BSP_USING_I2C + bool "Enable I2C" + select RT_USING_I2C + default n + + if BSP_USING_I2C + menuconfig BSP_USING_I2C0 + bool "Enable I2C0" + default n + + if BSP_USING_I2C0 + choice BSP_I2C0_DEV_MODE + prompt "Select I2C0 device mode" + default BSP_USING_I2C0_MASTER + help + Select the I2C0 device mode to be used. + + config BSP_USING_I2C0_MASTER + bool "Enable I2C0 Master Mode" + + config BSP_USING_I2C0_SLAVE + bool "Enable I2C0 Slave Mode" + + endchoice + endif + + menuconfig BSP_USING_I2C1 + bool "Enable I2C1" + default n + + if BSP_USING_I2C1 + choice BSP_I2C1_DEV_MODE + prompt "Select I2C1 device mode" + default BSP_USING_I2C1_MASTER + help + Select the I2C1 device mode to be used. + + config BSP_USING_I2C1_MASTER + bool "Enable I2C1 Master Mode" + + config BSP_USING_I2C1_SLAVE + bool "Enable I2C1 Slave Mode" + + endchoice + endif + + menuconfig BSP_USING_I2C2 + bool "Enable I2C2" + default n + + if BSP_USING_I2C2 + choice BSP_I2C2_DEV_MODE + prompt "Select I2C2 device mode" + default BSP_USING_I2C2_MASTER + help + Select the I2C2 device mode to be used. + + config BSP_USING_I2C2_MASTER + bool "Enable I2C2 Master Mode" + + config BSP_USING_I2C2_SLAVE + bool "Enable I2C2 Slave Mode" + + endchoice + endif + + menuconfig BSP_USING_I2C3 + bool "Enable I2C3" + default n + + if BSP_USING_I2C3 + choice BSP_I2C3_DEV_MODE + prompt "Select I2C3 device mode" + default BSP_USING_I2C3_MASTER + help + Select the I2C3 device mode to be used. + + config BSP_USING_I2C3_MASTER + bool "Enable I2C3 Master Mode" + + config BSP_USING_I2C3_SLAVE + bool "Enable I2C3 Slave Mode" + + endchoice + endif + + menuconfig BSP_USING_I2C4 + bool "Enable I2C4" + default n + + if BSP_USING_I2C4 + choice BSP_I2C4_DEV_MODE + prompt "Select I2C4 device mode" + default BSP_USING_I2C4_MASTER + help + Select the I2C4 device mode to be used. + + config BSP_USING_I2C4_MASTER + bool "Enable I2C4 Master Mode" + + config BSP_USING_I2C4_SLAVE + bool "Enable I2C4 Slave Mode" + + endchoice + endif + endif config BSP_USING_RTC bool "Enable RTC" diff --git a/bsp/k230/drivers/interdrv/i2c/SConscript b/bsp/k230/drivers/interdrv/i2c/SConscript new file mode 100644 index 00000000000..18cbbb1c9f2 --- /dev/null +++ b/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') diff --git a/bsp/k230/drivers/interdrv/i2c/drv_i2c.c b/bsp/k230/drivers/interdrv/i2c/drv_i2c.c new file mode 100644 index 00000000000..ed30e8ae363 --- /dev/null +++ b/bsp/k230/drivers/interdrv/i2c/drv_i2c.c @@ -0,0 +1,946 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#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 + +#define I2C_SLAVE_STATUS_ACTIVE 0x01 +#define I2C_SLAVE_STATUS_WRITE_IN_PROGRESS 0x02 +#define I2C_SLAVE_STATUS_READ_IN_PROGRESS 0x04 + +#define I2C_SLAVE_BUFFER_SIZE 256 + +enum _i2c_slave_event +{ + I2C_SLAVE_READ_REQUESTED, + I2C_SLAVE_WRITE_REQUESTED, + I2C_SLAVE_READ_PROCESSED, + I2C_SLAVE_WRITE_RECEIVED, + I2C_SLAVE_STOP, +}; + +typedef void(*i2c_slave_cb)(void *ctx, enum _i2c_slave_event event, rt_uint8_t *val); + +struct _i2c_slave +{ + rt_bool_t en; + rt_uint8_t address; + void *callback_ctx; + i2c_slave_cb callback; + rt_uint32_t status; +}; + +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_slave slave; + struct _i2c_speed_cfg speed_cfg; +}; + +static rt_size_t i2c_get_timer(rt_size_t base) +{ + return rt_tick_get() - base ; +} + +static void 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 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 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; + + if(dev->slave.en) + { + return -RT_EINVAL; + } + + /* + * 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 */ + 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 */ + i2c_enable(dev, RT_TRUE); + + return RT_EOK; +} + +static void 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 */ + 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 */ + i2c_enable(dev, RT_TRUE); +} + +static void 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 i2c_wait_for_bus_busy(struct k230_i2c_dev *dev) +{ + rt_size_t start_time = i2c_get_timer(0); + volatile i2c_t *i2c = (i2c_t *)dev->base; + + while((i2c->status.mst_activity) || !(i2c->status.tfe)) + { + /* Evaluate timeout */ + if(i2c_get_timer(start_time) > (rt_size_t)dev->dev.timeout * I2C_TX_FIFO_SIZE) + { + return -RT_ETIMEOUT; + } + } + + return RT_EOK; +} + +static int i2c_xfer_init(struct k230_i2c_dev *dev) +{ + volatile i2c_t *i2c = (i2c_t *)dev->base; + rt_uint8_t addr = 0; + + if(i2c_wait_for_bus_busy(dev) != RT_EOK) + { + return -RT_EBUSY; + } + + i2c_set_addr(dev); + + return RT_EOK; +} + +static int i2c_xfer_finish(struct k230_i2c_dev *dev) +{ + volatile i2c_t *i2c = (i2c_t *)dev->base; + rt_uint32_t start_stop_det = i2c_get_timer(0); + + while (1) + { + if(i2c->raw_intr_stat.stop_det) + { + readl(&i2c->clr_stop_det); + break; + } + + else if (i2c_get_timer(start_stop_det) > dev->dev.timeout) + { + break; + } + } + + if (i2c_wait_for_bus_busy(dev) != RT_EOK) + { + return -RT_EBUSY; + } + + i2c_flush_rxfifo(dev); + + return RT_EOK; +} + +static int _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(i2c_xfer_init(dev) != RT_EOK) + { + return -RT_EBUSY; + } + } + + start_time_rx = 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 = i2c_get_timer(0); + } + else if(i2c_get_timer(start_time_rx) > dev->dev.timeout) + { + return -RT_ETIMEOUT; + } + } + return i2c_xfer_finish(dev); +} + +static int _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 (i2c_xfer_init(dev) != RT_EOK) + { + return -RT_EBUSY; + } + + start_time_tx = 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 = i2c_get_timer(0); + } + else if(i2c_get_timer(start_time_tx) > dev->dev.timeout) + { + return -RT_ETIMEOUT; + } + } + + if (dev->msg->flags & RT_I2C_NO_STOP) + { + return RT_EOK; + } + + if (i2c_wait_for_bus_busy(dev) != RT_EOK) + { + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_ssize_t 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 = _i2c_read(i2c_dev); + } + else + { + ret = _i2c_write(i2c_dev); + } + if (ret != RT_EOK) + { + return -RT_EIO; + } + } + + return send_mesgs; +} + +static rt_err_t 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: + i2c_set_bus_timeout(i2c_dev, arg); + break; + + case RT_I2C_DEV_CTRL_CLK: + ret = i2c_set_bus_speed(i2c_dev, arg); + if (ret != RT_EOK) + { + return -RT_EIO; + } + break; + + default: break; + } + + return RT_EOK; +} + +#if defined(BSP_USING_I2C0_SLAVE) || defined(BSP_USING_I2C1_SLAVE) || \ + defined(BSP_USING_I2C2_SLAVE) || defined(BSP_USING_I2C3_SLAVE) || \ + defined(BSP_USING_I2C4_SLAVE) +struct i2c_slave_eeprom +{ + struct rt_device device; + volatile int poll_event; + rt_uint8_t* buffer; + rt_uint8_t ptr; + rt_bool_t flag_recv_ptr; +}; + +static rt_uint8_t eeprom_buffer[I2C_SLAVE_BUFFER_SIZE]; + +static struct i2c_slave_eeprom eeprom = +{ + .buffer = eeprom_buffer, +}; + +static int eeprom_open(struct dfs_file *file) +{ + file->vnode->size = I2C_SLAVE_BUFFER_SIZE; + file->flags &= ~O_APPEND; + + return RT_EOK; +} + +static int eeprom_close(struct dfs_file *file) +{ + return RT_EOK; +} + +static ssize_t eeprom_read(struct dfs_file *file, void *buffer, size_t size, off_t *pos) +{ + if (*pos >= file->vnode->size) + { + return 0; + } + size_t lack = file->vnode->size - *pos; + if (size > lack) + { + size = lack; + } + memcpy(buffer, eeprom_buffer + *pos, size); + *pos += size; + + return size; +} + +static ssize_t eeprom_write(struct dfs_file *file, const void *buffer, size_t size, off_t *pos) +{ + if (*pos >= file->vnode->size) + { + return 0; + } + size_t lack = file->vnode->size - *pos; + if (size > lack) + { + size = lack; + } + memcpy(eeprom_buffer + *pos, buffer, size); + *pos += size; + + return size; +} + +static off_t eeprom_lseek(struct dfs_file *file, off_t offset, int whence) +{ + (void)whence; + + if (offset < file->vnode->size) + { + return offset; + } + else + { + return -1; + } +} + +static int eeprom_poll(struct dfs_file *file, struct rt_pollreq *req) +{ + rt_device_t device = file->vnode->data; + int mask = eeprom.poll_event; + + rt_poll_add(&device->wait_queue, req); + eeprom.poll_event = 0; + + return mask; +} + +static const struct dfs_file_ops eeprom_fops = +{ + .open = eeprom_open, + .close = eeprom_close, + .read = eeprom_read, + .write = eeprom_write, + .poll = eeprom_poll, + .lseek = eeprom_lseek, +}; + +int i2c_slave_eeprom_init(void) { + int ret = 0; + rt_device_t device = &eeprom.device; + + ret = rt_device_register(device, "i2c-slv-eeprom", RT_DEVICE_FLAG_RDWR); + if (ret) + { + LOG_E("%s: rt_device_register error %d\n", __func__, ret); + return -RT_ERROR; + } + device->fops = &eeprom_fops; + device->user_data = device; + + return RT_EOK; +} +INIT_DEVICE_EXPORT(i2c_slave_eeprom_init); + +static void _i2c_slave_receive_addr(struct i2c_slave_eeprom *eeprom, rt_uint8_t *val) +{ + if(*val >= I2C_SLAVE_BUFFER_SIZE) + { + eeprom->ptr = 0; + } + else + { + eeprom->ptr = *val; + } + eeprom->flag_recv_ptr = RT_TRUE; +} + +static void _i2c_slave_write(struct i2c_slave_eeprom *eeprom, rt_uint8_t *val) +{ + if(eeprom->ptr >= I2C_SLAVE_BUFFER_SIZE) + { + eeprom->ptr = 0; + } + + eeprom->buffer[eeprom->ptr++] = *val; + if (!(eeprom->poll_event & POLLIN)) + { + eeprom->poll_event |= POLLIN; + } +} + +static void _i2c_slave_read_add_increment(struct i2c_slave_eeprom *eeprom, rt_uint8_t *val) +{ + (void)val; + + if(eeprom->ptr >= I2C_SLAVE_BUFFER_SIZE) + { + eeprom->ptr = 0; + + return; + } + eeprom->ptr++; +} + +static void _i2c_slave_read(struct i2c_slave_eeprom *eeprom, rt_uint8_t *val) +{ + *val = eeprom->buffer[eeprom->ptr]; +} + +static void i2c_slave_eeprom_callback(void *ctx, enum _i2c_slave_event event, rt_uint8_t *val) +{ + struct i2c_slave_eeprom *eeprom = ctx; + + switch (event) + { + case I2C_SLAVE_WRITE_RECEIVED: + if (eeprom->flag_recv_ptr) + { + // write data + _i2c_slave_write(eeprom, val); + } + else + { + // recv addr byte + _i2c_slave_receive_addr(eeprom, val); + } + break; + + case I2C_SLAVE_READ_PROCESSED: + /* The previous byte made it to the bus, get next one */ + _i2c_slave_read_add_increment(eeprom, val); + /* fall through */ + __attribute__((fallthrough)); + case I2C_SLAVE_READ_REQUESTED: + _i2c_slave_read(eeprom, val); + /* + * Do not increment buffer_idx here, because we don't know if + * this byte will be actually used. Read Linux I2C slave docs + * for details. + */ + break; + + case I2C_SLAVE_STOP: + if(eeprom->poll_event & POLLIN) + { + rt_wqueue_wakeup(&eeprom->device.wait_queue, (void*)POLLIN); + } + /* fall through */ + __attribute__((fallthrough)); + case I2C_SLAVE_WRITE_REQUESTED: + eeprom->ptr = 0; + eeprom->flag_recv_ptr = RT_FALSE; + break; + + default: + break; + } +} +#endif + +static rt_uint32_t i2c_slave_read_clear_intr(struct k230_i2c_dev *dev) +{ + volatile i2c_t *i2c = (i2c_t *)dev->base; + rt_uint32_t stat = readl(&i2c->intr_stat); + + if(i2c->intr_stat.r_tx_abrt) + { + LOG_E("tx abrt source: %08x\n", readl(&i2c->tx_abrt_source)); + } + readl(&i2c->clr_intr); + + return stat; +} + +static void i2c_slave_isr(int vector, void *param) { + struct k230_i2c_dev *dev = (struct k230_i2c_dev *)param; + volatile i2c_t *i2c = (i2c_t *)dev->base; + rt_uint32_t stat, tmp; + rt_uint8_t val = 0; + + if(!i2c->enable_status.en || !i2c->raw_intr_stat.activity) + { + return; + } + + stat = i2c_slave_read_clear_intr(dev); + i2c_ic_intr_stat_t intr_stat; + memcpy(&intr_stat, &stat, sizeof(stat)); + + if(intr_stat.r_rx_full) + { + if(!(dev->slave.status & I2C_SLAVE_STATUS_WRITE_IN_PROGRESS)) + { + dev->slave.status |= I2C_SLAVE_STATUS_WRITE_IN_PROGRESS; + dev->slave.status &= ~I2C_SLAVE_STATUS_READ_IN_PROGRESS; + dev->slave.callback(dev->slave.callback_ctx, I2C_SLAVE_WRITE_REQUESTED, &val); + } + + do + { + tmp = readl(&i2c->data_cmd); + if(tmp & I2C_DATA_CMD_FIRST_DATA_BYTE) + { + dev->slave.callback(dev->slave.callback_ctx, I2C_SLAVE_WRITE_REQUESTED, &val); + } + val = tmp; + dev->slave.callback(dev->slave.callback_ctx, I2C_SLAVE_WRITE_RECEIVED, &val); + } while(i2c->status.rfne); + } + + if(intr_stat.r_rd_req) + { + if(i2c->status.activity) + { + if(!(dev->slave.status & I2C_SLAVE_STATUS_READ_IN_PROGRESS)) + { + dev->slave.status |= I2C_SLAVE_STATUS_READ_IN_PROGRESS; + dev->slave.status &= ~I2C_SLAVE_STATUS_WRITE_IN_PROGRESS; + dev->slave.callback(dev->slave.callback_ctx, I2C_SLAVE_READ_REQUESTED, &val); + } + else + { + dev->slave.callback(dev->slave.callback_ctx, I2C_SLAVE_READ_PROCESSED, &val); + } + writel(val, &i2c->data_cmd); + } + } + + if(intr_stat.r_stop_det) + { + dev->slave.callback(dev->slave.callback_ctx, I2C_SLAVE_STOP, &val); + } +} + +static void i2c_slave_init(struct k230_i2c_dev *dev) { + volatile i2c_t *i2c = (i2c_t *)dev->base; + rt_uint8_t slave_address = dev->slave.address; + + i2c_enable(dev, RT_FALSE); + dev->slave.status &= ~I2C_SLAVE_STATUS_ACTIVE; + + if(dev->slave.callback == RT_NULL) + { + LOG_E("i2c device %s slave callback is NULL\n", dev->name); + return; + } + + dev->slave.status = 0; + writel(0, &i2c->con); + i2c->con.rx_fifo_full_hld_ctrl = 1; + i2c->con.restart_en = 1; + i2c->con.stop_det_ifaddressed = 1; + i2c->tx_tl.tl = I2C_TX_TL; + i2c->rx_tl.tl = I2C_RX_TL; + writel(0, &i2c->intr_mask); + i2c->intr_mask.m_rx_full = 1; + i2c->intr_mask.m_tx_abrt = 1; + i2c->intr_mask.m_stop_det = 1; + i2c->intr_mask.m_rx_under = 1; + i2c->intr_mask.m_rd_req = 1; + + + i2c->sar.sar = slave_address; + + rt_hw_interrupt_install(dev->vector, i2c_slave_isr, dev, dev->name); + + dev->slave.status |= I2C_SLAVE_STATUS_ACTIVE; + + i2c_enable(dev, RT_TRUE); + + rt_hw_interrupt_umask(dev->vector); +} + +static void i2c_master_init(struct k230_i2c_dev *dev) +{ + volatile i2c_t *i2c = (i2c_t *)dev->base; + + /* Disable i2c */ + 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 */ + i2c_enable(dev, RT_TRUE); +} + +static const struct rt_i2c_bus_device_ops i2c_ops = +{ + .master_xfer = i2c_xfer, + .i2c_bus_control = i2c_control, +}; + +static struct k230_i2c_dev i2c_devs[] = +{ +#ifdef BSP_USING_I2C0 + { + .name = "i2c0", + .base = I2C0_BASE_ADDR, + .size = I2C0_IO_SIZE, + .vector = K230_IRQ_I2C0, + #ifdef BSP_USING_I2C0_SLAVE + .slave = + { + .en = RT_TRUE, + .address = 0x50, + .callback_ctx = &eeprom, + .callback = i2c_slave_eeprom_callback, + } + #endif + }, +#endif +#ifdef BSP_USING_I2C1 + { + .name = "i2c1", + .base = I2C1_BASE_ADDR, + .size = I2C1_IO_SIZE, + .vector = K230_IRQ_I2C1, + #ifdef BSP_USING_I2C1_SLAVE + .slave = + { + .en = RT_TRUE, + .address = 0x51, + .callback_ctx = &eeprom, + .callback = i2c_slave_eeprom_callback, + } + #endif + }, +#endif +#ifdef BSP_USING_I2C2 + { + .name = "i2c2", + .base = I2C2_BASE_ADDR, + .size = I2C2_IO_SIZE, + .vector = K230_IRQ_I2C2, + #ifdef BSP_USING_I2C2_SLAVE + .slave = + { + .en = RT_TRUE, + .address = 0x52, + .callback_ctx = &eeprom, + .callback = i2c_slave_eeprom_callback, + } + #endif + }, +#endif +#ifdef BSP_USING_I2C3 + { + .name = "i2c3", + .base = I2C3_BASE_ADDR, + .size = I2C3_IO_SIZE, + .vector = K230_IRQ_I2C3, + #ifdef BSP_USING_I2C3_SLAVE + .slave = + { + .en = RT_TRUE, + .address = 0x53, + .callback_ctx = &eeprom, + .callback = i2c_slave_eeprom_callback, + } + #endif + }, +#endif +#ifdef BSP_USING_I2C4 + { + .name = "i2c4", + .base = I2C4_BASE_ADDR, + .size = I2C4_IO_SIZE, + .vector = K230_IRQ_I2C4, + #ifdef BSP_USING_I2C4_SLAVE + .slave = + { + .en = RT_TRUE, + .address = 0x54, + .callback_ctx = &eeprom, + .callback = i2c_slave_eeprom_callback, + } + #endif + }, +#endif +}; + +int rt_hw_i2c_init(void) +{ + int i; + + for (i = 0; i < sizeof(i2c_devs) / sizeof(i2c_devs[0]); i++) + { + i2c_devs[i].base = (rt_ubase_t)rt_ioremap((void *)i2c_devs[i].base, i2c_devs[i].size); + i2c_devs[i].dev.ops = &i2c_ops; + i2c_devs[i].clock = sysctl_clk_get_leaf_freq(SYSCTL_CLK_I2C0_CORE + i); + + LOG_I("i2c%d clock=%dHz\n", i, i2c_devs[i].clock); + + if(i2c_devs[i].slave.en) + { + i2c_slave_init(&i2c_devs[i]); + LOG_I("i2c%d slave address=0x%02x\n", i, i2c_devs[i].slave.address); + LOG_I("slave-eeprom size: %u", I2C_SLAVE_BUFFER_SIZE); + } + else + { + i2c_master_init(&i2c_devs[i]); + i2c_set_bus_timeout(&i2c_devs[i], I2C_DEFAULT_TIMEOUT); + i2c_set_bus_speed(&i2c_devs[i], I2C_DEFAULT_SPEED); + rt_i2c_bus_device_register(&i2c_devs[i].dev, i2c_devs[i].name); + LOG_I("i2c%d master mode\n", i); + } + } + + return RT_EOK; +} +INIT_DEVICE_EXPORT(rt_hw_i2c_init); diff --git a/bsp/k230/drivers/interdrv/i2c/drv_i2c.h b/bsp/k230/drivers/interdrv/i2c/drv_i2c.h new file mode 100644 index 00000000000..82eb4a6d096 --- /dev/null +++ b/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 + +#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__ */ diff --git a/bsp/k230/drivers/utest/SConscript b/bsp/k230/drivers/utest/SConscript index 1069520d736..a6fc1e57a8e 100644 --- a/bsp/k230/drivers/utest/SConscript +++ b/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') \ No newline at end of file diff --git a/bsp/k230/drivers/utest/test_i2c.c b/bsp/k230/drivers/utest/test_i2c.c new file mode 100644 index 00000000000..72abbd50d3b --- /dev/null +++ b/bsp/k230/drivers/utest/test_i2c.c @@ -0,0 +1,269 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#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。 + * 2. 测试I2C0从机模式 + * 从机模式下,等待主机发送数据,当接收到数据数据后,在i2c驱动 + * 中会唤醒队列,从而在该测试中会读取数据并打印出来。也可以在msh + * 使用echo与cat命令进行辅助测试。 + * 注:使用的主机为CH341T模块,I2C0从机地址为0x50。 + */ + +#define I2C_NAME "i2c0" +#define TARGET_ADDR 0x50 + +#define TEST_BUFFER_SIZE 16 + +#define FILE_PATH "/dev/i2c-slv-eeprom" + +#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."); + #ifdef BSP_USING_I2C0_MASTER + 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); + #else + rt_thread_mdelay(10); + #endif + } + + 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_slave(void) +{ + int fd = open(FILE_PATH, O_RDONLY); + if (fd < 0) + { + LOG_E("open %s failed", FILE_PATH); + uassert_true(0); + } + + int ret = 0, i; + rt_uint8_t buffer[TEST_BUFFER_SIZE]; + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; // wait read event + + while(1) + { + ret = poll(&pfd, 1, 5000); + + if (ret > 0) + { + if (pfd.revents & POLLIN) + { + int n = read(fd, buffer, TEST_BUFFER_SIZE); + LOG_I("slave buffer data: read %d bytes from %s\n", n, FILE_PATH); + for(i = 0; i < n; i++) + { + LOG_I("0x%02X ", buffer[i]); + } + break; + } + } + else if(ret < 0) + { + LOG_E("poll error"); + close(fd); + uassert_true(0); + } + else + { + LOG_W("poll timeout, retry..."); + } + } + close(fd); +} + +static void test_i2c0_master_slave(void) +{ +#ifdef BSP_USING_I2C0_MASTER + 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); +#else + _test_i2c0_slave(); +#endif +} + +static void testcase(void) +{ + LOG_I("This is a i2c test case.\n"); + UTEST_UNIT_RUN(test_i2c0_master_slave); +} + +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); diff --git a/bsp/k230/rtconfig.h b/bsp/k230/rtconfig.h index a1ba8e430e6..284e37acf06 100644 --- a/bsp/k230/rtconfig.h +++ b/bsp/k230/rtconfig.h @@ -213,6 +213,8 @@ #define RT_USING_CPUTIME #define RT_USING_CPUTIME_RISCV #define CPUTIME_TIMER_FREQ 25000000 +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM @@ -276,6 +278,7 @@ #define RT_USING_SAL #define SAL_INTERNET_CHECK +#define SOCKET_TABLE_STEP_LEN 4 /* Docking with protocol stacks */