static int cyttsp4_spi_xfer(u8 op, struct cyttsp4_spi *ts,
			u16 reg, u8 *buf, int length)
{
	struct device *dev = &ts->client->dev;
	struct spi_message msg;
	struct spi_transfer xfer[2];
	u8 wr_hdr_buf[CY_SPI_MAX_HEADER_BYTES];
	u8 rd_hdr_buf[CY_SPI_MAX_HEADER_BYTES];
	int rc;

	memset(wr_hdr_buf, 0, CY_SPI_MAX_HEADER_BYTES);
	memset(rd_hdr_buf, 0, CY_SPI_MAX_HEADER_BYTES);
	memset(xfer, 0, sizeof(xfer));

	spi_message_init(&msg);

	/* Header buffer */
	xfer[0].tx_buf = wr_hdr_buf;
	xfer[0].rx_buf = rd_hdr_buf;

	switch (op) {
	case CY_SPI_WR_OP:
		if (length + CY_SPI_WR_HEADER_BYTES > CY_SPI_DATA_SIZE) {
			dev_vdbg(dev,
				"%s: length+%d=%d is greater than SPI max=%d\n",
				__func__, CY_SPI_WR_HEADER_BYTES,
				length + CY_SPI_WR_HEADER_BYTES,
				CY_SPI_DATA_SIZE);
			rc = -EINVAL;
			goto cyttsp4_spi_xfer_exit;
		}

		/* Header byte 0 */
		if (reg > 255)
			wr_hdr_buf[0] = CY_SPI_WR_OP + CY_SPI_A8_BIT;
		else
			wr_hdr_buf[0] = CY_SPI_WR_OP;

		/* Header byte 1 */
		wr_hdr_buf[1] = reg % 256;

		xfer[0].len = CY_SPI_WR_HEADER_BYTES;

		spi_message_add_tail(&xfer[0], &msg);

		/* Data buffer */
		if (buf) {
			xfer[1].tx_buf = buf;
			xfer[1].len = length;

			spi_message_add_tail(&xfer[1], &msg);
		}
		break;

	case CY_SPI_RD_OP:
		if (!buf) {
			dev_err(dev, "%s: No read buffer\n", __func__);
			rc = -EINVAL;
			goto cyttsp4_spi_xfer_exit;
		}

		if ((length + CY_SPI_RD_HEADER_BYTES) > CY_SPI_DATA_SIZE) {
			dev_vdbg(dev,
				"%s: length+%d=%d is greater than SPI max=%d\n",
				__func__, CY_SPI_RD_HEADER_BYTES,
				length + CY_SPI_RD_HEADER_BYTES,
				CY_SPI_DATA_SIZE);
			rc = -EINVAL;
			goto cyttsp4_spi_xfer_exit;
		}

		/* Header byte 0 */
		wr_hdr_buf[0] = CY_SPI_RD_OP;

		xfer[0].len = CY_SPI_RD_HEADER_BYTES;

		spi_message_add_tail(&xfer[0], &msg);

		/* Data buffer */
		xfer[1].rx_buf = buf;
		xfer[1].len = length;

		spi_message_add_tail(&xfer[1], &msg);
		break;

	default:
		dev_dbg(dev, "%s: bad op code=%d\n", __func__, op);
		rc = -EINVAL;
		goto cyttsp4_spi_xfer_exit;
	}

	rc = spi_sync(ts->client, &msg);
	if (rc < 0) {
		dev_vdbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
			__func__, rc, xfer[0].len, op);
		/*
		 * do not return here since probably a bad ACK sequence
		 * let the following ACK check handle any errors and
		 * allow silent retries
		 */
	}

	if (rd_hdr_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
		/* signal ACK error so silent retry */
		rc = 1;

		switch (op) {
		case CY_SPI_WR_OP:
			_cyttsp4_spi_pr_buf(ts, wr_hdr_buf,
				CY_SPI_WR_HEADER_BYTES,
				"spi_wr_buf HEAD");
			if (buf)
				_cyttsp4_spi_pr_buf(ts, buf,
					length, "spi_wr_buf DATA");
			break;

		case CY_SPI_RD_OP:
			_cyttsp4_spi_pr_buf(ts, rd_hdr_buf,
				CY_SPI_RD_HEADER_BYTES, "spi_rd_buf HEAD");
			_cyttsp4_spi_pr_buf(ts, buf, length,
				"spi_rd_buf DATA");
			break;

		default:
			/*
			 * should not get here due to error check
			 * in first switch
			 */
			break;
		}
	}

