• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# I3C
2
3## Introduction
4
5### Function
6
7Improved Inter-Integrated Circuit (I3C) is a simple and cost-efficient two-wire bidirectional synchronous serial bus protocol developed by the Mobile Industry Processor Interface (MIPI) Alliance.
8
9I3C is a two-wire bidirectional serial bus, optimized for multiple sensor target devices and controlled by only one I3C controller at a time.  It is backward compatible with Inter-Integrated circuit (I2C) target devices, but features higher speed and lower power consumption and supports in-band interrupts (IBIs), hot-joins of target devices, and controller switchover.
10
11The IBIs over the serial bus eliminates the need for an extra interrupt line to complete interrupts in I2C. I2C devices, I3C target devices, and the I3C secondary controller can co-exist on the same I3C bus.
12
13### Basic Concepts
14
15- IBI
16
17  When there is no start signal on the serial clock (SCL) line, the I3C target device can pull down the serial data (SDA) line to make the controller send an SCL start signal, which initiates an IBI request. If multiple target devices send interrupt requests at the same time, the I3C controller arbitrates the requests based on the target device addresses. The request with a lower address is responded first.
18
19- Dynamic Address Assignment (DAA)
20
21  The I3C controller can dynamically allocate addresses to target devices to avoid address conflicts. Before addresses are allocated, each I3C device connected to an I3C bus must be uniquely identified in either of the following ways:
22
23  - The device has an I2C compliant static address that can be used by the host.
24  - The device has a 48-bit temporary ID.
25
26  The host must use a 48-bit temporary ID unless the device has a static IP address.
27
28- Common Command Code (CCC)
29
30  All I3C devices support CCC. The CCC can be sent to an I3C target device or all I3C target devices.
31
32- Bus Characteristic Register (BCR)
33
34  Each I3C device connected to an I3C bus has a read-only BCR, which describes the I3C compliant device's role and capabilities for use in DAA and CCC.
35
36- Device Characteristic Register (DCR)
37
38  Each I3C device connected to an I3C bus has a read-only DCR, which describes the I3C compliant device type (such as accelerometers, gyroscope, and others) for use in DAA and DCC.
39
40
41### Working Principles
42
43In the Hardware Driver Foundation (HDF), the I3C module uses the unified service mode for API adaptation. In this mode, a service is used as the I3C manager to handle external access requests in a unified manner. The unified service mode applies when the system has multiple device objects of the same type, for example, when there are more than 10 I3C controllers. If the independent service mode is used in this case, more device nodes need to be configured and more memory resources will be consumed. The following figure illustrtes the unified service mode.
44
45The I3C module is divided into the following layers:
46
47- Interface layer: provides the capabilities of opening a device, writing data, and closing a device.
48- Core layer: binds services, initializes and releases the PlatformManager, and provides the capabilities of adding, deleting, and obtaining controllers. The core layer also provides capabilities of adding, deleting, and obtaining the devices connected to the I3C bus and interrupt callbacks.
49- Adaptation layer: implements hardware-related functions, such as controller initialization.
50
51In the unified service mode, the core layer manages all controllers in a unified manner and publishes a service for the interface layer. That is, the driver does not need to publish a service for each controller.
52
53 **Figure 1** Unified service mode
54
55![image1](figures/unified-service-mode.png)
56
57### Constraints
58
59The I3C module supports only the kernel (LiteOS-A) for mini and small systems.
60
61## Development Guidelines
62
63### When to Use
64
65I3C can connect to one or more I3C or I2C target devices. It is used to:
66
67- Communicate with sensors, such as gyroscopes, barometers, and image sensors that support the I3C protocol.
68- Communicate with devices with other ports (such as UART serial ports) through software or hardware protocols.
69
70Before using I3C devices with OpenHarmony, you need to adapt the I3C driver to OpenHarmony. The following describes how to do it.
71
72### Available APIs
73
74To enable the upper layer to successfully operate the hardware by calling the I3C APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/i3c/i3c_core.h** for the core layer. You need to implement these hook functions at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer.
75
76**I3cMethod**:
77```c
78struct I3cMethod {
79    int32_t (*sendCccCmd)(struct I3cCntlr *cntlr, struct I3cCccCmd *ccc);
80    int32_t (*transfer)(struct I3cCntlr *cntlr, struct I3cMsg *msgs, int16_t count);
81    int32_t (*i2cTransfer)(struct I3cCntlr *cntlr, struct I3cMsg *msgs, int16_t count);
82    int32_t (*setConfig)(struct I3cCntlr *cntlr, struct I3cConfig *config);
83    int32_t (*getConfig)(struct I3cCntlr *cntlr, struct I3cConfig *config);
84    int32_t (*requestIbi)(struct I3cDevice *dev);
85    void (*freeIbi)(struct I3cDevice *dev);
86};
87```
88
89**Table 1** Hook functions in **I3cMethod**
90|Function|Input Parameter|Output Parameter|Return Value|Description|
91|-|-|-|-|-|
92|sendCccCmd| **cntlr**: structure pointer to an I3C controller at the core layer.<br>**ccc**: pointer to the CCC to send.| **ccc**: pointer to the CCC sent.| HDF_STATUS|Sends a CCC.|
93|Transfer  | **cntlr**: structure pointer to an I3C controller at the core layer.<br>**msgs**: structure pointer to the messages to transfer.<br>**count**: number of messages to transfer, which is of the int16_t type.| **msgs**: structure pointer to the messages transferred.| HDF_STATUS| Transfers user messages in I3C mode.|
94|i2cTransfer | **cntlr**: structure pointer to an I3C controller at the core layer.<br>**msgs**: structure pointer to the messages to transfer.<br>**count**: number of messages to transfer, which is of the int16_t type.| **msgs**: structure pointer to the messages transferred.| HDF_STATUS| Transfers user messages in I2C mode.|
95|setConfig| **cntlr**: structure pointer to an I3C controller at the core layer.<br>**config**: pointer to the controller configuration.| –| HDF_STATUS| Sets an I3C controller.|
96|getConfig| **cntlr**: structure pointer to an I3C controller at the core layer.| **config**: pointer to the controller configuration.| HDF_STATUS| Obtains the I3C controller configuration.|
97|requestIbi| **device**: structure pointer to an I3C device at the core layer.| –| HDF_STATUS| Requests an IBI for an I3C device.|
98|freeIbi| **device**: structure pointer to an I3C device at the core layer.| –| HDF_STATUS| Releases the IBI for an I3C device.|
99
100### How to Develop
101
102The I3C module adaptation involves the following steps:
103
1041. Instantiate the driver entry.
105
106   - Instantiate the **HdfDriverEntry** structure.
107   - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
108
1092. Configure attribute files.
110
111   - Add the **deviceNode** information to the **device_info.hcs** file.
112   - (Optional) Add the **i3c_config.hcs** file.
113
1143. Instantiate the I3C controller object.
115
116   - Initialize **I3cCntlr**.
117   - Instantiate **I3cMethod** in **I3cCntlr**. For details, see the description of **I3cMethod** below.
118
1194. Register an interrupt handler.
120
121   Registers an interrupt handler for the controller to implement the device hot-join and IBI features.
122
123### Example
124
1251. Instantiate the driver entry.
126
127    The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **//drivers/hdf_core/framework/include/core/hdf_device_desc.h**), and the module name must be the same as that in **device_info.hcs**. In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke.
128
129    Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
130
131    I3C driver entry example:
132
133    > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
134    >
135    > Multiple devices may connect to the I3C controller. In the HDF, a manager object needs to be created for this type of devices, and a manager service is published to handle external access requests uniformly. When a device needs to be started, the manager service locates the target device based on the specified parameters.
136    >
137    > You do not need to implement the driver of the I3C manager, which is implemented by the core layer. However, the **I3cCntlrAdd** function of the core layer must be invoked in the **Init** function to implement the related features.
138
139    ```c
140    static struct HdfDriverEntry g_virtualI3cDriverEntry = {
141        .moduleVersion = 1,
142        .Init = VirtualI3cInit,
143        .Release = VirtualI3cRelease,
144        .moduleName = "virtual_i3c_driver",      // (Mandatory) The value must be the same as that in the .hcs file.
145    };
146    HDF_INIT(g_virtualI3cDriverEntry);           // Call HDF_INIT to register the driver entry with the HDF.
147
148    /* Driver entry of the i3c_core.c manager service at the core layer. */
149    struct HdfDriverEntry g_i3cManagerEntry = {
150        .moduleVersion = 1,
151        .Init     = I3cManagerInit,
152        .Release  = I3cManagerRelease,
153        .moduleName = "HDF_PLATFORM_I3C_MANAGER", // The value must be the same as that of device0 in the device_info.hcs file.
154    };
155    HDF_INIT(g_i3cManagerEntry);
156    ```
157
1582. Configure attribute files.
159
160    Add the **deviceNode** information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file and configure the device attributes in **i3c_config.hcs**.
161
162    The **deviceNode** information is related to the driver entry registration. The device attribute values are closely related to the driver implementation and the default values or value ranges of the **I3cCntlr** members at the core layer.
163
164    In the unified service mode, the first device node in the **device_info.hcs** file must be the I3C manager. The I3C manager parameters must be set as follows:
165
166    |Parameter|Value|
167    |-|-|
168    |moduleName |HDF_PLATFORM_I3C_MANAGER|
169    |serviceName|Reserved.|
170    |policy|0|
171    |cntlrMatchAttr| Reserved.|
172
173    Configure I3C controller information from the second node. This node specifies a type of I3C controllers rather than a specific I3C controller. In this example, there is only one I3C controller. If there are multiple I3C controllers, add the **deviceNode** information to the **device_info.hcs** file and add the corresponding device attributes to the **i3c_config** file for each controller.
174
175    - **device_info.hcs** example
176
177        ```c
178        root {
179            device_i3c :: device {
180                device0 :: deviceNode {
181                    policy = 0;
182                    priority = 52;
183                    permission = 0644;
184                    serviceName = "HDF_PLATFORM_I3C_MANAGER";
185                    moduleName = "HDF_PLATFORM_I3C_MANAGER";
186                }
187            }
188            i3c_virtual :: deviceNode {
189                policy = 0;                               // The value 0 indicates that no service is published.
190                priority = 56;                            // Driver startup priority.
191                permission = 0644;                        // Permission for the device node created.
192                moduleName = "virtual_i3c_driver";        // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
193                serviceName = "VIRTUAL_I3C_DRIVER";       // (Mandatory) Unique name of the service published by the driver.
194                deviceMatchAttr = "virtual_i3c"; // (Mandatory) Controller private data, which must be same as that of the controller in i3c_config.hcs.
195            }                                             // The specific controller information is in i3c_config.hcs.
196        }
197        ```
198
199    - i3c_config.hcs example
200
201        ```c
202        root {
203            platform {
204                i3c_config {
205                    match_attr = "virtual_i3c";  // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
206                    template i3c_controller {    // Template configuration. In the template, you can configure the common parameters shared by device nodes.
207                        busId = 0;               // (Mandatory) I3C bus number.
208                        busMode = 0x0;           // Bus mode, which can be 0x0 (pure), 0x1 (mixed-fast), 0x2 (mixed-limited), or 0x3 (mixed-slow).
209                        regBasePhy = 0x120b0000; // (Mandatory) Physical base address.
210                        regSize = 0xd1;          // (Mandatory) Register bit width.
211                        IrqNum = 20;             // (Mandatory) Interrupt request (IRQ) number.
212                        i3cMaxRate = 12900000;   // (Optional) Maximum clock rate in I3C mode.
213                        i3cRate = 12500000;      // (Optional) Clock rate in I3C mode.
214                        i2cFmRate = 1000000;     // (Optional) Clock rate in I2C FM mode.
215                        i2cFmPlusRate = 400000;  // (Optional) Clock rate in I2C FM+ mode.
216                    }
217                    controller_0 :: i3c_controller {
218                        busId = 18;
219                        IrqNum = 20;
220                    }
221                }
222            }
223        }
224        ```
225        After the **i3c_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
226
227         For example, if the path of **i3c_config.hcs** is **device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i3c/i3c_config.hcs**, add the following statement to **hdf.hcs** of the product:
228
229        ```c
230         #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i3c/i3c_config.hcs" // Relative path of the file.
231        ```
232
233
234
2353. Instantiate the I3C controller object.
236
237    Initialize the **I3cCntlr** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init**, and **Release**) to instantiate I3cMethod in I3cCntlr (so that the underlying driver functions can be called).
238
239    Instantiate **I3cMethod** in **I3cCntlr**.<br>The **I3cLockMethod** hook function structure is not implemented in this example. To instantiate the structure, refer to the I2C driver development. Other members are initialized in **Init()**.
240
241    - Define a custom structure.
242
243      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
244      >
245      > To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **i3c_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the device number and bus number, to the **I3cCntlr** object at the core layer.
246
247        ```c
248        struct VirtualI3cCntlr {
249            struct I3cCntlr cntlr;           // (Mandatory) Control object at the core layer. For details, see the following description.
250            volatile unsigned char *regBase; // (Mandatory) Register base address.
251            uint32_t regBasePhy              // (Mandatory) Physical base address of the register.
252            uint32_t regSize;                // (Mandatory) Register bit width.
253            uint16_t busId;                  // (Mandatory) Bus number.
254            uint16_t busMode;
255            uint16_t IrqNum;
256            uint32_t i3cMaxRate;
257            uint32_t i3cRate;
258            uint32_t i2cFmRate;
259            uint32_t i2cFmPlusRate;
260        };
261
262        /* I3cCntlr is the controller structure at the core layer. The Init function assigns values to the members of I3cCntlr. */
263        struct I3cCntlr {
264            OsalSpinlock lock;
265            void *owner;
266            int16_t busId;
267            struct I3cConfig config;
268            uint16_t addrSlot[(I3C_ADDR_MAX + 1) / ADDRS_PER_UINT16];
269            struct I3cIbiInfo *ibiSlot[I3C_IBI_MAX];
270            const struct I3cMethod *ops;
271            const struct I3cLockMethod *lockOps;
272            void *priv;
273        };
274        ```
275
276    - Implement the **Init** function.
277
278        **Input parameter**:
279
280        **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
281
282        **Return value**:
283
284        **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/framework/include/utils/hdf_base.h** file.
285
286
287        |Status|Description|
288        |:-|:-:|
289        |HDF_ERR_INVALID_OBJECT|Invalid controller object.|
290        |HDF_ERR_INVALID_PARAM |Invalid parameter.|
291        |HDF_ERR_MALLOC_FAIL   |Failed to allocate the memory.|
292        |HDF_ERR_IO            |I/O error.|
293        |HDF_SUCCESS           |Transmission successful.|
294        |HDF_FAILURE           |Transmission failed.|
295
296        **Function description**:
297
298        Initializes the custom structure object and **I3cCntlr**, and calls the **I3cCntlrAdd** function to add the I3C controller to the core layer.
299
300         ```c
301         static int32_t VirtualI3cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
302         {
303             int32_t ret;
304             struct VirtualI3cCntlr *virtual = NULL;                               // (Mandatory) Custom structure object.
305             (void)device;
306
307             virtual = (struct VirtualI3cCntlr *)OsalMemCalloc(sizeof(*virtual)); // (Mandatory) Allocate memory.
308             if (virtual == NULL) {
309                 HDF_LOGE("%s: Malloc virtual fail!", __func__);
310                 return HDF_ERR_MALLOC_FAIL;
311             }
312
313             ret = VirtualI3cReadDrs(virtual, node);     // (Mandatory) Use the default values in the i3c_config file to fill in the structure. For details about the function definition, see the following.
314             if (ret != HDF_SUCCESS) {
315                 HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
316                 goto __ERR__;
317             }
318             ...
319             virtual->regBase = OsalIoRemap(virtual->regBasePhy, virtual->regSize);// (Mandatory) Address mapping.
320             ret = OsalRegisterIrq(hi35xx->softIrqNum, OSAL_IRQF_TRIGGER_NONE, I3cIbiHandle, "I3C", virtual); // (Mandatory) Register an interrupt handler.
321             if (ret != HDF_SUCCESS) {
322                 HDF_LOGE("%s: register irq failed!", __func__);
323                 return ret;
324             }
325             ...
326             VirtualI3cCntlrInit(virtual);              // (Mandatory) Initialize the I3C device.
327             virtual->cntlr.priv = (void *)node;        // (Mandatory) Set the storage device attributes.
328             virtual->cntlr.busId = virtual->busId;     // (Mandatory) Initialize I3cCntlr.
329             virtual->cntlr.ops = &g_method;            // (Mandatory) Attach the I3cMethod instance.
330             (void)OsalSpinInit(&virtual->spin);
331             ret = I3cCntlrAdd(&virtual->cntlr);        // (Mandatory) Call this function to add the controller to the core layer. The driver can access the platform core layer only when a success signal is returned.
332             if (ret != HDF_SUCCESS) {
333                 HDF_LOGE("%s: add i3c controller failed! ret = %d", __func__, ret);
334                 (void)OsalSpinDestroy(&virtual->spin);
335                 goto __ERR__;
336             }
337
338             return HDF_SUCCESS;
339         __ERR__:                                       // If the controller fails to be added, deinitialize related functions.
340             if (virtual != NULL) {
341                 OsalMemFree(virtual);
342                 virtual = NULL;
343             }
344
345             return ret;
346         }
347
348         static int32_t VirtualI3cInit(struct HdfDeviceObject *device)
349         {
350             int32_t ret;
351             const struct DeviceResourceNode *childNode = NULL;
352
353             if (device == NULL || device->property == NULL) {
354                 HDF_LOGE("%s: device or property is NULL", __func__);
355                 return HDF_ERR_INVALID_OBJECT;
356             }
357
358             DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
359                 ret = VirtualI3cParseAndInit(device, childNode);
360                 if (ret != HDF_SUCCESS) {
361                     break;
362                 }
363             }
364
365             return ret;
366         }
367
368         static int32_t VirtualI3cReadDrs(struct VirtualI3cCntlr *virtual, const struct DeviceResourceNode *node)
369         {
370             struct DeviceResourceIface *drsOps = NULL;
371
372             /* Obtain the drsOps method. */
373             drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
374             if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL) {
375                 HDF_LOGE("%s: Invalid drs ops fail!", __func__);
376                 return HDF_FAILURE;
377             }
378             /* Read the configuration parameters in sequence and fill them in the structure. */
379             if (drsOps->GetUint16(node, "busId", &virtual->busId, 0) != HDF_SUCCESS) {
380                 HDF_LOGE("%s: Read busId fail!", __func__);
381                 return HDF_ERR_IO;
382             }
383             if (drsOps->GetUint16(node, "busMode", &virtual->busMode, 0) != HDF_SUCCESS) {
384                 HDF_LOGE("%s: Read busMode fail!", __func__);
385                 return HDF_ERR_IO;
386             }
387             if (drsOps->GetUint16(node, "IrqNum", &virtual->IrqNum, 0) != HDF_SUCCESS) {
388                 HDF_LOGE("%s: Read IrqNum fail!", __func__);
389                 return HDF_ERR_IO;
390             }
391             ···
392             return HDF_SUCCESS;
393         }
394         ```
395
396    - Implement the **Release** function.
397
398        **Input parameter**:
399
400        **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
401
402        **Return value**:
403
404        No value is returned.
405
406        **Function description**:
407
408        Releases the memory and deletes the controller. This function assigns values to the **Release** function in the driver entry structure. If the HDF fails to call the **Init** function to initialize the driver, the **Release** function can be called to release driver resources.
409
410        > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
411        >
412        > All forced conversion operations for obtaining the corresponding object can be successful only when the **Init** function has the value assignment operations.
413
414        ```c
415        static void VirtualI3cRemoveByNode(const struct DeviceResourceNode *node)
416        {
417            int32_t ret;
418            int16_t busId;
419            struct I3cCntlr *cntlr = NULL;
420            struct VirtualI3cCntlr *virtual = NULL;
421            struct DeviceResourceIface *drsOps = NULL;
422
423            drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
424            if (drsOps == NULL || drsOps->GetUint32 == NULL) {
425                HDF_LOGE("%s: invalid drs ops fail!", __func__);
426                return;
427            }
428
429            ret = drsOps->GetUint16(node, "busId", (uint16_t *)&busId, 0);
430            if (ret != HDF_SUCCESS) {
431                HDF_LOGE("%s: read busId fail!", __func__);
432                return;
433            }
434        ...
435        /* Call I3cCntlrGet() to obtain the I3cCntlr object based on the cntlrNum of the device, and then call I3cCntlrRemove() to release the I3cCntlr object. */
436            cntlr = I3cCntlrGet(busId);
437            if (cntlr != NULL && cntlr->priv == node) {
438                I3cCntlrPut(cntlr);
439                I3cCntlrRemove(cntlr);                    // (Mandatory) Remove the I3cCntlr object from the manager driver.
440                virtual = (struct VirtualI3cCntlr *)cntlr; // (Mandatory) Obtain the custom object through a forced conversion and perform the release operation.
441                (void)OsalSpinDestroy(&virtual->spin);
442                OsalMemFree(virtual);
443            }
444            return;
445        }
446
447        static void VirtualI3cRelease(struct HdfDeviceObject *device)
448        {
449            const struct DeviceResourceNode *childNode = NULL;
450
451            HDF_LOGI("%s: enter", __func__);
452
453            if (device == NULL || device->property == NULL) {
454                HDF_LOGE("%s: device or property is NULL", __func__);
455                return;
456            }
457        ...
458        /* Traverse and parse all nodes in i3c_config.hcs and perform the release operation on each node. */
459            DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
460                VirtualI3cRemoveByNode(childNode);  // See the description of VirtualI3cRemoveByNode for more details.
461            }
462        }
463        ```
464
4654. Register an interrupt handler.
466
467    The interrupt handler performs an IBI or hot-join based on the address where the interrupt is generated.
468
469    ```c
470    static int32_t VirtualI3cReservedAddrWorker(struct VirtualI3cCntlr *virtual, uint16_t addr)
471    {
472        (void)virtual;
473        switch (addr) {
474            case I3C_HOT_JOIN_ADDR:
475                 VirtualI3cHotJoin(virtual);
476                break;
477            case I3C_RESERVED_ADDR_7H3E:
478            case I3C_RESERVED_ADDR_7H5E:
479            case I3C_RESERVED_ADDR_7H6E:
480            case I3C_RESERVED_ADDR_7H76:
481            case I3C_RESERVED_ADDR_7H7A:
482            case I3C_RESERVED_ADDR_7H7C:
483            case I3C_RESERVED_ADDR_7H7F:
484            /* All single-bit errors in the broadcast address */
485            HDF_LOGW("%s: broadcast Address single bit error!", __func__);
486                break;
487            default:
488                HDF_LOGD("%s: Reserved address which is not supported!", __func__);
489                break;
490        }
491
492        return HDF_SUCCESS;
493    }
494
495    static int32_t I3cIbiHandle(uint32_t irq, void *data)
496    {
497        struct VirtualI3cCntlr *virtual = NULL;
498        struct I3cDevice *device = NULL;
499        uint16_t ibiAddr;
500        char *testStr = "Hello I3C!";
501
502        (void)irq;
503        if (data == NULL) {
504            HDF_LOGW("%s: data is NULL!", __func__);
505            return HDF_ERR_INVALID_PARAM;
506        }
507        virtual = (struct VirtualI3cCntlr *)data;
508        /* (Mandatory) Obtain the address where the interrupt is generated. Use the CHECK_RESERVED_ADDR macro to determine whether the address is an I3C address. */
509        ibiAddr = VirtualI3cGetIbiAddr();
510        if (CHECK_RESERVED_ADDR(ibiAddr) == I3C_ADDR_RESERVED) {
511            HDF_LOGD("%s: Calling VirtualI3cResAddrWorker...", __func__);
512            return VirtualI3cReservedAddrWorker(virtual, ibiAddr);
513        } else {
514            HDF_LOGD("%s: Calling I3cCntlrIbiCallback...", __func__);
515            device = GetDeviceByAddr(&virtual->cntlr, ibiAddr);
516            if (device == NULL) {
517                HDF_LOGE("func:%s device is NULL!",__func__);
518                return HDF_ERR_MALLOC_FAIL;
519            }
520            if (device->ibi->payload > VIRTUAL_I3C_TEST_STR_LEN) {
521                /* Place the string "Hello I3C!" into the IBI buffer. */
522                *device->ibi->data = *testStr;
523            }
524            /* Invoke the IBI callback based on the I3C device that generates the IBI. */
525            return I3cCntlrIbiCallback(device);
526        }
527
528        return HDF_SUCCESS;
529    }
530    ```
531