summaryrefslogtreecommitdiff
path: root/fts_lib/ftsIO.c
diff options
context:
space:
mode:
Diffstat (limited to 'fts_lib/ftsIO.c')
-rw-r--r--fts_lib/ftsIO.c924
1 files changed, 924 insertions, 0 deletions
diff --git a/fts_lib/ftsIO.c b/fts_lib/ftsIO.c
new file mode 100644
index 0000000..9443fdd
--- /dev/null
+++ b/fts_lib/ftsIO.c
@@ -0,0 +1,924 @@
+/*
+ *
+ **************************************************************************
+ ** STMicroelectronics **
+ **************************************************************************
+ ** marco.cali@st.com **
+ **************************************************************************
+ * *
+ * I2C/SPI Communication *
+ * *
+ **************************************************************************
+ **************************************************************************
+ *
+ */
+
+/*!
+ * \file ftsIO.c
+ * \brief Contains all the functions which handle with the I2C/SPI
+ *communication
+ */
+
+
+#include "ftsSoftware.h"
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/of_gpio.h>
+
+#ifdef I2C_INTERFACE
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+static u16 I2CSAD; /* /< slave address of the IC in the i2c bus */
+#else
+#include <linux/spi/spidev.h>
+#endif
+
+static void *client; /* /< bus client retrived by the OS and
+ * used to execute the bus transfers */
+
+
+
+#include "ftsCore.h"
+#include "ftsError.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+
+
+/**
+ * Initialize the static client variable of the fts_lib library in order
+ * to allow any i2c/spi transaction in the driver (Must be called in the probe)
+ * @param clt pointer to i2c_client or spi_device struct which identify the bus
+ * slave device
+ * @return OK
+ */
+int openChannel(void *clt)
+{
+ client = clt;
+#ifdef I2C_INTERFACE
+ I2CSAD = ((struct i2c_client *)clt)->addr;
+ pr_info("openChannel: SAD: %02X\n", I2CSAD);
+#else
+ pr_info("%s: spi_master: flags = %04X !\n", __func__,
+ ((struct spi_device *)client)->master->flags);
+ pr_info("%s: spi_device: max_speed = %d chip select = %02X bits_per_words = %d mode = %04X !\n",
+ __func__, ((struct spi_device *)client)->max_speed_hz,
+ ((struct spi_device *)client)->chip_select,
+ ((struct spi_device *)client)->bits_per_word,
+ ((struct spi_device *)client)->mode);
+ pr_info("openChannel: completed!\n");
+#endif
+ return OK;
+}
+
+#ifdef I2C_INTERFACE
+/**
+ * Change the I2C slave address which will be used during the transaction
+ * (For Debug Only)
+ * @param sad new slave address id
+ * @return OK
+ */
+int changeSAD(u8 sad)
+{
+ I2CSAD = sad;
+ return OK;
+}
+#endif
+
+
+/**
+ * Retrieve the pointer to the device struct of the IC
+ * @return a the device struct pointer if client was previously set
+ * or NULL in all the other cases
+ */
+struct device *getDev(void)
+{
+ if (client != NULL)
+ return &(getClient()->dev);
+ else
+ return NULL;
+}
+
+
+#ifdef I2C_INTERFACE
+/**
+ * Retrieve the pointer of the i2c_client struct representing the IC as i2c
+ * slave
+ * @return client if it was previously set or NULL in all the other cases
+ */
+struct i2c_client *getClient()
+{
+ if (client != NULL)
+ return (struct i2c_client *)client;
+ else
+ return NULL;
+}
+#else
+/**
+ * Retrieve the pointer of the spi_device struct representing the IC as spi
+ * slave
+ * @return client if it was previously set or NULL in all the other cases
+ */
+struct spi_device *getClient()
+{
+ if (client != NULL)
+ return (struct spi_device *)client;
+ else
+ return NULL;
+}
+#endif
+
+struct fts_ts_info *getDrvInfo(void)
+{
+ struct device *dev = getDev();
+ struct fts_ts_info *info = NULL;
+
+ if (dev != NULL)
+ info = dev_get_drvdata(dev);
+ return info;
+}
+
+/****************** New I2C API *********************/
+
+/**
+ * Perform a direct bus read
+ * @param outBuf pointer of a byte array which should contain the byte read
+ * from the IC
+ * @param byteToRead number of bytes to read
+ * @return OK if success or an error code which specify the type of error
+ */
+static int fts_read_internal(u8 *outBuf, int byteToRead, bool dma_safe)
+{
+ int ret = -1;
+ int retry = 0;
+ struct fts_ts_info *info = getDrvInfo();
+#ifdef I2C_INTERFACE
+ struct i2c_msg I2CMsg[1];
+#else
+ struct spi_message msg;
+ struct spi_transfer transfer[1] = { { 0 } };
+#endif
+
+ if (dma_safe == false && byteToRead > sizeof(info->io_read_buf)) {
+ pr_err("%s: preallocated buffers are too small!\n", __func__);
+ return ERROR_ALLOC;
+ }
+
+#ifdef I2C_INTERFACE
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)I2C_M_RD;
+ I2CMsg[0].len = (__u16)byteToRead;
+ if (dma_safe == false)
+ I2CMsg[0].buf = (__u8 *)info->io_read_buf;
+ else
+ I2CMsg[0].buf = (__u8 *)outBuf;
+#else
+ spi_message_init(&msg);
+
+ transfer[0].len = byteToRead;
+ transfer[0].delay_usecs = SPI_DELAY_CS;
+ transfer[0].tx_buf = NULL;
+ if (dma_safe == false)
+ transfer[0].rx_buf = info->io_read_buf;
+ else
+ transfer[0].rx_buf = outBuf;
+ spi_message_add_tail(&transfer[0], &msg);
+#endif
+
+ if (client == NULL)
+ return ERROR_BUS_O;
+ while (retry < I2C_RETRY && ret < OK) {
+#ifdef I2C_INTERFACE
+ ret = i2c_transfer(getClient()->adapter, I2CMsg, 1);
+#else
+ ret = spi_sync(getClient(), &msg);
+#endif
+
+ retry++;
+ if (ret < OK)
+ mdelay(I2C_WAIT_BEFORE_RETRY);
+ /* pr_err("fts_writeCmd: attempt %d\n", retry); */
+ }
+ if (ret < 0) {
+ pr_err("%s: ERROR %08X\n", __func__, ERROR_BUS_R);
+ return ERROR_BUS_R;
+ }
+
+ if (dma_safe == false)
+ memcpy(outBuf, info->io_read_buf, byteToRead);
+
+ return OK;
+}
+
+
+/**
+ * Perform a bus write followed by a bus read without a stop condition
+ * @param cmd byte array containing the command to write
+ * @param cmdLength size of cmd
+ * @param outBuf pointer of a byte array which should contain the bytes read
+ * from the IC
+ * @param byteToRead number of bytes to read
+ * @return OK if success or an error code which specify the type of error
+ */
+static int fts_writeRead_internal(u8 *cmd, int cmdLength, u8 *outBuf,
+ int byteToRead, bool dma_safe)
+{
+ int ret = -1;
+ int retry = 0;
+ struct fts_ts_info *info = getDrvInfo();
+#ifdef I2C_INTERFACE
+ struct i2c_msg I2CMsg[2];
+#else
+ struct spi_message msg;
+ struct spi_transfer transfer[2] = { { 0 }, { 0 } };
+#endif
+
+ if (dma_safe == false && (cmdLength > sizeof(info->io_write_buf) ||
+ byteToRead > sizeof(info->io_read_buf))) {
+ pr_err("%s: preallocated buffers are too small!\n", __func__);
+ return ERROR_ALLOC;
+ }
+
+#ifdef I2C_INTERFACE
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, cmd, cmdLength);
+ cmd = info->io_write_buf;
+ }
+
+ /* write msg */
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ /* read msg */
+ I2CMsg[1].addr = (__u16)I2CSAD;
+ I2CMsg[1].flags = I2C_M_RD;
+ I2CMsg[1].len = byteToRead;
+ if (dma_safe == false)
+ I2CMsg[1].buf = (__u8 *)info->io_read_buf;
+ else
+ I2CMsg[1].buf = (__u8 *)outBuf;
+#else
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, cmd, cmdLength);
+ cmd = info->io_write_buf;
+ }
+
+ spi_message_init(&msg);
+
+ transfer[0].len = cmdLength;
+ transfer[0].tx_buf = cmd;
+ transfer[0].rx_buf = NULL;
+ spi_message_add_tail(&transfer[0], &msg);
+
+ transfer[1].len = byteToRead;
+ transfer[1].delay_usecs = SPI_DELAY_CS;
+ transfer[1].tx_buf = NULL;
+ if (dma_safe == false)
+ transfer[1].rx_buf = info->io_read_buf;
+ else
+ transfer[1].rx_buf = outBuf;
+ spi_message_add_tail(&transfer[1], &msg);
+
+#endif
+
+ if (client == NULL)
+ return ERROR_BUS_O;
+
+ while (retry < I2C_RETRY && ret < OK) {
+#ifdef I2C_INTERFACE
+ ret = i2c_transfer(getClient()->adapter, I2CMsg, 2);
+#else
+ ret = spi_sync(getClient(), &msg);
+#endif
+
+ retry++;
+ if (ret < OK)
+ mdelay(I2C_WAIT_BEFORE_RETRY);
+ }
+ if (ret < 0) {
+ pr_err("%s: ERROR %08X\n", __func__, ERROR_BUS_WR);
+ return ERROR_BUS_WR;
+ }
+
+ if (dma_safe == false)
+ memcpy(outBuf, info->io_read_buf, byteToRead);
+
+ return OK;
+}
+
+
+/**
+ * Perform a bus write
+ * @param cmd byte array containing the command to write
+ * @param cmdLength size of cmd
+ * @return OK if success or an error code which specify the type of error
+ */
+static int fts_write_internal(u8 *cmd, int cmdLength, bool dma_safe)
+{
+ int ret = -1;
+ int retry = 0;
+ struct fts_ts_info *info = getDrvInfo();
+#ifdef I2C_INTERFACE
+ struct i2c_msg I2CMsg[1];
+#else
+ struct spi_message msg;
+ struct spi_transfer transfer[1] = { { 0 } };
+#endif
+
+ if (dma_safe == false && cmdLength > sizeof(info->io_write_buf)) {
+ pr_err("%s: preallocated buffers are too small!\n", __func__);
+ return ERROR_ALLOC;
+ }
+
+#ifdef I2C_INTERFACE
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, cmd, cmdLength);
+ cmd = info->io_write_buf;
+ }
+
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+#else
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, cmd, cmdLength);
+ cmd = info->io_write_buf;
+ }
+
+ spi_message_init(&msg);
+
+ transfer[0].len = cmdLength;
+ transfer[0].delay_usecs = SPI_DELAY_CS;
+ transfer[0].tx_buf = cmd;
+ transfer[0].rx_buf = NULL;
+ spi_message_add_tail(&transfer[0], &msg);
+#endif
+
+
+ if (client == NULL)
+ return ERROR_BUS_O;
+ while (retry < I2C_RETRY && ret < OK) {
+#ifdef I2C_INTERFACE
+ ret = i2c_transfer(getClient()->adapter, I2CMsg, 1);
+#else
+ ret = spi_sync(getClient(), &msg);
+#endif
+
+ retry++;
+ if (ret < OK)
+ mdelay(I2C_WAIT_BEFORE_RETRY);
+ /* pr_err("fts_writeCmd: attempt %d\n", retry); */
+ }
+ if (ret < 0) {
+ pr_err("%s: ERROR %08X\n", __func__, ERROR_BUS_W);
+ return ERROR_BUS_W;
+ }
+ return OK;
+}
+
+/**
+ * Write a FW command to the IC and check automatically the echo event
+ * @param cmd byte array containing the command to send
+ * @param cmdLength size of cmd
+ * @return OK if success, or an error code which specify the type of error
+ */
+static int fts_writeFwCmd_internal(u8 *cmd, int cmdLength, bool dma_safe)
+{
+ int ret = -1;
+ int ret2 = -1;
+ int retry = 0;
+ struct fts_ts_info *info = getDrvInfo();
+#ifdef I2C_INTERFACE
+ struct i2c_msg I2CMsg[1];
+#else
+ struct spi_message msg;
+ struct spi_transfer transfer[1] = { { 0 } };
+#endif
+
+ if (dma_safe == false && cmdLength > sizeof(info->io_write_buf)) {
+ pr_err("%s: preallocated buffers are too small!\n", __func__);
+ return ERROR_ALLOC;
+ }
+
+#ifdef I2C_INTERFACE
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, cmd, cmdLength);
+ cmd = info->io_write_buf;
+ }
+
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+#else
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, cmd, cmdLength);
+ cmd = info->io_write_buf;
+ }
+
+ spi_message_init(&msg);
+
+ transfer[0].len = cmdLength;
+ transfer[0].delay_usecs = SPI_DELAY_CS;
+ transfer[0].tx_buf = cmd;
+ transfer[0].rx_buf = NULL;
+ spi_message_add_tail(&transfer[0], &msg);
+#endif
+
+ if (client == NULL)
+ return ERROR_BUS_O;
+ resetErrorList();
+ while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) {
+#ifdef I2C_INTERFACE
+ ret = i2c_transfer(getClient()->adapter, I2CMsg, 1);
+#else
+ ret = spi_sync(getClient(), &msg);
+#endif
+ retry++;
+ if (ret >= 0)
+ ret2 = checkEcho(cmd, cmdLength);
+ if (ret < OK || ret2 < OK)
+ mdelay(I2C_WAIT_BEFORE_RETRY);
+ /* pr_err("fts_writeCmd: attempt %d\n", retry); */
+ }
+ if (ret < 0) {
+ pr_err("fts_writeFwCmd: ERROR %08X\n", ERROR_BUS_W);
+ return ERROR_BUS_W;
+ }
+ if (ret2 < OK) {
+ pr_err("fts_writeFwCmd: check echo ERROR %08X\n", ret2);
+ return ret2;
+ }
+ return OK;
+}
+
+
+/**
+ * Perform two bus write and one bus read without any stop condition
+ * In case of FTI this function is not supported and the same sequence
+ * can be achieved calling fts_write followed by an fts_writeRead.
+ * @param writeCmd1 byte array containing the first command to write
+ * @param writeCmdLength size of writeCmd1
+ * @param readCmd1 byte array containing the second command to write
+ * @param readCmdLength size of readCmd1
+ * @param outBuf pointer of a byte array which should contain the bytes read
+ * from the IC
+ * @param byteToRead number of bytes to read
+ * @return OK if success or an error code which specify the type of error
+ */
+static int fts_writeThenWriteRead_internal(u8 *writeCmd1, int writeCmdLength,
+ u8 *readCmd1, int readCmdLength,
+ u8 *outBuf, int byteToRead,
+ bool dma_safe)
+{
+ int ret = -1;
+ int retry = 0;
+ struct fts_ts_info *info = getDrvInfo();
+#ifdef I2C_INTERFACE
+ struct i2c_msg I2CMsg[3];
+#else
+ struct spi_message msg;
+ struct spi_transfer transfer[3] = { { 0 }, { 0 }, { 0 } };
+#endif
+
+ if (dma_safe == false && (writeCmdLength > sizeof(info->io_write_buf) ||
+ readCmdLength > sizeof(info->io_extra_write_buf) ||
+ byteToRead > sizeof(info->io_read_buf))) {
+ pr_err("%s: preallocated buffers are too small!\n", __func__);
+ return ERROR_ALLOC;
+ }
+
+#ifdef I2C_INTERFACE
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, writeCmd1, writeCmdLength);
+ writeCmd1 = info->io_write_buf;
+ memcpy(info->io_extra_write_buf, readCmd1, readCmdLength);
+ readCmd1 = info->io_extra_write_buf;
+ }
+
+ /* write msg */
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)writeCmdLength;
+ I2CMsg[0].buf = (__u8 *)writeCmd1;
+
+ /* write msg */
+ I2CMsg[1].addr = (__u16)I2CSAD;
+ I2CMsg[1].flags = (__u16)0;
+ I2CMsg[1].len = (__u16)readCmdLength;
+ I2CMsg[1].buf = (__u8 *)readCmd1;
+
+ /* read msg */
+ I2CMsg[2].addr = (__u16)I2CSAD;
+ I2CMsg[2].flags = I2C_M_RD;
+ I2CMsg[2].len = byteToRead;
+ if (dma_safe == false)
+ I2CMsg[2].buf = (__u8 *)info->io_read_buf;
+ else
+ I2CMsg[2].buf = (__u8 *)outBuf;
+#else
+ if (dma_safe == false) {
+ memcpy(info->io_write_buf, writeCmd1, writeCmdLength);
+ writeCmd1 = info->io_write_buf;
+ memcpy(info->io_extra_write_buf, readCmd1, readCmdLength);
+ readCmd1 = info->io_extra_write_buf;
+ }
+
+ spi_message_init(&msg);
+
+ transfer[0].len = writeCmdLength;
+ transfer[0].tx_buf = writeCmd1;
+ transfer[0].rx_buf = NULL;
+ spi_message_add_tail(&transfer[0], &msg);
+
+ transfer[1].len = readCmdLength;
+ transfer[1].tx_buf = readCmd1;
+ transfer[1].rx_buf = NULL;
+ spi_message_add_tail(&transfer[1], &msg);
+
+ transfer[2].len = byteToRead;
+ transfer[2].delay_usecs = SPI_DELAY_CS;
+ transfer[2].tx_buf = NULL;
+ if (dma_safe == false)
+ transfer[2].rx_buf = info->io_read_buf;
+ else
+ transfer[2].rx_buf = outBuf;
+ spi_message_add_tail(&transfer[2], &msg);
+#endif
+
+ if (client == NULL)
+ return ERROR_BUS_O;
+ while (retry < I2C_RETRY && ret < OK) {
+#ifdef I2C_INTERFACE
+ ret = i2c_transfer(getClient()->adapter, I2CMsg, 3);
+#else
+ ret = spi_sync(getClient(), &msg);
+#endif
+ retry++;
+ if (ret < OK)
+ mdelay(I2C_WAIT_BEFORE_RETRY);
+ }
+
+ if (ret < 0) {
+ pr_err("%s: ERROR %08X\n", __func__, ERROR_BUS_WR);
+ return ERROR_BUS_WR;
+ }
+
+ if (dma_safe == false)
+ memcpy(outBuf, info->io_read_buf, byteToRead);
+
+ return OK;
+}
+
+/* Wrapper API for i2c read and write */
+int fts_read(u8 *outBuf, int byteToRead)
+{
+ return fts_read_internal(outBuf, byteToRead, false);
+}
+
+int fts_read_heap(u8 *outBuf, int byteToRead)
+{
+ return fts_read_internal(outBuf, byteToRead, true);
+}
+
+int fts_writeRead(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
+{
+ return fts_writeRead_internal(cmd, cmdLength, outBuf, byteToRead,
+ false);
+}
+
+int fts_writeRead_heap(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
+{
+ return fts_writeRead_internal(cmd, cmdLength, outBuf, byteToRead, true);
+}
+
+int fts_write(u8 *cmd, int cmdLength)
+{
+ return fts_write_internal(cmd, cmdLength, false);
+}
+
+int fts_write_heap(u8 *cmd, int cmdLength)
+{
+ return fts_write_internal(cmd, cmdLength, true);
+}
+
+int fts_writeFwCmd(u8 *cmd, int cmdLength)
+{
+ return fts_writeFwCmd_internal(cmd, cmdLength, false);
+}
+
+int fts_writeFwCmd_heap(u8 *cmd, int cmdLength)
+{
+ return fts_writeFwCmd_internal(cmd, cmdLength, true);
+}
+
+int fts_writeThenWriteRead(u8 *writeCmd1, int writeCmdLength,
+ u8 *readCmd1, int readCmdLength,
+ u8 *outBuf, int byteToRead)
+{
+ return fts_writeThenWriteRead_internal(writeCmd1, writeCmdLength,
+ readCmd1, readCmdLength,
+ outBuf, byteToRead, false);
+}
+
+int fts_writeThenWriteRead_heap(u8 *writeCmd1, int writeCmdLength,
+ u8 *readCmd1, int readCmdLength,
+ u8 *outBuf, int byteToRead)
+{
+ return fts_writeThenWriteRead_internal(writeCmd1, writeCmdLength,
+ readCmd1, readCmdLength,
+ outBuf, byteToRead, true);
+}
+
+/**
+ * Perform a chunked write with one byte op code and 1 to 8 bytes address
+ * @param cmd byte containing the op code to write
+ * @param addrSize address size in byte
+ * @param address the starting address
+ * @param data pointer of a byte array which contain the bytes to write
+ * @param dataSize size of data
+ * @return OK if success or an error code which specify the type of error
+ */
+/* this function works only if the address is max 8 bytes */
+int fts_writeU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *data,
+ int dataSize)
+{
+ u8 *finalCmd;
+ int remaining = dataSize;
+ int toWrite = 0, i = 0;
+ struct fts_ts_info *info = getDrvInfo();
+
+ finalCmd = info->io_write_buf;
+
+ if (addrSize <= sizeof(u64)) {
+ while (remaining > 0) {
+ if (remaining >= WRITE_CHUNK) {
+ toWrite = WRITE_CHUNK;
+ remaining -= WRITE_CHUNK;
+ } else {
+ toWrite = remaining;
+ remaining = 0;
+ }
+
+ finalCmd[0] = cmd;
+ pr_debug("%s: addrSize = %d\n", __func__, addrSize);
+ for (i = 0; i < addrSize; i++) {
+ finalCmd[i + 1] = (u8)((address >> ((addrSize -
+ 1 - i) *
+ 8)) & 0xFF);
+ pr_debug("%s: cmd[%d] = %02X\n",
+ __func__, i + 1, finalCmd[i + 1]);
+ }
+
+ memcpy(&finalCmd[addrSize + 1], data, toWrite);
+
+ if (fts_write_heap(finalCmd, 1 + addrSize + toWrite)
+ < OK) {
+ pr_err(" %s: ERROR %08X\n",
+ __func__, ERROR_BUS_W);
+ return ERROR_BUS_W;
+ }
+
+ address += toWrite;
+
+ data += toWrite;
+ }
+ } else
+ pr_err("%s: address size bigger than max allowed %lu... ERROR %08X\n",
+ __func__, sizeof(u64), ERROR_OP_NOT_ALLOW);
+
+ return OK;
+}
+
+/**
+ * Perform a chunked write read with one byte op code and 1 to 8 bytes address
+ * and dummy byte support.
+ * @param cmd byte containing the op code to write
+ * @param addrSize address size in byte
+ * @param address the starting address
+ * @param outBuf pointer of a byte array which contain the bytes to read
+ * @param byteToRead number of bytes to read
+ * @param hasDummyByte if the first byte of each reading is dummy (must be
+ * skipped)
+ * set to 1, otherwise if it is valid set to 0 (or any other value)
+ * @return OK if success or an error code which specify the type of error
+ */
+int fts_writeReadU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *outBuf,
+ int byteToRead, int hasDummyByte)
+{
+ u8 *finalCmd;
+ u8 *buff;
+ int remaining = byteToRead;
+ int toRead = 0, i = 0;
+ struct fts_ts_info *info = getDrvInfo();
+
+ finalCmd = info->io_write_buf;
+ buff = info->io_read_buf;
+
+ while (remaining > 0) {
+ if (remaining >= READ_CHUNK) {
+ toRead = READ_CHUNK;
+ remaining -= READ_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ finalCmd[0] = cmd;
+ for (i = 0; i < addrSize; i++)
+ finalCmd[i + 1] = (u8)((address >> ((addrSize - 1 - i) *
+ 8)) & 0xFF);
+
+ if (hasDummyByte == 1) {
+ if (fts_writeRead_heap(finalCmd, 1 + addrSize, buff,
+ toRead + 1) < OK) {
+ pr_err("%s: read error... ERROR %08X\n",
+ __func__, ERROR_BUS_WR);
+ return ERROR_BUS_WR;
+ }
+ memcpy(outBuf, buff + 1, toRead);
+ } else {
+ if (fts_writeRead_heap(finalCmd, 1 + addrSize, buff,
+ toRead) < OK) {
+ pr_err("%s: read error... ERROR %08X\n",
+ __func__, ERROR_BUS_WR);
+ return ERROR_BUS_WR;
+ }
+ memcpy(outBuf, buff, toRead);
+ }
+
+ address += toRead;
+
+ outBuf += toRead;
+ }
+
+ return OK;
+}
+
+/**
+ * Perform a chunked write followed by a second write with one byte op code
+ * for each write and 1 to 8 bytes address (the sum of the 2 address size of
+ * the two writes can not exceed 8 bytes)
+ * @param cmd1 byte containing the op code of first write
+ * @param addrSize1 address size in byte of first write
+ * @param cmd2 byte containing the op code of second write
+ * @param addrSize2 address size in byte of second write
+ * @param address the starting address
+ * @param data pointer of a byte array which contain the bytes to write
+ * @param dataSize size of data
+ * @return OK if success or an error code which specify the type of error
+ */
+/* this function works only if the sum of two addresses in the two commands is
+ * max 8 bytes */
+int fts_writeU8UXthenWriteU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2,
+ AddrSize addrSize2, u64 address, u8 *data,
+ int dataSize)
+{
+ u8 *finalCmd1;
+ u8 *finalCmd2;
+ int remaining = dataSize;
+ int toWrite = 0, i = 0;
+ struct fts_ts_info *info = getDrvInfo();
+
+ finalCmd1 = info->io_write_buf;
+ finalCmd2 = info->io_extra_write_buf;
+
+ while (remaining > 0) {
+ if (remaining >= WRITE_CHUNK) {
+ toWrite = WRITE_CHUNK;
+ remaining -= WRITE_CHUNK;
+ } else {
+ toWrite = remaining;
+ remaining = 0;
+ }
+
+ finalCmd1[0] = cmd1;
+ for (i = 0; i < addrSize1; i++)
+ finalCmd1[i + 1] = (u8)((address >> ((addrSize1 +
+ addrSize2 - 1 -
+ i) * 8)) & 0xFF);
+
+ finalCmd2[0] = cmd2;
+ for (i = addrSize1; i < addrSize1 + addrSize2; i++)
+ finalCmd2[i - addrSize1 + 1] = (u8)((address >>
+ ((addrSize1 +
+ addrSize2 - 1 -
+ i) * 8)) & 0xFF);
+
+ memcpy(&finalCmd2[addrSize2 + 1], data, toWrite);
+
+ if (fts_write_heap(finalCmd1, 1 + addrSize1) < OK) {
+ pr_err("%s: first write error... ERROR %08X\n",
+ __func__, ERROR_BUS_W);
+ return ERROR_BUS_W;
+ }
+
+ if (fts_write_heap(finalCmd2, 1 + addrSize2 + toWrite) < OK) {
+ pr_err("%s: second write error... ERROR %08X\n",
+ __func__, ERROR_BUS_W);
+ return ERROR_BUS_W;
+ }
+
+ address += toWrite;
+
+ data += toWrite;
+ }
+
+ return OK;
+}
+
+/**
+ * Perform a chunked write followed by a write read with one byte op code
+ * and 1 to 8 bytes address for each write and dummy byte support.
+ * @param cmd1 byte containing the op code of first write
+ * @param addrSize1 address size in byte of first write
+ * @param cmd2 byte containing the op code of second write read
+ * @param addrSize2 address size in byte of second write read
+ * @param address the starting address
+ * @param outBuf pointer of a byte array which contain the bytes to read
+ * @param byteToRead number of bytes to read
+ * @param hasDummyByte if the first byte of each reading is dummy (must be
+ * skipped) set to 1,
+ * otherwise if it is valid set to 0 (or any other value)
+ * @return OK if success or an error code which specify the type of error
+ */
+/* this function works only if the sum of two addresses in the two commands is
+ * max 8 bytes */
+int fts_writeU8UXthenWriteReadU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2,
+ AddrSize addrSize2, u64 address, u8 *outBuf,
+ int byteToRead, int hasDummyByte)
+{
+ u8 *finalCmd1;
+ u8 *finalCmd2;
+ u8 *buff;
+ int remaining = byteToRead;
+ int toRead = 0, i = 0;
+ struct fts_ts_info *info = getDrvInfo();
+
+ finalCmd1 = info->io_write_buf;
+ finalCmd2 = info->io_extra_write_buf;
+ buff = info->io_read_buf;
+
+ while (remaining > 0) {
+ if (remaining >= READ_CHUNK) {
+ toRead = READ_CHUNK;
+ remaining -= READ_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+
+ finalCmd1[0] = cmd1;
+ for (i = 0; i < addrSize1; i++)
+ finalCmd1[i + 1] = (u8)((address >> ((addrSize1 +
+ addrSize2 - 1 -
+ i) * 8)) & 0xFF);
+
+ finalCmd2[0] = cmd2;
+ for (i = addrSize1; i < addrSize1 + addrSize2; i++)
+ finalCmd2[i - addrSize1 + 1] = (u8)((address >>
+ ((addrSize1 +
+ addrSize2 - 1 -
+ i) * 8)) & 0xFF);
+
+ if (fts_write_heap(finalCmd1, 1 + addrSize1) < OK) {
+ pr_err("%s: first write error... ERROR %08X\n",
+ __func__, ERROR_BUS_W);
+ return ERROR_BUS_W;
+ }
+
+ if (hasDummyByte == 1) {
+ if (fts_writeRead_heap(finalCmd2, 1 + addrSize2, buff,
+ toRead + 1) < OK) {
+ pr_err("%s: read error... ERROR %08X\n",
+ __func__, ERROR_BUS_WR);
+ return ERROR_BUS_WR;
+ }
+ memcpy(outBuf, buff + 1, toRead);
+ } else {
+ if (fts_writeRead_heap(finalCmd2, 1 + addrSize2, buff,
+ toRead) < OK) {
+ pr_err("%s: read error... ERROR %08X\n",
+ __func__, ERROR_BUS_WR);
+ return ERROR_BUS_WR;
+ }
+ memcpy(outBuf, buff, toRead);
+ }
+
+ address += toRead;
+
+ outBuf += toRead;
+ }
+
+ return OK;
+}