diff options
Diffstat (limited to 'roms/u-boot/drivers/spi/spi-mem-nodm.c')
-rw-r--r-- | roms/u-boot/drivers/spi/spi-mem-nodm.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/spi/spi-mem-nodm.c b/roms/u-boot/drivers/spi/spi-mem-nodm.c new file mode 100644 index 000000000..765f05fe5 --- /dev/null +++ b/roms/u-boot/drivers/spi/spi-mem-nodm.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <spi-mem.h> + +int spi_mem_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + unsigned int pos = 0; + const u8 *tx_buf = NULL; + u8 *rx_buf = NULL; + u8 *op_buf; + int op_len; + u32 flag; + int ret; + int i; + + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) + rx_buf = op->data.buf.in; + else + tx_buf = op->data.buf.out; + } + + op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + op_buf = calloc(1, op_len); + + ret = spi_claim_bus(slave); + if (ret < 0) + return ret; + + op_buf[pos++] = op->cmd.opcode; + + if (op->addr.nbytes) { + for (i = 0; i < op->addr.nbytes; i++) + op_buf[pos + i] = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + + pos += op->addr.nbytes; + } + + if (op->dummy.nbytes) + memset(op_buf + pos, 0xff, op->dummy.nbytes); + + /* 1st transfer: opcode + address + dummy cycles */ + flag = SPI_XFER_BEGIN; + /* Make sure to set END bit if no tx or rx data messages follow */ + if (!tx_buf && !rx_buf) + flag |= SPI_XFER_END; + + ret = spi_xfer(slave, op_len * 8, op_buf, NULL, flag); + if (ret) + return ret; + + /* 2nd transfer: rx or tx data path */ + if (tx_buf || rx_buf) { + ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf, + rx_buf, SPI_XFER_END); + if (ret) + return ret; + } + + spi_release_bus(slave); + + for (i = 0; i < pos; i++) + debug("%02x ", op_buf[i]); + debug("| [%dB %s] ", + tx_buf || rx_buf ? op->data.nbytes : 0, + tx_buf || rx_buf ? (tx_buf ? "out" : "in") : "-"); + for (i = 0; i < op->data.nbytes; i++) + debug("%02x ", tx_buf ? tx_buf[i] : rx_buf[i]); + debug("[ret %d]\n", ret); + + free(op_buf); + + if (ret < 0) + return ret; + + return 0; +} + +int spi_mem_adjust_op_size(struct spi_slave *slave, + struct spi_mem_op *op) +{ + unsigned int len; + + len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + if (slave->max_write_size && len > slave->max_write_size) + return -EINVAL; + + if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) + op->data.nbytes = min(op->data.nbytes, + slave->max_read_size); + else if (slave->max_write_size) + op->data.nbytes = min(op->data.nbytes, + slave->max_write_size - len); + + if (!op->data.nbytes) + return -EINVAL; + + return 0; +} |