static int zynqmp_qspi_exec_op()

in spi-zynqmp-gqspi.c [935:1075]


static int zynqmp_qspi_exec_op(struct spi_mem *mem,
			       const struct spi_mem_op *op)
{
	struct zynqmp_qspi *xqspi = spi_controller_get_devdata
				    (mem->spi->master);
	int err = 0, i;
	u32 genfifoentry = 0;
	u16 opcode = op->cmd.opcode;
	u64 opaddr;

	dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",
		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
		op->dummy.buswidth, op->data.buswidth);

	mutex_lock(&xqspi->op_lock);
	zynqmp_qspi_config_op(xqspi, mem->spi);
	zynqmp_qspi_chipselect(mem->spi, false);
	genfifoentry |= xqspi->genfifocs;
	genfifoentry |= xqspi->genfifobus;

	if (op->cmd.opcode) {
		reinit_completion(&xqspi->data_completion);
		xqspi->txbuf = &opcode;
		xqspi->rxbuf = NULL;
		xqspi->bytes_to_transfer = op->cmd.nbytes;
		xqspi->bytes_to_receive = 0;
		zynqmp_qspi_write_op(xqspi, op->cmd.buswidth, genfifoentry);
		zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
				   zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
				   GQSPI_CFG_START_GEN_FIFO_MASK);
		zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
				   GQSPI_IER_GENFIFOEMPTY_MASK |
				   GQSPI_IER_TXNOT_FULL_MASK);
		if (!wait_for_completion_timeout
		    (&xqspi->data_completion, msecs_to_jiffies(1000))) {
			err = -ETIMEDOUT;
			goto return_err;
		}
	}

	if (op->addr.nbytes) {
		xqspi->txbuf = &opaddr;
		for (i = 0; i < op->addr.nbytes; i++) {
			*(((u8 *)xqspi->txbuf) + i) = op->addr.val >>
					(8 * (op->addr.nbytes - i - 1));
		}

		reinit_completion(&xqspi->data_completion);
		xqspi->rxbuf = NULL;
		xqspi->bytes_to_transfer = op->addr.nbytes;
		xqspi->bytes_to_receive = 0;
		zynqmp_qspi_write_op(xqspi, op->addr.buswidth, genfifoentry);
		zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
				   zynqmp_gqspi_read(xqspi,
						     GQSPI_CONFIG_OFST) |
				   GQSPI_CFG_START_GEN_FIFO_MASK);
		zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
				   GQSPI_IER_TXEMPTY_MASK |
				   GQSPI_IER_GENFIFOEMPTY_MASK |
				   GQSPI_IER_TXNOT_FULL_MASK);
		if (!wait_for_completion_timeout
		    (&xqspi->data_completion, msecs_to_jiffies(1000))) {
			err = -ETIMEDOUT;
			goto return_err;
		}
	}

	if (op->dummy.nbytes) {
		xqspi->txbuf = NULL;
		xqspi->rxbuf = NULL;
		/*
		 * xqspi->bytes_to_transfer here represents the dummy circles
		 * which need to be sent.
		 */
		xqspi->bytes_to_transfer = op->dummy.nbytes * 8 / op->dummy.buswidth;
		xqspi->bytes_to_receive = 0;
		/*
		 * Using op->data.buswidth instead of op->dummy.buswidth here because
		 * we need to use it to configure the correct SPI mode.
		 */
		zynqmp_qspi_write_op(xqspi, op->data.buswidth,
				     genfifoentry);
		zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
				   zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
				   GQSPI_CFG_START_GEN_FIFO_MASK);
	}

	if (op->data.nbytes) {
		reinit_completion(&xqspi->data_completion);
		if (op->data.dir == SPI_MEM_DATA_OUT) {
			xqspi->txbuf = (u8 *)op->data.buf.out;
			xqspi->rxbuf = NULL;
			xqspi->bytes_to_transfer = op->data.nbytes;
			xqspi->bytes_to_receive = 0;
			zynqmp_qspi_write_op(xqspi, op->data.buswidth,
					     genfifoentry);
			zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
					   zynqmp_gqspi_read
					   (xqspi, GQSPI_CONFIG_OFST) |
					   GQSPI_CFG_START_GEN_FIFO_MASK);
			zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
					   GQSPI_IER_TXEMPTY_MASK |
					   GQSPI_IER_GENFIFOEMPTY_MASK |
					   GQSPI_IER_TXNOT_FULL_MASK);
		} else {
			xqspi->txbuf = NULL;
			xqspi->rxbuf = (u8 *)op->data.buf.in;
			xqspi->bytes_to_receive = op->data.nbytes;
			xqspi->bytes_to_transfer = 0;
			err = zynqmp_qspi_read_op(xqspi, op->data.buswidth,
					    genfifoentry);
			if (err)
				goto return_err;

			zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
					   zynqmp_gqspi_read
					   (xqspi, GQSPI_CONFIG_OFST) |
					   GQSPI_CFG_START_GEN_FIFO_MASK);
			if (xqspi->mode == GQSPI_MODE_DMA) {
				zynqmp_gqspi_write
					(xqspi, GQSPI_QSPIDMA_DST_I_EN_OFST,
					 GQSPI_QSPIDMA_DST_I_EN_DONE_MASK);
			} else {
				zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
						   GQSPI_IER_GENFIFOEMPTY_MASK |
						   GQSPI_IER_RXNEMPTY_MASK |
						   GQSPI_IER_RXEMPTY_MASK);
			}
		}
		if (!wait_for_completion_timeout
		    (&xqspi->data_completion, msecs_to_jiffies(1000)))
			err = -ETIMEDOUT;
	}

return_err:

	zynqmp_qspi_chipselect(mem->spi, true);
	mutex_unlock(&xqspi->op_lock);

	return err;
}