blob: c99e6de933279f1925be81042037ea957c7b66d6 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass3834c842014-12-10 08:55:50 -07002/*
3 * Simulate an I2C port
4 *
5 * Copyright (c) 2014 Google, Inc
Simon Glass3834c842014-12-10 08:55:50 -07006 */
7
Tom Riniabb9a042024-05-18 20:20:43 -06008#include <common.h>
Simon Glass3834c842014-12-10 08:55:50 -07009#include <dm.h>
10#include <errno.h>
Simon Glass3834c842014-12-10 08:55:50 -070011#include <i2c.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass4662f612020-12-19 10:39:54 -070013#include <asm/i2c.h>
Simon Glass3834c842014-12-10 08:55:50 -070014#include <asm/test.h>
Simon Glass39ab8672020-07-07 13:11:48 -060015#include <dm/acpi.h>
Simon Glass3834c842014-12-10 08:55:50 -070016#include <dm/lists.h>
17#include <dm/device-internal.h>
Simon Glass3834c842014-12-10 08:55:50 -070018
Simon Glass3834c842014-12-10 08:55:50 -070019static int get_emul(struct udevice *dev, struct udevice **devp,
20 struct dm_i2c_ops **opsp)
21{
Simon Glass713c3f02015-01-25 08:27:13 -070022 struct dm_i2c_chip *plat;
Simon Glass3834c842014-12-10 08:55:50 -070023 int ret;
24
25 *devp = NULL;
26 *opsp = NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070027 plat = dev_get_parent_plat(dev);
Simon Glass713c3f02015-01-25 08:27:13 -070028 if (!plat->emul) {
Simon Glass17b56f62018-11-18 08:14:34 -070029 ret = i2c_emul_find(dev, &plat->emul);
Simon Glass3834c842014-12-10 08:55:50 -070030 if (ret)
31 return ret;
Simon Glass3834c842014-12-10 08:55:50 -070032 }
Simon Glass713c3f02015-01-25 08:27:13 -070033 *devp = plat->emul;
34 *opsp = i2c_get_ops(plat->emul);
Simon Glass3834c842014-12-10 08:55:50 -070035
36 return 0;
37}
38
Simon Glass4c70ed92015-04-20 12:37:15 -060039void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
40{
41 struct sandbox_i2c_priv *priv = dev_get_priv(bus);
42
43 priv->test_mode = test_mode;
44}
45
Simon Glass3834c842014-12-10 08:55:50 -070046static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
47 int nmsgs)
48{
Simon Glassde0977b2015-03-05 12:25:20 -070049 struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
Simon Glass4c70ed92015-04-20 12:37:15 -060050 struct sandbox_i2c_priv *priv = dev_get_priv(bus);
Simon Glass3834c842014-12-10 08:55:50 -070051 struct dm_i2c_ops *ops;
52 struct udevice *emul, *dev;
53 bool is_read;
54 int ret;
55
56 /* Special test code to return success but with no emulation */
Simon Glass4c70ed92015-04-20 12:37:15 -060057 if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
Simon Glass3834c842014-12-10 08:55:50 -070058 return 0;
59
Simon Glassa2723ae2015-01-25 08:26:55 -070060 ret = i2c_get_chip(bus, msg->addr, 1, &dev);
Simon Glass3834c842014-12-10 08:55:50 -070061 if (ret)
62 return ret;
63
64 ret = get_emul(dev, &emul, &ops);
65 if (ret)
66 return ret;
67
Simon Glass4c70ed92015-04-20 12:37:15 -060068 if (priv->test_mode) {
69 /*
70 * For testing, don't allow writing above 100KHz for writes and
71 * 400KHz for reads.
72 */
73 is_read = nmsgs > 1;
Simon Glassf0c99c52020-01-23 11:48:22 -070074 if (i2c->speed_hz > (is_read ? I2C_SPEED_FAST_RATE :
75 I2C_SPEED_STANDARD_RATE)) {
Simon Glass4c70ed92015-04-20 12:37:15 -060076 debug("%s: Max speed exceeded\n", __func__);
77 return -EINVAL;
78 }
Simon Glass34d8e952015-04-20 12:37:13 -060079 }
Simon Glass4c70ed92015-04-20 12:37:15 -060080
Simon Glass3834c842014-12-10 08:55:50 -070081 return ops->xfer(emul, msg, nmsgs);
82}
83
84static const struct dm_i2c_ops sandbox_i2c_ops = {
85 .xfer = sandbox_i2c_xfer,
86};
87
Simon Glass3834c842014-12-10 08:55:50 -070088static const struct udevice_id sandbox_i2c_ids[] = {
89 { .compatible = "sandbox,i2c" },
90 { }
91};
92
Simon Glass4d4558e2020-10-03 11:31:36 -060093U_BOOT_DRIVER(sandbox_i2c) = {
94 .name = "sandbox_i2c",
Simon Glass3834c842014-12-10 08:55:50 -070095 .id = UCLASS_I2C,
96 .of_match = sandbox_i2c_ids,
Simon Glass3834c842014-12-10 08:55:50 -070097 .ops = &sandbox_i2c_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -070098 .priv_auto = sizeof(struct sandbox_i2c_priv),
Simon Glass3834c842014-12-10 08:55:50 -070099};