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