Skip to content

Commit

Permalink
WIP: driver: i3c: add it51xxx i3cm driver
Browse files Browse the repository at this point in the history
**DO NOT FORGET TO RUN CLANG-FORMAT**

Build:
west build -p always -b it513xx_evb samples/hello_world/ \
-DCONFIG_I3C=y -DCONFIG_I3C_SHELL=y -DCONFIG_I3C_USE_IBI=y -DCONFIG_LOG=y

Test plan:
- i3c shell
- controller role
  - ccc command
    [Pass] (B)RSTDAA: $i3c ccc rstdaa i3c@f03c00
    [Pass] (B)ENTDAA: $i3c ccc entdaa i3c@f03c00
    [Pass] (D)GETPID: $i3c ccc getpid i3c@f03c00 i3c_dummy@2f000005fa00010002
    [Pass] (D)GETBCR: $i3c ccc getbcr i3c@f03c00 i3c_dummy@2f000005fa00010002
    [Pass] (D)GETDCR: $i3c ccc getdcr i3c@f03c00 i3c_dummy@2f000005fa00010002
    [Pass] (D)SETMWL:
                 $i3c ccc setmwl i3c@f03c00 i3c_dummy@2f000005fa00010002 BB
                 $devmem 0xf03d6a 8
                 $devmem 0xf03d6b 8
    [Pass] (D)GETMWL: $i3c ccc getmwl i3c@f03c00 i3c_dummy@2f000005fa00010002
    [Pass] direct read ccc with repeated start flag
    [Pass] direct write ccc with repeated start flag
  - (dynamic address) ENTDAA/SETAASA/SETDASA
    [Pass] ENTDAA(1-I3CM to 1-I3CS / 1-I3CM to 2-I3CS)
           $i3c ccc entdaa i3c@f03c00
           // check i3cs0 dynamic address
           $devmem 0xf03d64 8
           // check i3cs1 dynamic address
           $devmem 0xf03de4 8
    [Pass] SETDASA
           $i3c ccc rstdaa i3c@f03c00
           $i3c ccc setdasa i3c@f03c00 i3c_dummy@18000005fa00010001 0x18
           $i3c ccc setdasa i3c@f03c00 i3c_dummy@19000005fa00010002 0x19
           $i3c ccc getpid i3c@f03c00 i3c_dummy@18000005fa00010001
           $i3c ccc getpid i3c@f03c00 i3c_dummy@19000005fa00010002
    [Pass] SETAASA(note: need to enable the "supports-setaasa" property)
           $i3c ccc rstdaa i3c@f03c00
           $i3c ccc setaasa i3c@f03c00
           $i3c info i3c@f03c00
           $i3c ccc getpid i3c@f03c00 i3c_dummy@18000005fa00010001
           $i3c ccc getpid i3c@f03c00 i3c_dummy@19000005fa00010002
  - [Pass] (ibi) hot-join
    $i3c ccc rstdaa i3c@f03c00
    // generate i3cs0 hj event
    $devmem 0xf03d0c 8 0x03
    $i3c ccc getpid i3c@f03c00 i3c_dummy@18000005fa00010001
    $i3c ccc getpid i3c@f03c00 i3c_dummy@19000005fa00010002
  - [GG] (ibi) target interrupt
  - [Unsupported??](ibi) secondary controller request
    Check the PR: zephyrproject-rtos#78361
  - private transfer(with/without 7Eh address)
    [pending] (with 7Eh, start flag)
    [pending] (with 7Eh, repeated start flag)
    [pending] (without 7Eh, start flag)
    [pending] (without 7Eh, repeated start flag)
  - legacy i2c private transfer

