1
+/*
2
+ * QEMU I3C bus interface.
3
+ *
4
+ * Copyright 2025 Google LLC
5
+ *
6
+ * SPDX-License-Identifier: GPL-2.0-or-later
7
+ */
8
+
9
+#include "qemu/osdep.h"
10
+#include "qemu/log.h"
11
+#include "qapi/error.h"
12
+#include "trace.h"
13
+#include "hw/i3c/i3c.h"
14
+#include "hw/core/qdev-properties.h"
15
+
16
+/*
17
+ * In test mode (enabled by ENTTM CCC) we're supposed to send a random PID
18
+ * during ENTDAA, so we'll just send "QEMU".
19
+ */
20
+#define TEST_MODE_PROVISIONED_ID 0x0000554d4551ULL
21
+
22
+static const Property i3c_props[] = {
23
+ DEFINE_PROP_UINT8("static-address", struct I3CTarget, static_address, 0),
24
+ DEFINE_PROP_UINT8("dcr", struct I3CTarget, dcr, 0),
25
+ DEFINE_PROP_UINT8("bcr", struct I3CTarget, bcr, 0),
26
+ DEFINE_PROP_UINT64("pid", struct I3CTarget, pid, 0),
27
+};
28
+
29
+I3CBus *i3c_init_bus(DeviceState *parent, const char *name)
30
+{
31
+ return i3c_init_bus_type(TYPE_I3C_BUS, parent, name);
32
+}
33
+
34
+I3CBus *i3c_init_bus_type(const char *type, DeviceState *parent,
35
+ const char *name)
36
+{
37
+ I3CBus *bus;
38
+
39
+ bus = I3C_BUS(qbus_new(type, parent, name));
40
+ QLIST_INIT(&bus->current_devs);
41
+ bus->broadcast = false;
42
+ bus->in_entdaa = false;
43
+ bus->in_ccc = false;
44
+
45
+ /* I2C init. */
46
+ g_autofree gchar *i2c_bus_name = g_strdup_printf("%s-legacy-i2c", name);
47
+ bus->i2c_bus = i2c_init_bus(parent, i2c_bus_name);
48
+
49
+ return bus;
50
+}
51
+
52
+bool i3c_bus_busy(I3CBus *bus)
53
+{
54
+ return !QLIST_EMPTY(&bus->current_devs);
55
+}
56
+
57
+static bool i3c_target_match(I3CTarget *candidate, uint8_t address,
58
+ bool is_recv, bool broadcast, bool in_entdaa)
59
+{
60
+ /* Once a target has a dynamic address, it only responds to that. */
61
+ uint8_t targ_addr = candidate->address ? candidate->address :
62
+ candidate->static_address;
63
+
64
+ if (in_entdaa) {
65
+ if (address != I3C_BROADCAST) {
66
+ g_autofree char *path =
67
+ object_get_canonical_path(OBJECT(candidate));
68
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: I3C Address 0x%.2x sent during "
69
+ "ENTDAA instead of a broadcast address\n",
70
+ path, address);
71
+ return false;
72
+ }
73
+
74
+ /*
75
+ * Targets should only ACK ENTDAA broadcasts if they have no dynamic
76
+ * address.
77
+ */
78
+ return candidate->address == 0;
79
+ }
80
+
81
+ /* Return if our addresses match, or if it's a broadcast. */
82
+ return targ_addr == address || broadcast;
83
+}
84
+
85
+bool i3c_target_match_and_add(I3CBus *bus, I3CTarget *target, uint8_t address,
86
+ enum I3CEvent event)
87
+{
88
+ I3CTargetClass *tc = I3C_TARGET_GET_CLASS(target);
89
+ bool matched = tc->target_match(target, address, event == I3C_START_RECV,
90
+ bus->broadcast, bus->in_entdaa);
91
+
92
+ if (matched) {
93
+ I3CNode *node = g_new(struct I3CNode, 1);
94
+ node->target = target;
95
+ QLIST_INSERT_HEAD(&bus->current_devs, node, next);
96
+ }
97
+ return matched;
98
+}
99
+
100
+bool i3c_scan_bus(I3CBus *bus, uint8_t address, enum I3CEvent event)
101
+{
102
+ BusChild *child;
103
+ I3CNode *node, *next;
104
+
105
+ /* Clear out any devices from a previous (re-)START. */
106
+ QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
107
+ QLIST_REMOVE(node, next);
108
+ g_free(node);
109
+ }
110
+
111
+ QTAILQ_FOREACH(child, &bus->parent_obj.children, sibling) {
112
+ DeviceState *qdev = child->child;
113
+ I3CTarget *target = I3C_TARGET(qdev);
114
+
115
+ if (i3c_target_match_and_add(bus, target, address, event)) {
116
+ return true;
117
+ }
118
+ }
119
+
120
+ /* No one on the bus could respond. */
121
+ return false;
122
+}
123
+
124
+/* Class-level event handling, since we do some CCCs at the class level. */
125
+static int i3c_target_event(I3CTarget *t, enum I3CEvent event)
126
+{
127
+ I3CTargetClass *tc = I3C_TARGET_GET_CLASS(t);
128
+ trace_i3c_target_event(t->address, event);
129
+
130
+ if (event == I3C_STOP) {
131
+ t->curr_ccc = 0;
132
+ t->ccc_byte_offset = 0;
133
+ t->in_ccc = false;
134
+ }
135
+ return tc->event(t, event);
136
+}
137
+
138
+/*
139
+ * Sends a START or repeated START and the address for an I3C transaction.
140
+ *
141
+ * This function returns 0 if a device on the bus was able to respond to the
142
+ * address, and non-zero otherwise.
143
+ * A non-zero return represents a NACK.
144
+ */
145
+static int i3c_do_start_transfer(I3CBus *bus, uint8_t address,
146
+ enum I3CEvent event)
147
+{
148
+ I3CTargetClass *tc;
149
+ I3CNode *node;
150
+
151
+ if (address == I3C_BROADCAST) {
152
+ bus->broadcast = true;
153
+ /* If we're not in ENTDAA, a broadcast is the start of a new CCC. */
154
+ if (!bus->in_entdaa) {
155
+ bus->in_ccc = false;
156
+ }
157
+ } else {
158
+ bus->broadcast = false;
159
+ }
160
+
161
+ /* No one responded to the address, NACK it. */
162
+ if (!i3c_scan_bus(bus, address, event)) {
163
+ return -1;
164
+ }
165
+
166
+ QLIST_FOREACH(node, &bus->current_devs, next) {
167
+ I3CTarget *t = node->target;
168
+
169
+ tc = I3C_TARGET_GET_CLASS(t);
170
+ if (tc->event) {
171
+ int rv = i3c_target_event(t, event);
172
+ if (rv && !bus->broadcast) {
173
+ return rv;
174
+ }
175
+ }
176
+ }
177
+
178
+ return 0;
179
+}
180
+
181
+int i3c_start_transfer(I3CBus *bus, uint8_t address, bool is_recv)
182
+{
183
+ trace_i3c_start_transfer(address, is_recv);
184
+ return i3c_do_start_transfer(bus, address, is_recv
185
+ ? I3C_START_RECV
186
+ : I3C_START_SEND);
187
+}
188
+
189
+int i3c_start_recv(I3CBus *bus, uint8_t address)
190
+{
191
+ trace_i3c_start_transfer(address, true);
192
+ return i3c_do_start_transfer(bus, address, I3C_START_RECV);
193
+}
194
+
195
+int i3c_start_send(I3CBus *bus, uint8_t address)
196
+{
197
+ trace_i3c_start_transfer(address, false);
198
+ return i3c_do_start_transfer(bus, address, I3C_START_SEND);
199
+}
200
+
201
+void i3c_end_transfer(I3CBus *bus)
202
+{
203
+ I3CTargetClass *tc;
204
+ I3CNode *node, *next;
205
+
206
+ trace_i3c_end_transfer();
207
+
208
+ /*
209
+ * If we're in ENTDAA, we need to notify all devices when ENTDAA is done.
210
+ * This is because everyone initially participates due to the broadcast,
211
+ * but gradually drops out as they get assigned addresses.
212
+ * Since the current_devs list only stores who's currently participating,
213
+ * and not everyone who previously participated, we send the STOP to all
214
+ * children.
215
+ */
216
+ if (bus->in_entdaa) {
217
+ BusChild *child;
218
+
219
+ QTAILQ_FOREACH(child, &bus->parent_obj.children, sibling) {
220
+ DeviceState *qdev = child->child;
221
+ I3CTarget *t = I3C_TARGET(qdev);
222
+ tc = I3C_TARGET_GET_CLASS(t);
223
+ if (tc->event) {
224
+ i3c_target_event(t, I3C_STOP);
225
+ }
226
+ }
227
+ } else {
228
+ QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
229
+ I3CTarget *t = node->target;
230
+ tc = I3C_TARGET_GET_CLASS(t);
231
+ if (tc->event) {
232
+ i3c_target_event(t, I3C_STOP);
233
+ }
234
+ QLIST_REMOVE(node, next);
235
+ g_free(node);
236
+ }
237
+ }
238
+ bus->broadcast = false;
239
+ bus->in_entdaa = false;
240
+ bus->in_ccc = false;
241
+}
242
+
243
+/*
244
+ * Any CCCs that are universal across all I3C devices should be handled here.
245
+ * Once they're handled, we pass the CCC up to the I3C target to do anything
246
+ * else it may want with the bytes.
247
+ */
248
+static int i3c_target_handle_ccc_write(I3CTarget *t, const uint8_t *data,
249
+ uint32_t num_to_send, uint32_t *num_sent)
250
+{
251
+ I3CTargetClass *tc = I3C_TARGET_GET_CLASS(t);
252
+ *num_sent = 0;
253
+
254
+ /* Is this the start of a new CCC? */
255
+ if (!t->in_ccc) {
256
+ t->curr_ccc = *data;
257
+ t->in_ccc = true;
258
+ *num_sent = 1;
259
+ trace_i3c_target_handle_ccc(t->address, t->curr_ccc);
260
+ }
261
+
262
+ switch (t->curr_ccc) {
263
+ case I3C_CCC_ENTDAA:
264
+ /*
265
+ * This is the last byte of ENTDAA, the controller is assigning us an
266
+ * address.
267
+ */
268
+ if (t->ccc_byte_offset == 8) {
269
+ t->address = *data;
270
+ t->in_ccc = false;
271
+ t->curr_ccc = 0;
272
+ t->ccc_byte_offset = 0;
273
+ *num_sent = 1;
274
+ }
275
+ break;
276
+ case I3C_CCCD_SETDASA:
277
+ t->address = t->static_address;
278
+ break;
279
+ case I3C_CCC_SETAASA:
280
+ t->address = t->static_address;
281
+ break;
282
+ case I3C_CCC_RSTDAA:
283
+ t->address = 0;
284
+ break;
285
+ case I3C_CCCD_SETNEWDA:
286
+ /* If this isn't the CCC byte, it's our new address. */
287
+ if (*num_sent == 0) {
288
+ t->address = *data;
289
+ *num_sent = 1;
290
+ }
291
+ break;
292
+ case I3C_CCC_ENTTM:
293
+ /*
294
+ * If there are still more to look at, the next byte is the test mode
295
+ * byte.
296
+ */
297
+ if (*num_sent != num_to_send) {
298
+ /* Enter test mode if the byte is non-zero. Otherwise exit. */
299
+ t->in_test_mode = !!data[*num_sent];
300
+ ++*num_sent;
301
+ }
302
+ break;
303
+ /* Ignore other CCCs it's better to handle on a device-by-device basis. */
304
+ default:
305
+ break;
306
+ }
307
+ return tc->handle_ccc_write(t, data, num_to_send, num_sent);
308
+}
309
+
310
+int i3c_send_byte(I3CBus *bus, uint8_t data)
311
+{
312
+ /*
313
+ * Ignored, the caller can determine how many were sent based on if this was
314
+ * ACKed/NACKed.
315
+ */
316
+ uint32_t num_sent;
317
+ return i3c_send(bus, &data, 1, &num_sent);
318
+}
319
+
320
+int i3c_send(I3CBus *bus, const uint8_t *data, uint32_t num_to_send,
321
+ uint32_t *num_sent)
322
+{
323
+ I3CTargetClass *tc;
324
+ I3CTarget *t;
325
+ I3CNode *node;
326
+ int ret = 0;
327
+
328
+ /* If this message is a broadcast and no CCC has been found, grab it. */
329
+ if (bus->broadcast && !bus->in_ccc) {
330
+ bus->ccc = *data;
331
+ bus->in_ccc = true;
332
+ /*
333
+ * We need to keep track if we're currently in ENTDAA.
334
+ * On any other CCC, the CCC is over on a RESTART or STOP, but ENTDAA
335
+ * is only over on a STOP.
336
+ */
337
+ if (bus->ccc == I3C_CCC_ENTDAA) {
338
+ bus->in_entdaa = true;
339
+ }
340
+ }
341
+
342
+ QLIST_FOREACH(node, &bus->current_devs, next) {
343
+ t = node->target;
344
+ tc = I3C_TARGET_GET_CLASS(t);
345
+ if (bus->in_ccc) {
346
+ if (!tc->handle_ccc_write) {
347
+ ret = -1;
348
+ continue;
349
+ }
350
+ ret = i3c_target_handle_ccc_write(t, data, num_to_send, num_sent);
351
+ /* Targets should only NACK on a direct CCC. */
352
+ if (ret && !CCC_IS_DIRECT(bus->ccc)) {
353
+ ret = 0;
354
+ }
355
+ } else {
356
+ if (tc->send) {
357
+ ret = ret || tc->send(t, data, num_to_send, num_sent);
358
+ } else {
359
+ ret = -1;
360
+ }
361
+ }
362
+ }
363
+
364
+ trace_i3c_send(*num_sent, num_to_send, ret == 0);
365
+
366
+ return ret ? -1 : 0;
367
+}
368
+
369
+static int i3c_target_handle_ccc_read(I3CTarget *t, uint8_t *data,
370
+ uint32_t num_to_read, uint32_t *num_read)
371
+{
372
+ I3CTargetClass *tc = I3C_TARGET_GET_CLASS(t);
373
+ uint8_t read_count = 0;
374
+ uint64_t pid;
375
+
376
+ switch (t->curr_ccc) {
377
+ case I3C_CCC_ENTDAA:
378
+ if (t->in_test_mode) {
379
+ pid = TEST_MODE_PROVISIONED_ID;
380
+ } else {
381
+ pid = t->pid;
382
+ }
383
+ /* Return the 6-byte PID, followed by BCR then DCR. */
384
+ while (t->ccc_byte_offset < 6) {
385
+ if (read_count >= num_to_read) {
386
+ break;
387
+ }
388
+ data[read_count] = (pid >> (t->ccc_byte_offset * 8)) & 0xff;
389
+ t->ccc_byte_offset++;
390
+ read_count++;
391
+ }
392
+ if (read_count < num_to_read) {
393
+ data[read_count] = t->bcr;
394
+ t->ccc_byte_offset++;
395
+ read_count++;
396
+ }
397
+ if (read_count < num_to_read) {
398
+ data[read_count] = t->dcr;
399
+ t->ccc_byte_offset++;
400
+ read_count++;
401
+ }
402
+ *num_read = read_count;
403
+ break;
404
+ case I3C_CCCD_GETPID:
405
+ while (t->ccc_byte_offset < 6) {
406
+ if (read_count >= num_to_read) {
407
+ break;
408
+ }
409
+ data[read_count] = (t->pid >> (t->ccc_byte_offset * 8)) & 0xff;
410
+ t->ccc_byte_offset++;
411
+ read_count++;
412
+ }
413
+ *num_read = read_count;
414
+ break;
415
+ case I3C_CCCD_GETBCR:
416
+ *data = t->bcr;
417
+ *num_read = 1;
418
+ break;
419
+ case I3C_CCCD_GETDCR:
420
+ *data = t->dcr;
421
+ *num_read = 1;
422
+ break;
423
+ default:
424
+ /* Unhandled on the I3CTarget class level. */
425
+ break;
426
+ }
427
+
428
+ return tc->handle_ccc_read(t, data, num_to_read, num_read);
429
+}
430
+
431
+int i3c_recv_byte(I3CBus *bus, uint8_t *data)
432
+{
433
+ /*
434
+ * Ignored, the caller can determine how many bytes were read based on if
435
+ * this is ACKed/NACKed.
436
+ */
437
+ uint32_t num_read;
438
+ return i3c_recv(bus, data, 1, &num_read);
439
+}
440
+
441
+int i3c_recv(I3CBus *bus, uint8_t *data, uint32_t num_to_read,
442
+ uint32_t *num_read)
443
+{
444
+ int ret = 0;
445
+ I3CTargetClass *tc;
446
+ I3CTarget *t;
447
+
448
+ *data = 0xff;
449
+ if (!QLIST_EMPTY(&bus->current_devs)) {
450
+ tc = I3C_TARGET_GET_CLASS(QLIST_FIRST(&bus->current_devs)->target);
451
+ t = QLIST_FIRST(&bus->current_devs)->target;
452
+ if (bus->in_ccc) {
453
+ if (!tc->handle_ccc_read) {
454
+ return -1;
455
+ }
456
+ ret = i3c_target_handle_ccc_read(t, data, num_to_read, num_read);
457
+ } else {
458
+ if (tc->recv) {
459
+ /*
460
+ * Targets cannot NACK on a direct transfer, so the data
461
+ * is returned directly.
462
+ */
463
+ *num_read = tc->recv(t, data, num_to_read);
464
+ }
465
+ }
466
+ }
467
+
468
+ trace_i3c_recv(*num_read, num_to_read, ret == 0);
469
+
470
+ return ret;
471
+}
472
+
473
+void i3c_nack(I3CBus *bus)
474
+{
475
+ I3CTargetClass *tc;
476
+ I3CNode *node;
477
+
478
+ if (QLIST_EMPTY(&bus->current_devs)) {
479
+ return;
480
+ }
481
+
482
+ QLIST_FOREACH(node, &bus->current_devs, next) {
483
+ tc = I3C_TARGET_GET_CLASS(node->target);
484
+ if (tc->event) {
485
+ i3c_target_event(node->target, I3C_NACK);
486
+ }
487
+ }
488
+}
489
+
490
+int i3c_target_send_ibi(I3CTarget *t, uint8_t addr, bool is_recv)
491
+{
492
+ I3CBus *bus = I3C_BUS(t->parent_obj.parent_bus);
493
+ I3CBusClass *bc = I3C_BUS_GET_CLASS(bus);
494
+ trace_i3c_target_send_ibi(addr, is_recv);
495
+ return bc->ibi_handle(bus, addr, is_recv);
496
+}
497
+
498
+int i3c_target_send_ibi_bytes(I3CTarget *t, uint8_t data)
499
+{
500
+ I3CBus *bus = I3C_BUS(t->parent_obj.parent_bus);
501
+ I3CBusClass *bc = I3C_BUS_GET_CLASS(bus);
502
+ trace_i3c_target_send_ibi_bytes(data);
503
+ return bc->ibi_recv(bus, data);
504
+}
505
+
506
+int i3c_target_ibi_finish(I3CTarget *t, uint8_t data)
507
+{
508
+ I3CBus *bus = I3C_BUS(t->parent_obj.parent_bus);
509
+ I3CBusClass *bc = I3C_BUS_GET_CLASS(bus);
510
+ trace_i3c_target_ibi_finish();
511
+ return bc->ibi_finish(bus);
512
+}
513
+
514
+static bool i3c_addr_is_rsvd(uint8_t addr)
515
+{
516
+ const bool is_rsvd[255] = {
517
+ [0x00] = true,
518
+ [0x01] = true,
519
+ [0x02] = true,
520
+ [0x3e] = true,
521
+ [0x5e] = true,
522
+ [0x6e] = true,
523
+ [0x76] = true,
524
+ [0x7a] = true,
525
+ [0x7c] = true,
526
+ [0x7e] = true,
527
+ [0x7f] = true,
528
+ };
529
+
530
+ return is_rsvd[addr];
531
+}
532
+
533
+I3CTarget *i3c_target_new(const char *name, uint8_t addr, uint8_t dcr,
534
+ uint8_t bcr, uint64_t pid)
535
+{
536
+ DeviceState *dev;
537
+
538
+ dev = qdev_new(name);
539
+ qdev_prop_set_uint8(dev, "static-address", addr);
540
+ qdev_prop_set_uint8(dev, "dcr", dcr);
541
+ qdev_prop_set_uint8(dev, "bcr", bcr);
542
+ qdev_prop_set_uint64(dev, "pid", pid);
543
+
544
+ if (i3c_addr_is_rsvd(addr)) {
545
+ g_autofree char *path = object_get_canonical_path(OBJECT(dev));
546
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: I3C target created with reserved "
547
+ "address 0x%.2x\n", path, addr);
548
+ }
549
+ return I3C_TARGET(dev);
550
+}
551
+
552
+bool i3c_target_realize_and_unref(I3CTarget *dev, I3CBus *bus, Error **errp)
553
+{
554
+ return qdev_realize_and_unref(&dev->parent_obj, &bus->parent_obj, errp);
555
+}
556
+
557
+I3CTarget *i3c_target_create_simple(I3CBus *bus, const char *name, uint8_t addr,
558
+ uint8_t dcr, uint8_t bcr, uint64_t pid)
559
+{
560
+ I3CTarget *dev = i3c_target_new(name, addr, dcr, bcr, pid);
561
+ dev->address = 0;
562
+ i3c_target_realize_and_unref(dev, bus, &error_abort);
563
+
564
+ return dev;
565
+}
566
+
567
+/* Legacy I2C functions. */
568
+void legacy_i2c_nack(I3CBus *bus)
569
+{
570
+ trace_legacy_i2c_nack();
571
+ i2c_nack(bus->i2c_bus);
572
+}
573
+
574
+uint8_t legacy_i2c_recv(I3CBus *bus)
575
+{
576
+ uint8_t byte = i2c_recv(bus->i2c_bus);
577
+ trace_legacy_i2c_recv(byte);
578
+ return byte;
579
+}
580
+
581
+int legacy_i2c_send(I3CBus *bus, uint8_t data)
582
+{
583
+ trace_legacy_i2c_send(data);
584
+ return i2c_send(bus->i2c_bus, data);
585
+}
586
+
587
+int legacy_i2c_start_transfer(I3CBus *bus, uint8_t address, bool is_recv)
588
+{
589
+ trace_legacy_i2c_start_transfer(address, is_recv);
590
+ return i2c_start_transfer(bus->i2c_bus, address, is_recv);
591
+}
592
+
593
+int legacy_i2c_start_recv(I3CBus *bus, uint8_t address)
594
+{
595
+ trace_legacy_i2c_start_transfer(address, true);
596
+ return i2c_start_transfer(bus->i2c_bus, address, /*is_recv=*/true);
597
+}
598
+
599
+int legacy_i2c_start_send(I3CBus *bus, uint8_t address)
600
+{
601
+ trace_legacy_i2c_start_transfer(address, false);
602
+ return i2c_start_transfer(bus->i2c_bus, address, /*is_recv=*/false);
603
+}
604
+
605
+void legacy_i2c_end_transfer(I3CBus *bus)
606
+{
607
+ trace_legacy_i2c_end_transfer();
608
+ i2c_end_transfer(bus->i2c_bus);
609
+}
610
+
611
+I2CSlave *legacy_i2c_device_create_simple(I3CBus *bus, const char *name,
612
+ uint8_t addr)
613
+{
614
+ I2CSlave *dev = i2c_slave_new(name, addr);
615
+
616
+ i2c_slave_realize_and_unref(dev, bus->i2c_bus, &error_abort);
617
+ return dev;
618
+}
619
+
620
+static void i3c_target_class_init(ObjectClass *klass, const void *data)
621
+{
622
+ DeviceClass *k = DEVICE_CLASS(klass);
623
+ I3CTargetClass *sc = I3C_TARGET_CLASS(klass);
624
+ set_bit(DEVICE_CATEGORY_MISC, k->categories);
625
+ k->bus_type = TYPE_I3C_BUS;
626
+ device_class_set_props(k, i3c_props);
627
+ sc->target_match = i3c_target_match;
628
+}
629
+
630
+static const TypeInfo i3c_types[] = {
631
+ {
632
+ .name = TYPE_I3C_BUS,
633
+ .parent = TYPE_BUS,
634
+ .instance_size = sizeof(I3CBus),
635
+ .class_size = sizeof(I3CBusClass),
636
+ },
637
+ {
638
+ .name = TYPE_I3C_TARGET,
639
+ .parent = TYPE_DEVICE,
640
+ .instance_size = sizeof(I3CTarget),
641
+ .abstract = true,
642
+ .class_size = sizeof(I3CTargetClass),
643
+ .class_init = i3c_target_class_init,
644
+ },
645
+};
646
+
647
+DEFINE_TYPES(i3c_types)