diff options
Diffstat (limited to 'drivers/spi/sandbox_spi.c')
-rw-r--r-- | drivers/spi/sandbox_spi.c | 200 |
1 files changed, 74 insertions, 126 deletions
diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c index 12e9bdad38..e717424db8 100644 --- a/drivers/spi/sandbox_spi.c +++ b/drivers/spi/sandbox_spi.c @@ -9,26 +9,23 @@ */ #include <common.h> +#include <dm.h> #include <malloc.h> #include <spi.h> +#include <spi_flash.h> #include <os.h> #include <asm/errno.h> #include <asm/spi.h> #include <asm/state.h> +#include <dm/device-internal.h> + +DECLARE_GLOBAL_DATA_PTR; #ifndef CONFIG_SPI_IDLE_VAL # define CONFIG_SPI_IDLE_VAL 0xFF #endif -struct sandbox_spi_slave { - struct spi_slave slave; - const struct sandbox_spi_emu_ops *ops; - void *priv; -}; - -#define to_sandbox_spi_slave(s) container_of(s, struct sandbox_spi_slave, slave) - const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus, unsigned long *cs) { @@ -45,120 +42,52 @@ const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus, return endp + 1; } -int spi_cs_is_valid(unsigned int bus, unsigned int cs) -{ - return bus < CONFIG_SANDBOX_SPI_MAX_BUS && - cs < CONFIG_SANDBOX_SPI_MAX_CS; -} - -void spi_cs_activate(struct spi_slave *slave) -{ - struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); - - debug("sandbox_spi: activating CS\n"); - if (sss->ops->cs_activate) - sss->ops->cs_activate(sss->priv); -} - -void spi_cs_deactivate(struct spi_slave *slave) -{ - struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); - - debug("sandbox_spi: deactivating CS\n"); - if (sss->ops->cs_deactivate) - sss->ops->cs_deactivate(sss->priv); -} - -void spi_init(void) -{ -} - -void spi_set_speed(struct spi_slave *slave, uint hz) +__weak int sandbox_spi_get_emul(struct sandbox_state *state, + struct udevice *bus, struct udevice *slave, + struct udevice **emulp) { + return -ENOENT; } -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) +static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { - struct sandbox_spi_slave *sss; + struct udevice *bus = slave->parent; struct sandbox_state *state = state_get_current(); - const char *spec; - - if (!spi_cs_is_valid(bus, cs)) { - debug("sandbox_spi: Invalid SPI bus/cs\n"); - return NULL; - } - - sss = spi_alloc_slave(struct sandbox_spi_slave, bus, cs); - if (!sss) { - debug("sandbox_spi: Out of memory\n"); - return NULL; - } - - spec = state->spi[bus][cs].spec; - sss->ops = state->spi[bus][cs].ops; - if (!spec || !sss->ops || sss->ops->setup(&sss->priv, spec)) { - free(sss); - printf("sandbox_spi: unable to locate a slave client\n"); - return NULL; - } - - return &sss->slave; -} - -void spi_free_slave(struct spi_slave *slave) -{ - struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); - - debug("sandbox_spi: releasing slave\n"); - - if (sss->ops->free) - sss->ops->free(sss->priv); - - free(sss); -} - -static int spi_bus_claim_cnt[CONFIG_SANDBOX_SPI_MAX_BUS]; - -int spi_claim_bus(struct spi_slave *slave) -{ - if (spi_bus_claim_cnt[slave->bus]++) { - printf("sandbox_spi: error: bus already claimed: %d!\n", - spi_bus_claim_cnt[slave->bus]); - } - - return 0; -} - -void spi_release_bus(struct spi_slave *slave) -{ - if (--spi_bus_claim_cnt[slave->bus]) { - printf("sandbox_spi: error: bus freed too often: %d!\n", - spi_bus_claim_cnt[slave->bus]); - } -} - -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, - void *din, unsigned long flags) -{ - struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); + struct dm_spi_emul_ops *ops; + struct udevice *emul; uint bytes = bitlen / 8, i; - int ret = 0; + int ret; u8 *tx = (void *)dout, *rx = din; + uint busnum, cs; if (bitlen == 0) - goto done; + return 0; /* we can only do 8 bit transfers */ if (bitlen % 8) { printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n", bitlen); - flags |= SPI_XFER_END; - goto done; + return -EINVAL; } - if (flags & SPI_XFER_BEGIN) - spi_cs_activate(slave); + busnum = bus->seq; + cs = spi_chip_select(slave); + if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS || + cs >= CONFIG_SANDBOX_SPI_MAX_CS) { + printf("%s: busnum=%u, cs=%u: out of range\n", __func__, + busnum, cs); + return -ENOENT; + } + ret = sandbox_spi_get_emul(state, bus, slave, &emul); + if (ret) { + printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n", + __func__, busnum, cs, ret); + return -ENOENT; + } + ret = device_probe(emul); + if (ret) + return ret; /* make sure rx/tx buffers are full so clients can assume */ if (!tx) { @@ -178,12 +107,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, } } - debug("sandbox_spi: xfer: bytes = %u\n tx:", bytes); - for (i = 0; i < bytes; ++i) - debug(" %u:%02x", i, tx[i]); - debug("\n"); - - ret = sss->ops->xfer(sss->priv, tx, rx, bytes); + ops = spi_emul_get_ops(emul); + ret = ops->xfer(emul, bitlen, dout, din, flags); debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:", ret, ret ? "bad" : "good"); @@ -196,22 +121,45 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, if (rx != din) free(rx); - done: - if (flags & SPI_XFER_END) - spi_cs_deactivate(slave); - return ret; } -/** - * Set up a new SPI slave for an fdt node - * - * @param blob Device tree blob - * @param node SPI peripheral node to use - * @return 0 if ok, -1 on error - */ -struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, - int spi_node) +static int sandbox_spi_set_speed(struct udevice *bus, uint speed) +{ + return 0; +} + +static int sandbox_spi_set_mode(struct udevice *bus, uint mode) +{ + return 0; +} + +static int sandbox_cs_info(struct udevice *bus, uint cs, + struct spi_cs_info *info) { - return NULL; + /* Always allow activity on CS 0 */ + if (cs >= 1) + return -ENODEV; + + return 0; } + +static const struct dm_spi_ops sandbox_spi_ops = { + .xfer = sandbox_spi_xfer, + .set_speed = sandbox_spi_set_speed, + .set_mode = sandbox_spi_set_mode, + .cs_info = sandbox_cs_info, +}; + +static const struct udevice_id sandbox_spi_ids[] = { + { .compatible = "sandbox,spi" }, + { } +}; + +U_BOOT_DRIVER(spi_sandbox) = { + .name = "spi_sandbox", + .id = UCLASS_SPI, + .of_match = sandbox_spi_ids, + .per_child_auto_alloc_size = sizeof(struct spi_slave), + .ops = &sandbox_spi_ops, +}; |