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