/src/u-boot/drivers/i2c/sandbox_i2c.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0+ |
2 | | /* |
3 | | * Simulate an I2C port |
4 | | * |
5 | | * Copyright (c) 2014 Google, Inc |
6 | | */ |
7 | | |
8 | | #include <dm.h> |
9 | | #include <errno.h> |
10 | | #include <i2c.h> |
11 | | #include <log.h> |
12 | | #include <asm/i2c.h> |
13 | | #include <asm/test.h> |
14 | | #include <dm/acpi.h> |
15 | | #include <dm/lists.h> |
16 | | #include <dm/device-internal.h> |
17 | | |
18 | | static int get_emul(struct udevice *dev, struct udevice **devp, |
19 | | struct dm_i2c_ops **opsp) |
20 | 0 | { |
21 | 0 | struct dm_i2c_chip *plat; |
22 | 0 | int ret; |
23 | |
|
24 | 0 | *devp = NULL; |
25 | 0 | *opsp = NULL; |
26 | 0 | plat = dev_get_parent_plat(dev); |
27 | 0 | if (!plat->emul) { |
28 | 0 | ret = i2c_emul_find(dev, &plat->emul); |
29 | 0 | if (ret) |
30 | 0 | return ret; |
31 | 0 | } |
32 | 0 | *devp = plat->emul; |
33 | 0 | *opsp = i2c_get_ops(plat->emul); |
34 | |
|
35 | 0 | return 0; |
36 | 0 | } |
37 | | |
38 | | void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode) |
39 | 0 | { |
40 | 0 | struct sandbox_i2c_priv *priv = dev_get_priv(bus); |
41 | |
|
42 | 0 | priv->test_mode = test_mode; |
43 | 0 | } |
44 | | |
45 | | static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, |
46 | | int nmsgs) |
47 | 0 | { |
48 | 0 | struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus); |
49 | 0 | struct sandbox_i2c_priv *priv = dev_get_priv(bus); |
50 | 0 | struct dm_i2c_ops *ops; |
51 | 0 | struct udevice *emul, *dev; |
52 | 0 | bool is_read; |
53 | 0 | int ret; |
54 | | |
55 | | /* Special test code to return success but with no emulation */ |
56 | 0 | if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR) |
57 | 0 | return 0; |
58 | | |
59 | 0 | ret = i2c_get_chip(bus, msg->addr, 1, &dev); |
60 | 0 | if (ret) |
61 | 0 | return ret; |
62 | | |
63 | 0 | ret = get_emul(dev, &emul, &ops); |
64 | 0 | if (ret) |
65 | 0 | return ret; |
66 | | |
67 | 0 | if (priv->test_mode) { |
68 | | /* |
69 | | * For testing, don't allow writing above 100KHz for writes and |
70 | | * 400KHz for reads. |
71 | | */ |
72 | 0 | is_read = nmsgs > 1; |
73 | 0 | if (i2c->speed_hz > (is_read ? I2C_SPEED_FAST_RATE : |
74 | 0 | I2C_SPEED_STANDARD_RATE)) { |
75 | 0 | debug("%s: Max speed exceeded\n", __func__); |
76 | 0 | return -EINVAL; |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | 0 | return ops->xfer(emul, msg, nmsgs); |
81 | 0 | } |
82 | | |
83 | | static const struct dm_i2c_ops sandbox_i2c_ops = { |
84 | | .xfer = sandbox_i2c_xfer, |
85 | | }; |
86 | | |
87 | | static const struct udevice_id sandbox_i2c_ids[] = { |
88 | | { .compatible = "sandbox,i2c" }, |
89 | | { } |
90 | | }; |
91 | | |
92 | | U_BOOT_DRIVER(sandbox_i2c) = { |
93 | | .name = "sandbox_i2c", |
94 | | .id = UCLASS_I2C, |
95 | | .of_match = sandbox_i2c_ids, |
96 | | .ops = &sandbox_i2c_ops, |
97 | | .priv_auto = sizeof(struct sandbox_i2c_priv), |
98 | | }; |