static int rmi_spi_xfer()

in rmi4/rmi_spi.c [112:240]


static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi,
			const struct rmi_spi_cmd *cmd, const u8 *tx_buf,
			int tx_len, u8 *rx_buf, int rx_len)
{
	struct spi_device *spi = rmi_spi->spi;
	struct rmi_device_platform_data_spi *spi_data =
					&rmi_spi->xport.pdata.spi_data;
	struct spi_message msg;
	struct spi_transfer *xfer;
	int ret = 0;
	int len;
	int cmd_len = 0;
	int total_tx_len;
	int i;
	u16 addr = cmd->addr;

	spi_message_init(&msg);

	switch (cmd->op) {
	case RMI_SPI_WRITE:
	case RMI_SPI_READ:
		cmd_len += 2;
		break;
	case RMI_SPI_V2_READ_UNIFIED:
	case RMI_SPI_V2_READ_SPLIT:
	case RMI_SPI_V2_WRITE:
		cmd_len += 4;
		break;
	}

	total_tx_len = cmd_len + tx_len;
	len = max(total_tx_len, rx_len);

	if (len > RMI_SPI_XFER_SIZE_LIMIT)
		return -EINVAL;

	if (rmi_spi->xfer_buf_size < len) {
		ret = rmi_spi_manage_pools(rmi_spi, len);
		if (ret < 0)
			return ret;
	}

	if (addr == 0)
		/*
		 * SPI needs an address. Use 0x7FF if we want to keep
		 * reading from the last position of the register pointer.
		 */
		addr = 0x7FF;

	switch (cmd->op) {
	case RMI_SPI_WRITE:
		rmi_spi->tx_buf[0] = (addr >> 8);
		rmi_spi->tx_buf[1] = addr & 0xFF;
		break;
	case RMI_SPI_READ:
		rmi_spi->tx_buf[0] = (addr >> 8) | 0x80;
		rmi_spi->tx_buf[1] = addr & 0xFF;
		break;
	case RMI_SPI_V2_READ_UNIFIED:
		break;
	case RMI_SPI_V2_READ_SPLIT:
		break;
	case RMI_SPI_V2_WRITE:
		rmi_spi->tx_buf[0] = 0x40;
		rmi_spi->tx_buf[1] = (addr >> 8) & 0xFF;
		rmi_spi->tx_buf[2] = addr & 0xFF;
		rmi_spi->tx_buf[3] = tx_len;
		break;
	}

	if (tx_buf)
		memcpy(&rmi_spi->tx_buf[cmd_len], tx_buf, tx_len);

	if (rmi_spi->tx_xfer_count > 1) {
		for (i = 0; i < total_tx_len; i++) {
			xfer = &rmi_spi->tx_xfers[i];
			memset(xfer, 0,	sizeof(struct spi_transfer));
			xfer->tx_buf = &rmi_spi->tx_buf[i];
			xfer->len = 1;
			xfer->delay.value = spi_data->write_delay_us;
			xfer->delay.unit = SPI_DELAY_UNIT_USECS;
			spi_message_add_tail(xfer, &msg);
		}
	} else {
		xfer = rmi_spi->tx_xfers;
		memset(xfer, 0, sizeof(struct spi_transfer));
		xfer->tx_buf = rmi_spi->tx_buf;
		xfer->len = total_tx_len;
		spi_message_add_tail(xfer, &msg);
	}

	rmi_dbg(RMI_DEBUG_XPORT, &spi->dev, "%s: cmd: %s tx_buf len: %d tx_buf: %*ph\n",
		__func__, cmd->op == RMI_SPI_WRITE ? "WRITE" : "READ",
		total_tx_len, total_tx_len, rmi_spi->tx_buf);

	if (rx_buf) {
		if (rmi_spi->rx_xfer_count > 1) {
			for (i = 0; i < rx_len; i++) {
				xfer = &rmi_spi->rx_xfers[i];
				memset(xfer, 0, sizeof(struct spi_transfer));
				xfer->rx_buf = &rmi_spi->rx_buf[i];
				xfer->len = 1;
				xfer->delay.value = spi_data->read_delay_us;
				xfer->delay.unit = SPI_DELAY_UNIT_USECS;
				spi_message_add_tail(xfer, &msg);
			}
		} else {
			xfer = rmi_spi->rx_xfers;
			memset(xfer, 0, sizeof(struct spi_transfer));
			xfer->rx_buf = rmi_spi->rx_buf;
			xfer->len = rx_len;
			spi_message_add_tail(xfer, &msg);
		}
	}

	ret = spi_sync(spi, &msg);
	if (ret < 0) {
		dev_err(&spi->dev, "spi xfer failed: %d\n", ret);
		return ret;
	}

	if (rx_buf) {
		memcpy(rx_buf, rmi_spi->rx_buf, rx_len);
		rmi_dbg(RMI_DEBUG_XPORT, &spi->dev, "%s: (%d) %*ph\n",
			__func__, rx_len, rx_len, rx_buf);
	}

	return 0;
}