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; }
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; }