/*
* cyttsp7_core.c
* Cypress TrueTouch(TM) Standard Product V4 Core Module.
* For use with Cypress touchscreen controllers.
* Supported parts include:
* CYAT817X
*
* Copyright (C) 2015-2017 Cypress Semiconductor
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2, and only 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp7_regs.h"
#define CY_CORE_STARTUP_RETRY_COUNT 3
/*
* If platform init (cd->cpdata->init) function resets or powers on the device,
* then set this flag as true.
*/
#define CY_CORE_DEVICE_RESET_BY_PLATFORM_INIT false
bool cydata_free = false;
bool test_free = false;
bool pcfg_free = false;
bool opcfg_free = false;
bool ddata_free = false;
bool mdata_free = false;
bool btn_free = false;
bool xy_mode_free = false;
bool btn_rec_data_free = false;
static const u8 security_key[] = {
0xA5, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD, 0x5A
};
static const u8 ldr_exit[] = {
CY_CMD_LDR_HOST_SYNC, CY_START_OF_PACKET, CY_CMD_LDR_EXIT, 0x00, 0x00,
0x4F, 0x6D, CY_END_OF_PACKET
};
static const u8 ldr_fast_exit[] = {
CY_CMD_LDR_HOST_SYNC, CY_START_OF_PACKET, CY_CMD_LDR_FAST_EXIT,
0x00, 0x00, 0xC3, 0x68, CY_END_OF_PACKET
};
static const u8 ldr_err_app[] = {
CY_START_OF_PACKET, 0x02, 0x00, 0x00, 0x55, 0xDD, CY_END_OF_PACKET
};
MODULE_FIRMWARE(CY_FW_FILE_NAME);
struct atten_node {
struct list_head node;
char id;
int (*func)(struct device *);
struct device *dev;
int mode;
};
static inline size_t merge_bytes(u8 high, u8 low)
{
return (high << 8) + low;
}
#ifdef VERBOSE_DEBUG
void cyttsp7_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size,
const char *data_name)
{
struct cyttsp7_core_data *cd = dev_get_drvdata(dev);
int i, k;
const char fmt[] = "%02X ";
int max;
if (!size)
return;
if (!pr_buf) {
if (cd->pr_buf)
pr_buf = cd->pr_buf;
else
return;
}
max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
pr_buf[0] = 0;
for (i = k = 0; i < size && k < max; i++, k += 3)
scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]);
dev_vdbg(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name, size - 1,
pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
}
EXPORT_SYMBOL_GPL(cyttsp7_pr_buf);
#endif
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP7_VDEBUG
void cyttsp7_parse_tch_data(struct device *dev, u8 *xy_data, u8 num_cur_rec)
{
struct cyttsp7_touch tch;
int i;
for (i = 0; i < num_cur_rec; i++) {
cyttsp7_get_touch_record_(dev, i, tch.abs);
/* Lift-off */
if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF)
dev_dbg(dev, "%s:LIFTOFF EVENT DETECTED\n", __func__);
/* Significant Displacemnet */
if (tch.abs[CY_TCH_E] == CY_EV_MOVE)
dev_dbg(dev, "%s:SIGNIFICANT DISPLACEMENT EVENT DETECTED\n",
__func__);
/* Touch Down */
if (tch.abs[CY_TCH_E] == CY_EV_TOUCHDOWN)
dev_dbg(dev, "%s:TOUCHDOWN EVENT DETECTED\n", __func__);
/* proximity event */
if (tch.abs[CY_TCH_O] == CY_OBJ_PROXIMITY)
dev_dbg(dev, "%s: PROXIMITY EVENT DETECTED\n",
__func__);
/* Hover Event*/
if (tch.abs[CY_TCH_O] == CY_OBJ_HOVER)
dev_dbg(dev, "%s:HOVER EVENT DETECTED\n", __func__);
/* Slider Standard*/
if (tch.abs[CY_TCH_O] == CY_OBJ_SLIDER_STANDARD)
dev_dbg(dev, "%s:SLIDER STANDARD EVENT DETECTED\n",
__func__);
/* Slider Lagre*/
if (tch.abs[CY_TCH_O] == CY_OBJ_SLIDER_LARGE)
dev_dbg(dev, "%s:SLIDER LARGE EVENT DETECTED\n",
__func__);
/* Slider Glove*/
if (tch.abs[CY_TCH_O] == CY_OBJ_SLIDER_GLOVE)
dev_dbg(dev, "%s:SLIDER GLOVE EVENT DETECTED\n",
__func__);
dev_dbg(dev, "FORCE TOUCH DATA : %02X", tch.abs[CY_TCH_P]);
}
}
#endif
static inline int cyttsp7_adap_read(struct cyttsp7_core_data *cd, u16 addr,
void *buf, int size)
{
return cd->bus_ops->read(cd->dev, addr, buf, size, cd->max_xfer);
}
static inline int cyttsp7_adap_write(struct cyttsp7_core_data *cd, u16 addr,
const void *buf, int size)
{
return cd->bus_ops->write(cd->dev, addr, cd->wr_buf, buf, size,
cd->max_xfer);
}
/* cyttsp7_platform_detect_read()
*
* This function is passed to platform detect
* function to perform a read operation
*/
static int cyttsp7_platform_detect_read(struct device *dev, u16 addr,
void *buf, int size)
{
struct cyttsp7_core_data *cd = dev_get_drvdata(dev);
return cd->bus_ops->read(cd->dev, addr, buf, size, cd->max_xfer);
}
static const u8 *cyttsp7_get_security_key_(struct device *dev,
int *size)
{
if (size)
*size = sizeof(security_key);
return security_key;
}
static u16 cyttsp7_calc_app_crc(const u8 *data, int size)
{
int i, j;
u16 crc = 0xFFFF;
for (i = 0; i < size; i++) {
crc ^= ((u16)data[i] << 8);
for (j = 8; j > 0; j--)
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
return crc;
}
static inline void cyttsp7_get_touch_axis(struct cyttsp7_core_data *cd,
int *axis, int size, int max, u8 *xy_data, int bofs)
{
int nbyte;
int next = 0;
for (nbyte = 0, *axis = 0; nbyte < size; nbyte++) {
dev_vdbg(cd->dev,
"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d) bofs=%d\n",
__func__, *axis, *axis, size, max, xy_data, next,
xy_data[next], xy_data[next], bofs);
*axis = (*axis << 8) + (xy_data[next] >> bofs);
next++;
}
*axis &= max - 1;
dev_vdbg(cd->dev,
"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d)\n",
__func__, *axis, *axis, size, max, xy_data, next,
xy_data[next], xy_data[next]);
}
/*
* cyttsp7_get_touch_record_()
*
* Fills touch info for a touch record specified by rec_no
* Should only be called in Operational mode IRQ attention and
* rec_no should be less than the number of current touch records
*/
void cyttsp7_get_touch_record_(struct device *dev, int rec_no, int *rec_abs)
{
struct cyttsp7_core_data *cd = dev_get_drvdata(dev);
struct cyttsp7_sysinfo *si = &cd->sysinfo;
u8 *xy_data = si->xy_data + (rec_no * si->si_ofs.tch_rec_size);
enum cyttsp7_tch_abs abs;
memset(rec_abs, 0, CY_TCH_NUM_ABS * sizeof(int));
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
cyttsp7_get_touch_axis(cd, &rec_abs[abs],
si->si_ofs.tch_abs[abs].size,
si->si_ofs.tch_abs[abs].max,
xy_data + si->si_ofs.tch_abs[abs].ofs,
si->si_ofs.tch_abs[abs].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp7_tch_abs_string[abs],
rec_abs[abs], rec_abs[abs]);
}
}
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP7_VDEBUG
int cyttsp7_pr_gest_data(struct device *dev, struct cyttsp7_sysinfo *si)
{
struct cyttsp7_core_data *cd = dev_get_drvdata(dev);
u8 gest_ofs, gest_cnt, gest_id = 0;
u16 gest_pos_x = 0, gest_pos_y = 0;
u8 num_btn_regs = si->si_ofs.num_btn_regs;
//u8 gesture_enabled = si->ttconfig.gesture_enable;
u8 gesture_enabled = cd->sysinfo.ttconfig.gesture_enable;
if (gesture_enabled) {
if ((gesture_enabled & CY_GEST_ENABLED_STD) == CY_GEST_ENABLED_STD)
dev_dbg(dev, "%s:GESTURE ENABLED:STANDARD\n", __func__);
else if ((gesture_enabled & CY_GEST_ENABLED_EXT) == CY_GEST_ENABLED_EXT)
dev_dbg(dev, "%s:GESTURE ENABLED:EXTENDED\n", __func__);
} else {
dev_dbg(dev, "%s:GESTURE DISABLED\n", __func__);
return 0;
}
gest_ofs = si->si_ofs.rep_ofs + num_btn_regs + 2;
gest_id = si->xy_mode[gest_ofs];
gest_cnt = si->xy_mode[gest_ofs+1];
if (IS_GEST_EXTD(gest_id)) {
gest_id = gest_id & CY_GEST_EXT_ID_MASK;
gest_pos_x = ((si->xy_mode[gest_ofs+1]) << 8)
| (si->xy_mode[gest_ofs+2]);
gest_pos_y = ((si->xy_mode[gest_ofs+3]) << 8)
| (si->xy_mode[gest_ofs+4]);
}
dev_dbg(dev, "%s:Gesture ID = %02X\n", __func__, gest_id);
dev_dbg(dev, "%s:Gesture Count = %02X\n", __func__, ges