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