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