Question:
- exit hdr pattern is sent if no target responses 7Eh address
- how to ack dynamic address assignment(I3CM15'b[1])
- what is i3cm ccc with defining byte(I3CM15'b[0] and I3CM16)
- timing control
- secondary controller, IBI controller request are supported??

Note:
- MIPI I3C v1.0 not support direct ccc with data byte(defining byte), therefore,
  > RSTACT(9Ah): unsupported
  > GETCAPS(95h), GETSTATUS(90h): only support format 1
  > GETMXDS(94h): only support format 1 and 2

Change-Id: I7cb70eccf17faf4360d70ba5833bd31a00b5343e
Signed-off-by: Ren Chen <[email protected]>
  • Loading branch information
Chenhongren committed Dec 2, 2024
1 parent 8fd693d commit 0518c55
Show file tree
Hide file tree
Showing 14 changed files with 1,704 additions and 1 deletion.
45 changes: 45 additions & 0 deletions boards/ite/it513xx_evb/it513xx_evb.dts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,48 @@
};
};
};

&i3c0 {
status = "okay";
/* TODO: FIXME */
pinctrl-0 = <&i3c0_clk_gpj3_default
&i3c0_data_gpj4_default>;
pinctrl-names = "default";

i3c_dummy_1: i3c_dummy@19000005fa00010002 {
compatible = "i3c-dummy-device";
reg = <0x19 0x05fa 0x00010002>;
supports-setaasa;
status = "okay";
};
i3c_dummy_2: i3c_dummy@18000005fa00010001 {
compatible = "i3c-dummy-device";
reg = <0x18 0x05fa 0x00010001>;
supports-setaasa;
status = "okay";
};
};

&i3c1 {
status = "disabled";
pinctrl-0 = <
&i3c1_clk_gpj5_default
&i3c1_data_gpe1_default>;
pinctrl-names = "default";
};

&i3c2 {
status = "okay";
pinctrl-0 = <
&i3c1_clk_gpj5_default
&i3c1_data_gpe1_default>;
pinctrl-names = "default";
};

&i3c3 {
status = "okay";
pinctrl-0 = <
&i3c2_clk_gpe2_default
&i3c2_data_gpe3_default>;
pinctrl-names = "default";
};
15 changes: 15 additions & 0 deletions drivers/i3c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ zephyr_library_sources_ifdef(
i3c_npcx.c
)

zephyr_library_sources_ifdef(
CONFIG_I3C_IT51XXX
i3c_it51xxx.c
)

zephyr_library_sources_ifdef(
CONFIG_I3C_IT51XXX_TARGET
i3c_it51xxx_target.c
)

zephyr_library_sources_ifdef(
CONFIG_I3C_DUMMY_DEVICE
i3c_dummy_device.c
)

zephyr_library_sources_ifdef(
CONFIG_I3C_TEST
i3c_test.c
Expand Down
5 changes: 5 additions & 0 deletions drivers/i3c/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ config I3C_USE_GROUP_ADDR

Says Y if unsure.

config I3C_DUMMY_DEVICE
bool "I3C dummy device driver"
default y

menuconfig I3C_USE_IBI
bool "Use In-Band Interrupt (IBI)"
default y
Expand Down Expand Up @@ -118,5 +122,6 @@ rsource "Kconfig.nxp"
rsource "Kconfig.cdns"
rsource "Kconfig.npcx"
rsource "Kconfig.test"
rsource "Kconfig.it51xxx"

endif # I3C
35 changes: 35 additions & 0 deletions drivers/i3c/Kconfig.it51xxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright (c) 2025 ITE Corporation.
# SPDX-License-Identifier: Apache-2.0

DT_COMPAT_ITE_IT51XXX_I3C := ite,it51xxx-i3cm

module = I3C_IT51XXX
module-str = i3c-it51xxx
source "subsys/logging/Kconfig.template.log_config"

config I3C_IT51XXX
bool "IT51XXX I3CM driver"
depends on DT_HAS_ITE_IT51XXX_I3CM_ENABLED
select PINCTRL
select I3C_IBI_WORKQUEUE if I3C_USE_IBI
select SOC_IT51XXX_CPU_IDLE_GATING
default y
help
Enable it51xxx i3cm driver.

config I3C_IT51XXX_DLM_SIZE
int "IT51XXX I3CM DLM data size"
depends on I3C_IT51XXX
default 1024
help
Set i3cm data-local-memory(DLM) size.

config I3C_IT51XXX_TARGET
bool "IT51XXX I3CS driver"
depends on DT_HAS_ITE_IT51XXX_I3CS_ENABLED
select PINCTRL
select I3C_IBI_WORKQUEUE if I3C_USE_IBI
select SOC_IT51XXX_CPU_IDLE_GATING
default y
help
Enable it51xxx i3cs driver.
96 changes: 96 additions & 0 deletions drivers/i3c/i3c_dummy_device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2025 ITE Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT i3c_dummy_device

#include <zephyr/sys/util.h>
#include <zephyr/device.h>
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <zephyr/sys/sys_io.h>
#include <zephyr/sys/util.h>
#include <zephyr/drivers/i3c.h>

#include <zephyr/logging/log.h>
#define LOG_MODULE_NAME i3c_dummy_device
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);

