uboot/drivers/i2c/sandbox_i2c.c
<<
>>
Prefs
   1/*
   2 * Simulate an I2C port
   3 *
   4 * Copyright (c) 2014 Google, Inc
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <errno.h>
  12#include <fdtdec.h>
  13#include <i2c.h>
  14#include <asm/test.h>
  15#include <dm/lists.h>
  16#include <dm/device-internal.h>
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20struct sandbox_i2c_priv {
  21        bool test_mode;
  22};
  23
  24static int get_emul(struct udevice *dev, struct udevice **devp,
  25                    struct dm_i2c_ops **opsp)
  26{
  27        struct dm_i2c_chip *plat;
  28        struct udevice *child;
  29        int ret;
  30
  31        *devp = NULL;
  32        *opsp = NULL;
  33        plat = dev_get_parent_platdata(dev);
  34        if (!plat->emul) {
  35                ret = dm_scan_fdt_dev(dev);
  36                if (ret)
  37                        return ret;
  38
  39                for (device_find_first_child(dev, &child); child;
  40                     device_find_next_child(&child)) {
  41                        if (device_get_uclass_id(child) != UCLASS_I2C_EMUL)
  42                                continue;
  43
  44                        ret = device_probe(child);
  45                        if (ret)
  46                                return ret;
  47
  48                        break;
  49                }
  50
  51                if (child)
  52                        plat->emul = child;
  53                else
  54                        return -ENODEV;
  55        }
  56        *devp = plat->emul;
  57        *opsp = i2c_get_ops(plat->emul);
  58
  59        return 0;
  60}
  61
  62void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
  63{
  64        struct sandbox_i2c_priv *priv = dev_get_priv(bus);
  65
  66        priv->test_mode = test_mode;
  67}
  68
  69static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
  70                            int nmsgs)
  71{
  72        struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
  73        struct sandbox_i2c_priv *priv = dev_get_priv(bus);
  74        struct dm_i2c_ops *ops;
  75        struct udevice *emul, *dev;
  76        bool is_read;
  77        int ret;
  78
  79        /* Special test code to return success but with no emulation */
  80        if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
  81                return 0;
  82
  83        ret = i2c_get_chip(bus, msg->addr, 1, &dev);
  84        if (ret)
  85                return ret;
  86
  87        ret = get_emul(dev, &emul, &ops);
  88        if (ret)
  89                return ret;
  90
  91        if (priv->test_mode) {
  92                /*
  93                * For testing, don't allow writing above 100KHz for writes and
  94                * 400KHz for reads.
  95                */
  96                is_read = nmsgs > 1;
  97                if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
  98                        debug("%s: Max speed exceeded\n", __func__);
  99                        return -EINVAL;
 100                }
 101        }
 102
 103        return ops->xfer(emul, msg, nmsgs);
 104}
 105
 106static const struct dm_i2c_ops sandbox_i2c_ops = {
 107        .xfer           = sandbox_i2c_xfer,
 108};
 109
 110static const struct udevice_id sandbox_i2c_ids[] = {
 111        { .compatible = "sandbox,i2c" },
 112        { }
 113};
 114
 115U_BOOT_DRIVER(i2c_sandbox) = {
 116        .name   = "i2c_sandbox",
 117        .id     = UCLASS_I2C,
 118        .of_match = sandbox_i2c_ids,
 119        .ops    = &sandbox_i2c_ops,
 120        .priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv),
 121};
 122