uboot/drivers/spi/sandbox_spi.c
<<
>>
Prefs
   1/*
   2 * Simulate a SPI port
   3 *
   4 * Copyright (c) 2011-2013 The Chromium OS Authors.
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * Licensed under the GPL-2 or later.
   9 */
  10
  11#define LOG_CATEGORY UCLASS_SPI
  12
  13#include <common.h>
  14#include <dm.h>
  15#include <log.h>
  16#include <malloc.h>
  17#include <spi.h>
  18#include <spi_flash.h>
  19#include <os.h>
  20
  21#include <linux/errno.h>
  22#include <asm/spi.h>
  23#include <asm/state.h>
  24#include <dm/acpi.h>
  25#include <dm/device-internal.h>
  26
  27#ifndef CONFIG_SPI_IDLE_VAL
  28# define CONFIG_SPI_IDLE_VAL 0xFF
  29#endif
  30
  31/**
  32 * struct sandbox_spi_priv - Sandbox SPI private data
  33 *
  34 * Helper struct to keep track of the sandbox SPI bus internal state. It is
  35 * used in unit tests to verify that dm spi functions update the bus
  36 * speed/mode properly (for instance, when jumping back and forth between spi
  37 * slaves claiming the bus, we need to make sure that the bus speed is updated
  38 * accordingly for each slave).
  39 *
  40 * @speed:      Current bus speed.
  41 * @mode:       Current bus mode.
  42 */
  43struct sandbox_spi_priv {
  44        uint speed;
  45        uint mode;
  46};
  47
  48__weak int sandbox_spi_get_emul(struct sandbox_state *state,
  49                                struct udevice *bus, struct udevice *slave,
  50                                struct udevice **emulp)
  51{
  52        return -ENOENT;
  53}
  54
  55uint sandbox_spi_get_speed(struct udevice *dev)
  56{
  57        struct sandbox_spi_priv *priv = dev_get_priv(dev);
  58
  59        return priv->speed;
  60}
  61
  62uint sandbox_spi_get_mode(struct udevice *dev)
  63{
  64        struct sandbox_spi_priv *priv = dev_get_priv(dev);
  65
  66        return priv->mode;
  67}
  68
  69static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen,
  70                            const void *dout, void *din, unsigned long flags)
  71{
  72        struct udevice *bus = slave->parent;
  73        struct sandbox_state *state = state_get_current();
  74        struct dm_spi_emul_ops *ops;
  75        struct udevice *emul;
  76        uint bytes = bitlen / 8, i;
  77        int ret;
  78        uint busnum, cs;
  79
  80        if (bitlen == 0)
  81                return 0;
  82
  83        /* we can only do 8 bit transfers */
  84        if (bitlen % 8) {
  85                printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n",
  86                       bitlen);
  87                return -EINVAL;
  88        }
  89
  90        busnum = dev_seq(bus);
  91        cs = spi_chip_select(slave);
  92        if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS ||
  93            cs >= CONFIG_SANDBOX_SPI_MAX_CS) {
  94                printf("%s: busnum=%u, cs=%u: out of range\n", __func__,
  95                       busnum, cs);
  96                return -ENOENT;
  97        }
  98        ret = sandbox_spi_get_emul(state, bus, slave, &emul);
  99        if (ret) {
 100                printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n",
 101                       __func__, busnum, cs, ret);
 102                return -ENOENT;
 103        }
 104        ret = device_probe(emul);
 105        if (ret)
 106                return ret;
 107
 108        ops = spi_emul_get_ops(emul);
 109        ret = ops->xfer(emul, bitlen, dout, din, flags);
 110
 111        log_content("sandbox_spi: xfer: got back %i (that's %s)\n rx:",
 112                    ret, ret ? "bad" : "good");
 113        if (din) {
 114                for (i = 0; i < bytes; ++i)
 115                        log_content(" %u:%02x", i, ((u8 *)din)[i]);
 116        }
 117        log_content("\n");
 118
 119        return ret;
 120}
 121
 122static int sandbox_spi_set_speed(struct udevice *bus, uint speed)
 123{
 124        struct sandbox_spi_priv *priv = dev_get_priv(bus);
 125
 126        priv->speed = speed;
 127
 128        return 0;
 129}
 130
 131static int sandbox_spi_set_mode(struct udevice *bus, uint mode)
 132{
 133        struct sandbox_spi_priv *priv = dev_get_priv(bus);
 134
 135        priv->mode = mode;
 136
 137        return 0;
 138}
 139
 140static int sandbox_cs_info(struct udevice *bus, uint cs,
 141                           struct spi_cs_info *info)
 142{
 143        /* Always allow activity on CS 0, CS 1 */
 144        if (cs >= 2)
 145                return -EINVAL;
 146
 147        return 0;
 148}
 149
 150static int sandbox_spi_get_mmap(struct udevice *dev, ulong *map_basep,
 151                                uint *map_sizep, uint *offsetp)
 152{
 153        *map_basep = 0x1000;
 154        *map_sizep = 0x2000;
 155        *offsetp = 0x100;
 156
 157        return 0;
 158}
 159
 160static const struct dm_spi_ops sandbox_spi_ops = {
 161        .xfer           = sandbox_spi_xfer,
 162        .set_speed      = sandbox_spi_set_speed,
 163        .set_mode       = sandbox_spi_set_mode,
 164        .cs_info        = sandbox_cs_info,
 165        .get_mmap       = sandbox_spi_get_mmap,
 166};
 167
 168static const struct udevice_id sandbox_spi_ids[] = {
 169        { .compatible = "sandbox,spi" },
 170        { }
 171};
 172
 173U_BOOT_DRIVER(sandbox_spi) = {
 174        .name   = "sandbox_spi",
 175        .id     = UCLASS_SPI,
 176        .of_match = sandbox_spi_ids,
 177        .ops    = &sandbox_spi_ops,
 178        .priv_auto = sizeof(struct sandbox_spi_priv),
 179};
 180