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