xref: /rk3399_rockchip-uboot/drivers/i2c/sandbox_i2c.c (revision aabf79929ed69c1d8e4db8b15a0b53d46b1eeeaf)
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 <i2c.h>
13d19de0d3SSimon Glass #include <asm/test.h>
14d19de0d3SSimon Glass #include <dm/lists.h>
15d19de0d3SSimon Glass #include <dm/device-internal.h>
16d19de0d3SSimon Glass 
17d19de0d3SSimon Glass DECLARE_GLOBAL_DATA_PTR;
18d19de0d3SSimon Glass 
19182bf92dSSimon Glass struct sandbox_i2c_priv {
20182bf92dSSimon Glass 	bool test_mode;
21d19de0d3SSimon Glass };
22d19de0d3SSimon Glass 
get_emul(struct udevice * dev,struct udevice ** devp,struct dm_i2c_ops ** opsp)23d19de0d3SSimon Glass static int get_emul(struct udevice *dev, struct udevice **devp,
24d19de0d3SSimon Glass 		    struct dm_i2c_ops **opsp)
25d19de0d3SSimon Glass {
26e6f66ec0SSimon Glass 	struct dm_i2c_chip *plat;
27a989ec8dSPrzemyslaw Marczak 	struct udevice *child;
28d19de0d3SSimon Glass 	int ret;
29d19de0d3SSimon Glass 
30d19de0d3SSimon Glass 	*devp = NULL;
31d19de0d3SSimon Glass 	*opsp = NULL;
32e6f66ec0SSimon Glass 	plat = dev_get_parent_platdata(dev);
33e6f66ec0SSimon Glass 	if (!plat->emul) {
34*2e3f1ff6SSimon Glass 		ret = dm_scan_fdt_dev(dev);
35d19de0d3SSimon Glass 		if (ret)
36d19de0d3SSimon Glass 			return ret;
37d19de0d3SSimon Glass 
38a989ec8dSPrzemyslaw Marczak 		for (device_find_first_child(dev, &child); child;
39a989ec8dSPrzemyslaw Marczak 		     device_find_next_child(&child)) {
40a989ec8dSPrzemyslaw Marczak 			if (device_get_uclass_id(child) != UCLASS_I2C_EMUL)
41a989ec8dSPrzemyslaw Marczak 				continue;
42a989ec8dSPrzemyslaw Marczak 
43a989ec8dSPrzemyslaw Marczak 			ret = device_probe(child);
44d19de0d3SSimon Glass 			if (ret)
45d19de0d3SSimon Glass 				return ret;
46a989ec8dSPrzemyslaw Marczak 
47a989ec8dSPrzemyslaw Marczak 			break;
48a989ec8dSPrzemyslaw Marczak 		}
49a989ec8dSPrzemyslaw Marczak 
50a989ec8dSPrzemyslaw Marczak 		if (child)
51a989ec8dSPrzemyslaw Marczak 			plat->emul = child;
52a989ec8dSPrzemyslaw Marczak 		else
53a989ec8dSPrzemyslaw Marczak 			return -ENODEV;
54d19de0d3SSimon Glass 	}
55e6f66ec0SSimon Glass 	*devp = plat->emul;
56e6f66ec0SSimon Glass 	*opsp = i2c_get_ops(plat->emul);
57d19de0d3SSimon Glass 
58d19de0d3SSimon Glass 	return 0;
59d19de0d3SSimon Glass }
60d19de0d3SSimon Glass 
sandbox_i2c_set_test_mode(struct udevice * bus,bool test_mode)61182bf92dSSimon Glass void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
62182bf92dSSimon Glass {
63182bf92dSSimon Glass 	struct sandbox_i2c_priv *priv = dev_get_priv(bus);
64182bf92dSSimon Glass 
65182bf92dSSimon Glass 	priv->test_mode = test_mode;
66182bf92dSSimon Glass }
67182bf92dSSimon Glass 
sandbox_i2c_xfer(struct udevice * bus,struct i2c_msg * msg,int nmsgs)68d19de0d3SSimon Glass static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
69d19de0d3SSimon Glass 			    int nmsgs)
70d19de0d3SSimon Glass {
71e564f054SSimon Glass 	struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
72182bf92dSSimon Glass 	struct sandbox_i2c_priv *priv = dev_get_priv(bus);
73d19de0d3SSimon Glass 	struct dm_i2c_ops *ops;
74d19de0d3SSimon Glass 	struct udevice *emul, *dev;
75d19de0d3SSimon Glass 	bool is_read;
76d19de0d3SSimon Glass 	int ret;
77d19de0d3SSimon Glass 
78d19de0d3SSimon Glass 	/* Special test code to return success but with no emulation */
79182bf92dSSimon Glass 	if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
80d19de0d3SSimon Glass 		return 0;
81d19de0d3SSimon Glass 
8225ab4b03SSimon Glass 	ret = i2c_get_chip(bus, msg->addr, 1, &dev);
83d19de0d3SSimon Glass 	if (ret)
84d19de0d3SSimon Glass 		return ret;
85d19de0d3SSimon Glass 
86d19de0d3SSimon Glass 	ret = get_emul(dev, &emul, &ops);
87d19de0d3SSimon Glass 	if (ret)
88d19de0d3SSimon Glass 		return ret;
89d19de0d3SSimon Glass 
90182bf92dSSimon Glass 	if (priv->test_mode) {
91d19de0d3SSimon Glass 		/*
92d19de0d3SSimon Glass 		* For testing, don't allow writing above 100KHz for writes and
93182bf92dSSimon Glass 		* 400KHz for reads.
94d19de0d3SSimon Glass 		*/
95d19de0d3SSimon Glass 		is_read = nmsgs > 1;
961bde67b1SSimon Glass 		if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
971bde67b1SSimon Glass 			debug("%s: Max speed exceeded\n", __func__);
98d19de0d3SSimon Glass 			return -EINVAL;
991bde67b1SSimon Glass 		}
100182bf92dSSimon Glass 	}
101182bf92dSSimon Glass 
102d19de0d3SSimon Glass 	return ops->xfer(emul, msg, nmsgs);
103d19de0d3SSimon Glass }
104d19de0d3SSimon Glass 
105d19de0d3SSimon Glass static const struct dm_i2c_ops sandbox_i2c_ops = {
106d19de0d3SSimon Glass 	.xfer		= sandbox_i2c_xfer,
107d19de0d3SSimon Glass };
108d19de0d3SSimon Glass 
109d19de0d3SSimon Glass static const struct udevice_id sandbox_i2c_ids[] = {
110d19de0d3SSimon Glass 	{ .compatible = "sandbox,i2c" },
111d19de0d3SSimon Glass 	{ }
112d19de0d3SSimon Glass };
113d19de0d3SSimon Glass 
114d19de0d3SSimon Glass U_BOOT_DRIVER(i2c_sandbox) = {
115d19de0d3SSimon Glass 	.name	= "i2c_sandbox",
116d19de0d3SSimon Glass 	.id	= UCLASS_I2C,
117d19de0d3SSimon Glass 	.of_match = sandbox_i2c_ids,
118d19de0d3SSimon Glass 	.ops	= &sandbox_i2c_ops,
119182bf92dSSimon Glass 	.priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv),
120d19de0d3SSimon Glass };
121