Commit b7c25b11b6a1e3f840464224309b72a91b65bc56
1 parent
25cbb47090
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
dm: sandbox: i2c: Add a new 'emulation parent' uclass
Sandbox i2c works using emulation drivers which are currently children of the i2c device: rtc_0: rtc@43 { reg = <0x43>; compatible = "sandbox-rtc"; emul { compatible = "sandbox,i2c-rtc"; }; }; In this case the emulation device is attached to i2c bus on address 0x43 and provides the Real-Time-Clock (RTC) functionality. However this is not ideal, since every device on an I2C bus has a child device. This is only really the case for sandbox, but we want to avoid special-case code for sandbox. A better approach seems to be to add a separate node on the bus, an 'emulation parent'. This can be given a bogus address (such as 0xff) and hides all the emulators away. Then we can use a phandle to point from the device to the correct emualtor, and only on sandbox. The code to find an emulator does not interfere with normal i2c operation. Add a new UCLASS_I2C_EMUL_PARENT uclass which allows finding an emulator given a bus, and finding a bus given an emulator. This will be used in a follow-on patch. Signed-off-by: Simon Glass <sjg@chromium.org>
Showing 3 changed files with 99 additions and 0 deletions Side-by-side Diff
drivers/i2c/i2c-emul-uclass.c
... | ... | @@ -6,9 +6,86 @@ |
6 | 6 | #include <common.h> |
7 | 7 | #include <dm.h> |
8 | 8 | #include <i2c.h> |
9 | +#include <dm/device-internal.h> | |
10 | +#include <dm/uclass-internal.h> | |
9 | 11 | |
12 | +/* | |
13 | + * i2c emulation works using an 'emul' node at the bus level. Each device in | |
14 | + * that node is in the UCLASS_I2C_EMUL uclass, and emulates one i2c device. A | |
15 | + * pointer to the device it emulates is in the 'dev' property of the emul device | |
16 | + * uclass platdata (struct i2c_emul_platdata), put there by i2c_emul_find(). | |
17 | + * When sandbox wants an emulator for a device, it calls i2c_emul_find() which | |
18 | + * searches for the emulator with the correct address. To find the device for an | |
19 | + * emulator, call i2c_emul_get_device(). | |
20 | + * | |
21 | + * The 'emul' node is in the UCLASS_I2C_EMUL_PARENT uclass. We use a separate | |
22 | + * uclass so avoid having strange devices on the I2C bus. | |
23 | + */ | |
24 | + | |
25 | +/** | |
26 | + * struct i2c_emul_uc_platdata - information about the emulator for this device | |
27 | + * | |
28 | + * This is used by devices in UCLASS_I2C_EMUL to record information about the | |
29 | + * device being emulated. It is accessible with dev_get_uclass_platdata() | |
30 | + * | |
31 | + * @dev: Device being emulated | |
32 | + */ | |
33 | +struct i2c_emul_uc_platdata { | |
34 | + struct udevice *dev; | |
35 | +}; | |
36 | + | |
37 | +struct udevice *i2c_emul_get_device(struct udevice *emul) | |
38 | +{ | |
39 | + struct i2c_emul_uc_platdata *uc_plat = dev_get_uclass_platdata(emul); | |
40 | + | |
41 | + return uc_plat->dev; | |
42 | +} | |
43 | + | |
44 | +int i2c_emul_find(struct udevice *dev, struct udevice **emulp) | |
45 | +{ | |
46 | + struct i2c_emul_uc_platdata *uc_plat; | |
47 | + struct udevice *emul; | |
48 | + int ret; | |
49 | + | |
50 | + ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev, | |
51 | + "sandbox,emul", &emul); | |
52 | + if (ret) { | |
53 | + log_err("No emulators for device '%s'\n", dev->name); | |
54 | + return ret; | |
55 | + } | |
56 | + uc_plat = dev_get_uclass_platdata(emul); | |
57 | + uc_plat->dev = dev; | |
58 | + *emulp = emul; | |
59 | + | |
60 | + return device_probe(emul); | |
61 | +} | |
62 | + | |
10 | 63 | UCLASS_DRIVER(i2c_emul) = { |
11 | 64 | .id = UCLASS_I2C_EMUL, |
12 | 65 | .name = "i2c_emul", |
66 | + .per_device_platdata_auto_alloc_size = | |
67 | + sizeof(struct i2c_emul_uc_platdata), | |
68 | +}; | |
69 | + | |
70 | +/* | |
71 | + * This uclass is a child of the i2c bus. Its platdata is not defined here so | |
72 | + * is defined by its parent, UCLASS_I2C, which uses struct dm_i2c_chip. See | |
73 | + * per_child_platdata_auto_alloc_size in UCLASS_DRIVER(i2c). | |
74 | + */ | |
75 | +UCLASS_DRIVER(i2c_emul_parent) = { | |
76 | + .id = UCLASS_I2C_EMUL_PARENT, | |
77 | + .name = "i2c_emul_parent", | |
78 | + .post_bind = dm_scan_fdt_dev, | |
79 | +}; | |
80 | + | |
81 | +static const struct udevice_id i2c_emul_parent_ids[] = { | |
82 | + { .compatible = "sandbox,i2c-emul-parent" }, | |
83 | + { } | |
84 | +}; | |
85 | + | |
86 | +U_BOOT_DRIVER(i2c_emul_parent_drv) = { | |
87 | + .name = "i2c_emul_parent_drv", | |
88 | + .id = UCLASS_I2C_EMUL_PARENT, | |
89 | + .of_match = i2c_emul_parent_ids, | |
13 | 90 | }; |
include/dm/uclass-id.h
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | UCLASS_TEST_DUMMY, |
22 | 22 | UCLASS_SPI_EMUL, /* sandbox SPI device emulator */ |
23 | 23 | UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ |
24 | + UCLASS_I2C_EMUL_PARENT, /* parent for I2C device emulators */ | |
24 | 25 | UCLASS_PCI_EMUL, /* sandbox PCI device emulator */ |
25 | 26 | UCLASS_USB_EMUL, /* sandbox USB bus device emulator */ |
26 | 27 | UCLASS_AXI_EMUL, /* sandbox AXI bus device emulator */ |
include/i2c.h
... | ... | @@ -536,6 +536,27 @@ |
536 | 536 | */ |
537 | 537 | void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs); |
538 | 538 | |
539 | +/** | |
540 | + * i2c_emul_find() - Find an emulator for an i2c sandbox device | |
541 | + * | |
542 | + * This looks at the device's 'emul' phandle | |
543 | + * | |
544 | + * @dev: Device to find an emulator for | |
545 | + * @emulp: Returns the associated emulator, if found * | |
546 | + * @return 0 if OK, -ENOENT or -ENODEV if not found | |
547 | + */ | |
548 | +int i2c_emul_find(struct udevice *dev, struct udevice **emulp); | |
549 | + | |
550 | +/** | |
551 | + * i2c_emul_get_device() - Find the device being emulated | |
552 | + * | |
553 | + * Given an emulator this returns the associated device | |
554 | + * | |
555 | + * @emul: Emulator for the device | |
556 | + * @return device that @emul is emulating | |
557 | + */ | |
558 | +struct udevice *i2c_emul_get_device(struct udevice *emul); | |
559 | + | |
539 | 560 | #ifndef CONFIG_DM_I2C |
540 | 561 | |
541 | 562 | /* |