cyttsp4_spi_xfer_exit:
	return rc;
}
예제 #2
0
static int cyttsp4_spi_xfer(u8 op, struct cyttsp4_spi *ts,
	u16 reg, u8 *buf, int length)
{
	struct spi_message msg;
	struct spi_transfer xfer[2];
	int retval;

	memset(ts->wr_buf, 0, length + CY_SPI_WR_HEADER_BYTES);
	memset(ts->rd_buf, 0, length + CY_SPI_RD_HEADER_BYTES);
	memset(xfer, 0, sizeof(xfer));
	spi_message_init(&msg);
	xfer[0].tx_buf = ts->wr_buf;
	xfer[0].rx_buf = ts->rd_buf;
	switch (op) {
	case CY_SPI_WR_OP:
		if ((length + CY_SPI_WR_HEADER_BYTES) > CY_SPI_DATA_SIZE) {
			dev_vdbg(ts->bus_ops.dev,
				"%s: length+%d=%d is greater than SPI max=%d\n",
				__func__, CY_SPI_WR_HEADER_BYTES,
				length + CY_SPI_WR_HEADER_BYTES,
				CY_SPI_DATA_SIZE);
			retval = -EINVAL;
			goto cyttsp4_spi_xfer_exit;
		}
		/* header byte 0 */
		if (reg / (CY_SPI_MAX_REG / 2))
			ts->wr_buf[0] = CY_SPI_WR_OP + CY_SPI_A8_BIT;
		else
			ts->wr_buf[0] = CY_SPI_WR_OP;
		/* header byte 1 */
		ts->wr_buf[1] = reg % (CY_SPI_MAX_REG / 2);
		if (buf != NULL)
			memcpy(&ts->wr_buf[2], buf, length);
		xfer[0].len = length + CY_SPI_WR_HEADER_BYTES;
		spi_message_add_tail(&xfer[0], &msg);
		break;
	case CY_SPI_RD_OP:
		if (buf == NULL) {
			dev_err(ts->bus_ops.dev,
			"%s: read return buf=%p\n", __func__, buf);
			retval = -EINVAL;
			goto cyttsp4_spi_xfer_exit;
		}
		if ((length + CY_SPI_RD_HEADER_BYTES) > CY_SPI_DATA_SIZE) {
			dev_vdbg(ts->bus_ops.dev,
				"%s: length+%d=%d is greater than SPI max=%d\n",
				__func__, CY_SPI_RD_HEADER_BYTES,
				length + CY_SPI_RD_HEADER_BYTES,
				CY_SPI_DATA_SIZE);
			retval = -EINVAL;
			goto cyttsp4_spi_xfer_exit;
		}
		/* header byte 0 */
		ts->wr_buf[0] = CY_SPI_RD_OP;
		xfer[0].len = CY_SPI_RD_HEADER_BYTES;
		spi_message_add_tail(&xfer[0], &msg);
		xfer[1].rx_buf = buf;
		xfer[1].len = length;
		spi_message_add_tail(&xfer[1], &msg);
		break;
	default:
		dev_dbg(ts->bus_ops.dev,
			"%s: bad op code=%d\n", __func__, op);
		retval = -EINVAL;
		goto cyttsp4_spi_xfer_exit;
	}

	retval = spi_sync(ts->spi_client, &msg);
	if (retval < 0) {
		dev_vdbg(ts->bus_ops.dev,
			"%s: spi_sync() error %d, len=%d, op=%d\n",
			__func__, retval, xfer[0].len, op);

		/*
		 * do not return here since probably a bad ACK sequence
		 * let the following ACK check handle any errors and
		 * allow silent retries
		 */
	}

	if (ts->rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
		/* signal ACK error so silent retry */
		retval = 1;
		switch (op) {
		case CY_SPI_WR_OP:
			_cyttsp4_spi_pr_buf(ts, ts->wr_buf,
				length + CY_SPI_WR_HEADER_BYTES, "spi_wr_buf");
			break;
		case CY_SPI_RD_OP:
			_cyttsp4_spi_pr_buf(ts, ts->rd_buf,
				length + CY_SPI_RD_HEADER_BYTES, "spi_rd_buf");
			break;
		default:
			/*
			 * should not get here due to error check
			 * in first switch
			 */
			break;
		}
	} else
		retval = 0;

cyttsp4_spi_xfer_exit:
	return retval;
}