
Add all drivers for new platforms. Change-Id: Ie9947b0c6f8ddfee7dab6dfa80d6aca62323f4da Signed-off-by: Fei Mao <feim1@codeaurora.org>
520 baris
13 KiB
C
520 baris
13 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* FTS Capacitive touch screen controller (FingerTipS)
|
|
*
|
|
* Copyright (C) 2016-2019, STMicroelectronics Limited.
|
|
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
|
|
*
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
*
|
|
**************************************************************************
|
|
** STMicroelectronics **
|
|
**************************************************************************
|
|
** marco.cali@st.com **
|
|
**************************************************************************
|
|
* *
|
|
* FTS functions for getting frames *
|
|
* *
|
|
**************************************************************************
|
|
**************************************************************************
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
#include <stdarg.h>
|
|
#include <linux/input.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/serio.h>
|
|
#include <linux/time.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/i2c-dev.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/power_supply.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/of_gpio.h>
|
|
//#include <linux/sec_sysfs.h>
|
|
|
|
#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
|
|
}
|