Commit c60e1f25 authored by Simon Glass's avatar Simon Glass

dm: sandbox: Add a SPI emulation uclass

U-Boot includes a SPI emulation driver already but it is not explicit, and
is hidden in the SPI flash code.

Conceptually with sandbox's SPI implementation we have a layer which
creates SPI bus transitions and a layer which interprets them, currently
only for SPI flash. The latter is actually an emulation, and it should be
possible to add more than one emulation - not just SPI flash.

Add a SPI emulation uclass so that other emulations can be plugged in to
support different types of emulated devices on difference buses/chip
Signed-off-by: default avatarSimon Glass <>
Reviewed-by: default avatarJagannadha Sutradharudu Teki <>
parent d7af6a48
......@@ -8,6 +8,7 @@
# There are many options which enable SPI, so make this library available
obj-y += spi-uclass.o
obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
obj-y += spi.o
* Copyright (c) 2014 Google, Inc
* SPDX-License-Identifier: GPL-2.0+
#include <common.h>
#include <dm.h>
#include <spi.h>
#include <spi_flash.h>
UCLASS_DRIVER(spi_emul) = {
.name = "spi_emul",
......@@ -18,6 +18,7 @@ enum uclass_id {
UCLASS_SPI_EMUL, /* sandbox SPI device emulator */
/* U-Boot uclasses start here */
UCLASS_GPIO, /* Bank of general-purpose I/O pins */
......@@ -456,6 +456,35 @@ struct dm_spi_ops {
int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
struct dm_spi_emul_ops {
* SPI transfer
* This writes "bitlen" bits out the SPI MOSI port and simultaneously
* clocks "bitlen" bits in the SPI MISO port. That's just the way SPI
* works. Here the device is a slave.
* The source of the outgoing bits is the "dout" parameter and the
* destination of the input bits is the "din" parameter. Note that
* "dout" and "din" can point to the same memory location, in which
* case the input data overwrites the output data (since both are
* buffered by temporary variables, this is OK).
* spi_xfer() interface:
* @slave: The SPI slave which will be sending/receiving the data.
* @bitlen: How many bits to write and read.
* @dout: Pointer to a string of bits sent to the device. The
* bits are held in a byte array and are sent MSB first.
* @din: Pointer to a string of bits that will be sent back to
* the master.
* @flags: A bitwise combination of SPI_XFER_* flags.
* Returns: 0 on success, not -1 on failure
int (*xfer)(struct udevice *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags);
* spi_find_bus_and_cs() - Find bus and slave devices by number
......@@ -545,12 +574,28 @@ int spi_ofdata_to_platdata(const void *blob, int node, struct spi_slave *spi);
int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info);
struct sandbox_state;
* sandbox_spi_get_emul() - get an emulator for a SPI slave
* This provides a way to attach an emulated SPI device to a particular SPI
* slave, so that xfer() operations on the slave will be handled by the
* emulator. If a emulator already exists on that chip select it is returned.
* Otherwise one is created.
* @state: Sandbox state
* @bus: SPI bus requesting the emulator
* @slave: SPI slave device requesting the emulator
* @emuip: Returns pointer to emulator
* @return 0 if OK, -ve on error
int sandbox_spi_get_emul(struct sandbox_state *state,
struct udevice *bus, struct udevice *slave,
struct udevice **emulp);
/* Access the serial operations for a device */
#define spi_get_ops(dev) ((struct dm_spi_ops *)(dev)->driver->ops)
#define spi_emul_get_ops(dev) ((struct dm_spi_emul_ops *)(dev)->driver->ops)
#endif /* CONFIG_DM_SPI */
#endif /* _SPI_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment