// SPDX-License-Identifier: GPL-2.0-only /* * FTS Capacitive touch screen controller (FingerTipS) * * Copyright (C) 2016-2019, STMicroelectronics Limited. * Authors: AMG(Analog Mems Group) * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ /** * ************************************************************************** ** STMicroelectronics ** ************************************************************************** ** marco.cali@st.com ** ************************************************************************** * * * FTS functions for getting frames * * * ************************************************************************** ************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include "ftsCrossCompile.h" #include "ftsCompensation.h" #include "ftsError.h" #include "ftsFrame.h" #include "ftsHardware.h" #include "ftsIO.h" #include "ftsSoftware.h" #include "ftsTool.h" #include "ftsTime.h" #include "../fts.h" static char tag[8] = "[ FTS ]\0"; static int sense_len, force_len; int getOffsetFrame(u16 address, u16 *offset) { u8 data[2]; u8 cmd = { FTS_CMD_FRAMEBUFFER_R }; char *temp = NULL; if (readCmdU16(cmd, address, data, OFFSET_LENGTH, DUMMY_FRAMEBUFFER) < 0) { logError(1, "%s %S: ERROR %02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } u8ToU16(data, offset); temp = printHex("Offest = ", data, OFFSET_LENGTH); if (temp != NULL) logError(0, "%s %s", tag, temp); kfree(temp); return OK; } int getChannelsLength(void) { int ret; u8 *data = (u8 *)kmalloc_array(2, sizeof(u8), GFP_KERNEL); if (data == NULL) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = readB2(ADDR_SENSE_LEN, data, 2); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_READ_B2); kfree(data); return (ret|ERROR_READ_B2); } sense_len = (int)data[0]; force_len = (int)data[1]; logError(0, "%s Force_len = %d Sense_Len = %d\n", tag, force_len, sense_len); kfree(data); return OK; } int getFrameData(u16 address, int size, short **frame) { int i, j, ret; u8 *data = (u8 *)kmalloc_array(size, sizeof(u8), GFP_KERNEL); if (data == NULL) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); kfree(data); return ERROR_I2C_R; } j = 0; for (i = 0; i < size; i += 2) { (*frame)[j] = (short)((data[i + 1] << 8) + data[i]); j++; } kfree(data); return OK; } int getMSFrame(u16 type, struct MutualSenseFrame *frame, int keep_first_row) { u16 offset; int ret; if (getSenseLen() == 0 || getForceLen() == 0) { ret = getChannelsLength(); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_CH_LEN); return (ret|ERROR_CH_LEN); } } ret = getOffsetFrame(type, &offset); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_GET_OFFSET); return (ret | ERROR_GET_OFFSET); } switch (type) { case ADDR_RAW_TOUCH: case ADDR_FILTER_TOUCH: case ADDR_NORM_TOUCH: case ADDR_CALIB_TOUCH: if (keep_first_row == 1) { frame->node_data_size = ((force_len + 1) * sense_len); frame->header.force_node = force_len + 1; } else { frame->node_data_size = ((force_len) * sense_len); offset += (sense_len * BYTES_PER_NODE); frame->header.force_node = force_len; } frame->header.sense_node = sense_len; break; case ADDR_NORM_MS_KEY: case ADDR_RAW_MS_KEY: frame->header.force_node = 1; frame->header.sense_node = ftsInfo.u8_msKeyLen; frame->node_data_size = ftsInfo.u8_msKeyLen; break; default: logError(1, "%s %s: ERROR % 02X\n", tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } frame->node_data = (short *)kmalloc_array(frame->node_data_size, sizeof(short), GFP_KERNEL); if (frame->node_data == NULL) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = getFrameData(offset, frame->node_data_size * BYTES_PER_NODE, &(frame->node_data)); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_GET_FRAME_DATA); kfree(frame->node_data); return (ret | ERROR_GET_FRAME_DATA); } // if you want to access one node i,j, //you should compute the offset like: //offset = i * columns + j => frame[i, j] logError(0, "%s Frame acquired!\n", tag); //return the number of data put inside frame return frame->node_data_size; } int getSenseLen(void) { int ret; if (sense_len != 0) return sense_len; if (ftsInfo.u8_scrSenseLen != 0) { sense_len = ftsInfo.u8_scrSenseLen; } else { ret = getChannelsLength(); if (ret < OK) return ret; } return sense_len; } int getForceLen(void) { int ret; if (force_len != 0) return force_len; if (ftsInfo.u8_scrForceLen != 0) { force_len = ftsInfo.u8_scrForceLen; } else { ret = getChannelsLength(); if (ret < OK) return ret; } return force_len; } int requestFrame(u16 type) { int retry = 0; int ret; u16 answer; char *temp = NULL; int event_to_search[1]; u8 readEvent[FIFO_EVENT_SIZE]; u8 cmd[3] = { FTS_CMD_REQU_FRAME_DATA, 0x00, 0x00}; // B7 is the command for asking frame data event_to_search[0] = (int)EVENTID_FRAME_DATA_READ; u16ToU8(type, &cmd[1]); while (retry < FRAME_DATA_READ_RETRY) { temp = printHex("Command = ", cmd, 3); if (temp != NULL) logError(0, "%s %s", tag, temp); kfree(temp); //send the request to the chip to load in memory the Frame Data ret = fts_writeFwCmd(cmd, 3); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } ret = pollForEvent(event_to_search, 1, readEvent, TIMEOUT_REQU_COMP_DATA); if (ret < OK) { logError(0, "%s Event did not Found at %d attemp!\n", tag, retry + 1); retry += 1; } else { retry = 0; break; } } if (retry == FRAME_DATA_READ_RETRY) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_TIMEOUT); return ERROR_TIMEOUT; } u8ToU16_le(&readEvent[1], &answer); if (answer == type) return OK; logError(1, "%s The event found has a different type of ", tag); logError(1, "Frame data:%02X\n", ERROR_DIFF_COMP_TYPE); return ERROR_DIFF_COMP_TYPE; } int readFrameDataHeader(u16 type, struct DataHeader *header) { u16 offset = ADDR_FRAMEBUFFER_DATA; u16 answer; u8 data[FRAME_DATA_HEADER]; if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, FRAME_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } logError(0, "%s Read Data Header done!\n", tag); if (data[0] != FRAME_HEADER_SIGNATURE) { logError(1, "%s %s %02X Wrong Header Signature !%02X != %02X\n", tag, __func__, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE); return ERROR_WRONG_COMP_SIGN; } u8ToU16_le(&data[1], &answer); if (answer != type) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_DIFF_COMP_TYPE); return ERROR_DIFF_COMP_TYPE; } logError(0, "%s Type of Frame data OK!\n", tag); header->type = type; header->force_node = (int)data[4]; header->sense_node = (int)data[5]; return OK; } int getMSFrame2(u16 type, struct MutualSenseFrame *frame) { u16 offset = ADDR_FRAMEBUFFER_DATA+FRAME_DATA_HEADER; int size, ret; frame->node_data = NULL; if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER || type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) { logError(1, "%s %s:Choose a MS type of frame data ERROR %02X\n", tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestFrame(type); if (ret < 0) { logError(1, "%s readMutualSenseCompensation:ERROR %02X\n", tag, ERROR_REQU_COMP_DATA); return (ret | ERROR_REQU_COMP_DATA); } ret = readFrameDataHeader(type, &(frame->header)); if (ret < 0) { logError(1, "%s readMutualSenseCompensationData:ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER); return (ret | ERROR_COMP_DATA_HEADER); } switch (type) { case MS_TOUCH_ACTIVE: case MS_TOUCH_LOW_POWER: case MS_TOUCH_ULTRA_LOW_POWER: size = frame->header.force_node * frame->header.sense_node; break; case MS_KEY: //or use directly the number in the ftsChip if (frame->header.force_node > frame->header.sense_node) size = frame->header.force_node; else size = frame->header.sense_node; frame->header.force_node = 1; frame->header.sense_node = size; break; default: logError(1, "%s %s: ERROR % 02X\n", tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } frame->node_data = (short *)kmalloc_array(size, sizeof(short), GFP_KERNEL); if (frame->node_data == NULL) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = getFrameData(offset, size*BYTES_PER_NODE, &(frame->node_data)); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_GET_FRAME_DATA); kfree(frame->node_data); return (ret | ERROR_GET_FRAME_DATA); } // if you want to access one node i,j, //you should compute the offset like: //offset = i * columns + j = > frame[i, j] logError(0, "%s Frame acquired!\n", tag); frame->node_data_size = size; return size;//return the number of data put inside frame } int getSSFrame2(u16 type, struct SelfSenseFrame *frame) { u16 offset = ADDR_FRAMEBUFFER_DATA + FRAME_DATA_HEADER; int size, ret; short *temp = NULL; frame->force_data = NULL; frame->sense_data = NULL; if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) { logError(1, "%s %s:Choose a SS type of frame data ERROR %02X\n", tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestFrame(type); if (ret < 0) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_REQU_COMP_DATA); return (ret | ERROR_REQU_COMP_DATA); } ret = readFrameDataHeader(type, &(frame->header)); if (ret < 0) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_COMP_DATA_HEADER); return (ret | ERROR_COMP_DATA_HEADER); } switch (type) { case SS_TOUCH: case SS_HOVER: case SS_PROXIMITY: size = frame->header.force_node + frame->header.sense_node; break; default: logError(1, "%s %s: ERROR % 02X\n", tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } temp = (short *)kmalloc_array(size, sizeof(short), GFP_KERNEL); if (temp == NULL) { logError(1, "%s %s: temp ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = getFrameData(offset, size*BYTES_PER_NODE, &temp); if (ret < OK) { logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_GET_FRAME_DATA); kfree(temp); return (ret | ERROR_GET_FRAME_DATA); } frame->force_data = (short *)kmalloc_array(frame->header.force_node, sizeof(short), GFP_KERNEL); if (frame->force_data == NULL) { logError(1, "%s %s: frame->force_data ERROR %02X\n", tag, __func__, ERROR_ALLOC); kfree(temp); return ERROR_ALLOC; } memcpy(frame->force_data, temp, frame->header.force_node * sizeof(short)); frame->sense_data = (short *)kmalloc_array(frame->header.sense_node, sizeof(short), GFP_KERNEL); if (frame->sense_data == NULL) { logError(1, "%s %s: frame->sense_data ERROR %02X\n", tag, __func__, ERROR_ALLOC); kfree(temp); kfree(frame->force_data); return ERROR_ALLOC; } memcpy(frame->sense_data, &temp[frame->header.force_node], frame->header.sense_node * sizeof(short)); logError(0, "%s Frame acquired!\n", tag); kfree(temp); return size; //return the number of data put inside frame }