xref: /rk3399_rockchip-uboot/drivers/i2c/sandbox_i2c.c (revision 1bde67b1f492cbb0177241a56af59f706d45fccf)
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 
21d19de0d3SSimon Glass struct dm_sandbox_i2c_emul_priv {
22d19de0d3SSimon Glass 	struct udevice *emul;
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 
50d19de0d3SSimon Glass static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
51d19de0d3SSimon Glass 			    int nmsgs)
52d19de0d3SSimon Glass {
53e564f054SSimon Glass 	struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
54d19de0d3SSimon Glass 	struct dm_i2c_ops *ops;
55d19de0d3SSimon Glass 	struct udevice *emul, *dev;
56d19de0d3SSimon Glass 	bool is_read;
57d19de0d3SSimon Glass 	int ret;
58d19de0d3SSimon Glass 
59d19de0d3SSimon Glass 	/* Special test code to return success but with no emulation */
60d19de0d3SSimon Glass 	if (msg->addr == SANDBOX_I2C_TEST_ADDR)
61d19de0d3SSimon Glass 		return 0;
62d19de0d3SSimon Glass 
6325ab4b03SSimon Glass 	ret = i2c_get_chip(bus, msg->addr, 1, &dev);
64d19de0d3SSimon Glass 	if (ret)
65d19de0d3SSimon Glass 		return ret;
66d19de0d3SSimon Glass 
67d19de0d3SSimon Glass 	ret = get_emul(dev, &emul, &ops);
68d19de0d3SSimon Glass 	if (ret)
69d19de0d3SSimon Glass 		return ret;
70d19de0d3SSimon Glass 
71d19de0d3SSimon Glass 	/*
72d19de0d3SSimon Glass 	 * For testing, don't allow writing above 100KHz for writes and
73d19de0d3SSimon Glass 	 * 400KHz for reads
74d19de0d3SSimon Glass 	 */
75d19de0d3SSimon Glass 	is_read = nmsgs > 1;
76*1bde67b1SSimon Glass 	if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
77*1bde67b1SSimon Glass 		debug("%s: Max speed exceeded\n", __func__);
78d19de0d3SSimon Glass 		return -EINVAL;
79*1bde67b1SSimon Glass 	}
80d19de0d3SSimon Glass 	return ops->xfer(emul, msg, nmsgs);
81d19de0d3SSimon Glass }
82d19de0d3SSimon Glass 
83d19de0d3SSimon Glass static const struct dm_i2c_ops sandbox_i2c_ops = {
84d19de0d3SSimon Glass 	.xfer		= sandbox_i2c_xfer,
85d19de0d3SSimon Glass };
86d19de0d3SSimon Glass 
87d19de0d3SSimon Glass static const struct udevice_id sandbox_i2c_ids[] = {
88d19de0d3SSimon Glass 	{ .compatible = "sandbox,i2c" },
89d19de0d3SSimon Glass 	{ }
90d19de0d3SSimon Glass };
91d19de0d3SSimon Glass 
92d19de0d3SSimon Glass U_BOOT_DRIVER(i2c_sandbox) = {
93d19de0d3SSimon Glass 	.name	= "i2c_sandbox",
94d19de0d3SSimon Glass 	.id	= UCLASS_I2C,
95d19de0d3SSimon Glass 	.of_match = sandbox_i2c_ids,
96d19de0d3SSimon Glass 	.ops	= &sandbox_i2c_ops,
97d19de0d3SSimon Glass };
98