#define IBI_MDB_GROUP GENMASK(7, 5)
#define IBI_MDB_GROUP_PENDING_READ_NOTI 5
#define IBI_MDB_SPEC_ID GENMASK(4, 0)

#define MAX_READ_DATA_LEN 64

struct i3c_dummy_device_config {
const struct device *bus;
const uint64_t pid;
};

struct i3c_dummy_device_data {
struct i3c_device_desc *desc;
struct k_work work;
uint8_t buf[MAX_READ_DATA_LEN];
};

static void i3c_dummy_device_work(struct k_work *work)
{
struct i3c_dummy_device_data *data = CONTAINER_OF(work, struct i3c_dummy_device_data, work);
struct i3c_msg msg;

msg.buf = data->buf;
msg.len = MAX_READ_DATA_LEN;
msg.flags = I3C_MSG_READ | I3C_MSG_STOP;
i3c_transfer(data->desc, &msg, 1);
LOG_HEXDUMP_INF(msg.buf, msg.len, "Pending read data:");
}

static int i3c_dummy_device_ibi_cb(struct i3c_device_desc *target, struct i3c_ibi_payload *payload)
{
const struct device *dev = target->dev;
struct i3c_dummy_device_data *data = dev->data;

if (payload->payload_len) {
LOG_HEXDUMP_INF(payload->payload, payload->payload_len, "IBI payload:");

if (FIELD_GET(IBI_MDB_GROUP, payload->payload[0]) ==
IBI_MDB_GROUP_PENDING_READ_NOTI) {
k_work_submit(&data->work);
}
}

return 0;
}

static int i3c_dummy_device_init(const struct device *dev)
{
const struct i3c_dummy_device_config *config = dev->config;
struct i3c_dummy_device_data *data = dev->data;
uint64_t pid = config->pid;
const struct i3c_device_id i3c_id = I3C_DEVICE_ID(pid);

LOG_INF("%s (%012llx) belongs to bus %s", dev->name, config->pid, config->bus->name);

data->desc = i3c_device_find(config->bus, &i3c_id);
i3c_ibi_enable(data->desc);

data->desc->ibi_cb = i3c_dummy_device_ibi_cb;
k_work_init(&data->work, i3c_dummy_device_work);

return 0;
}

#define I3C_DUMMY_DEVICE_INIT(n) \
static const struct i3c_dummy_device_config i3c_dummy_device_config_##n = { \
.bus = DEVICE_DT_GET(DT_INST_BUS(n)), \
.pid = ((uint64_t)DT_PROP_BY_IDX(DT_DRV_INST(n), reg, 1) << 32) | \
DT_PROP_BY_IDX(DT_DRV_INST(n), reg, 2), \
}; \
\
static struct i3c_dummy_device_data i3c_dummy_device_data_##n; \
DEVICE_DT_INST_DEFINE(n, i3c_dummy_device_init, NULL, &i3c_dummy_device_data_##n, \
&i3c_dummy_device_config_##n, POST_KERNEL, 51, NULL);

DT_INST_FOREACH_STATUS_OKAY(I3C_DUMMY_DEVICE_INIT)
Loading

0 comments on commit 0518c55

Please sign in to comment.