Release 4.11 drivers/input/touchscreen/cyttsp4_core.c
/*
* cyttsp4_core.c
* Cypress TrueTouch(TM) Standard Product V4 Core driver module.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2012 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 "cyttsp4_core.h"
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h>
#include <linux/slab.h>
/* Timeout in ms. */
#define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT 500
#define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT 5000
#define CY_CORE_MODE_CHANGE_TIMEOUT 1000
#define CY_CORE_RESET_AND_WAIT_TIMEOUT 500
#define CY_CORE_WAKEUP_TIMEOUT 500
#define CY_CORE_STARTUP_RETRY_COUNT 3
static const u8 ldr_exit[] = {
0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
};
static const u8 ldr_err_app[] = {
0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17
};
static inline size_t merge_bytes(u8 high, u8 low)
{
return (high << 8) + low;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
#ifdef VERBOSE_DEBUG
static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size,
const char *data_name)
{
int i, k;
const char fmt[] = "%02X ";
int max;
if (!size)
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);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 132 | 100.00% | 1 | 100.00% |
Total | 132 | 100.00% | 1 | 100.00% |
#else
#define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0)
#endif
static int cyttsp4_load_status_regs(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
struct device *dev = cd->dev;
int rc;
rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size,
si->xy_mode);
if (rc < 0)
dev_err(dev, "%s: fail read mode regs r=%d\n",
__func__, rc);
else
cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode,
si->si_ofs.mode_size, "xy_mode");
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 94 | 100.00% | 1 | 100.00% |
Total | 94 | 100.00% | 1 | 100.00% |
static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode)
{
u8 cmd = mode ^ CY_HST_TOGGLE;
int rc;
/*
* Mode change issued, handshaking now will cause endless mode change
* requests, for sync mode modechange will do same with handshake
* */
if (mode & CY_HST_MODE_CHANGE)
return 0;
rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
if (rc < 0)
dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n",
__func__, rc);
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 73 | 100.00% | 1 | 100.00% |
Total | 73 | 100.00% | 1 | 100.00% |
static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd)
{
u8 cmd = CY_HST_RESET;
int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
if (rc < 0) {
dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n",
__func__);
return rc;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 59 | 100.00% | 1 | 100.00% |
Total | 59 | 100.00% | 1 | 100.00% |
static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd)
{
if (cd->cpdata->xres) {
cd->cpdata->xres(cd->cpdata, cd->dev);
dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__);
return 0;
}
dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__);
return -ENOSYS;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 65 | 100.00% | 1 | 100.00% |
Total | 65 | 100.00% | 1 | 100.00% |
static int cyttsp4_hw_reset(struct cyttsp4 *cd)
{
int rc = cyttsp4_hw_hard_reset(cd);
if (rc == -ENOSYS)
rc = cyttsp4_hw_soft_reset(cd);
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 36 | 100.00% | 1 | 100.00% |
Total | 36 | 100.00% | 1 | 100.00% |
/*
* Gets number of bits for a touch filed as parameter,
* sets maximum value for field which is used as bit mask
* and returns number of bytes required for that field
*/
static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max)
{
*max = 1UL << nbits;
return (nbits + 7) / 8;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 29 | 96.67% | 1 | 50.00% |
Dan Carpenter | 1 | 3.33% | 1 | 50.00% |
Total | 30 | 100.00% | 2 | 100.00% |
static int cyttsp4_si_data_offsets(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data),
&si->si_data);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n",
__func__, rc);
return rc;
}
/* Print sysinfo data offsets */
cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data,
sizeof(si->si_data), "sysinfo_data_offsets");
/* convert sysinfo data offset bytes into integers */
si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
si->si_data.map_szl);
si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
si->si_data.map_szl);
si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh,
si->si_data.cydata_ofsl);
si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh,
si->si_data.test_ofsl);
si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh,
si->si_data.pcfg_ofsl);
si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh,
si->si_data.opcfg_ofsl);
si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh,
si->si_data.ddata_ofsl);
si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh,
si->si_data.mdata_ofsl);
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 269 | 100.00% | 1 | 100.00% |
Total | 269 | 100.00% | 1 | 100.00% |
static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
int read_offset;
int mfgid_sz, calc_mfgid_sz;
void *p;
int rc;
si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
si->si_ofs.cydata_size);
p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__);
return -ENOMEM;
}
si->si_ptrs.cydata = p;
read_offset = si->si_ofs.cydata_ofs;
/* Read the CYDA registers up to MFGID field */
rc = cyttsp4_adap_read(cd, read_offset,
offsetof(struct cyttsp4_cydata, mfgid_sz)
+ sizeof(si->si_ptrs.cydata->mfgid_sz),
si->si_ptrs.cydata);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read cydata r=%d\n",
__func__, rc);
return rc;
}
/* Check MFGID size */
mfgid_sz = si->si_ptrs.cydata->mfgid_sz;
calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata);
if (mfgid_sz != calc_mfgid_sz) {
dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n",
__func__, mfgid_sz, calc_mfgid_sz);
return -EINVAL;
}
read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz)
+ sizeof(si->si_ptrs.cydata->mfgid_sz);
/* Read the CYDA registers for MFGID field */
rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz,
si->si_ptrs.cydata->mfg_id);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read cydata r=%d\n",
__func__, rc);
return rc;
}
read_offset += si->si_ptrs.cydata->mfgid_sz;
/* Read the rest of the CYDA registers */
rc = cyttsp4_adap_read(cd, read_offset,
sizeof(struct cyttsp4_cydata)
- offsetof(struct cyttsp4_cydata, cyito_idh),
&si->si_ptrs.cydata->cyito_idh);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read cydata r=%d\n",
__func__, rc);
return rc;
}
cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata,
si->si_ofs.cydata_size, "sysinfo_cydata");
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 409 | 99.76% | 1 | 50.00% |
Alexey Dobriyan | 1 | 0.24% | 1 | 50.00% |
Total | 410 | 100.00% | 2 | 100.00% |
static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
void *p;
int rc;
si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc test memory\n", __func__);
return -ENOMEM;
}
si->si_ptrs.test = p;
rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size,
si->si_ptrs.test);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read test data r=%d\n",
__func__, rc);
return rc;
}
cyttsp4_pr_buf(cd->dev, cd->pr_buf,
(u8 *)si->si_ptrs.test, si->si_ofs.test_size,
"sysinfo_test_data");
if (si->si_ptrs.test->post_codel &
CY_POST_CODEL_WDG_RST)
dev_info(cd->dev, "%s: %s codel=%02X\n",
__func__, "Reset was a WATCHDOG RESET",
si->si_ptrs.test->post_codel);
if (!(si->si_ptrs.test->post_codel &
CY_POST_CODEL_CFG_DATA_CRC_FAIL))
dev_info(cd->dev, "%s: %s codel=%02X\n", __func__,
"Config Data CRC FAIL",
si->si_ptrs.test->post_codel);
if (!(si->si_ptrs.test->post_codel &
CY_POST_CODEL_PANEL_TEST_FAIL))
dev_info(cd->dev, "%s: %s codel=%02X\n",
__func__, "PANEL TEST FAIL",
si->si_ptrs.test->post_codel);
dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n",
__func__, si->si_ptrs.test->post_codel & 0x08 ?
"ENABLED" : "DISABLED",
si->si_ptrs.test->post_codel);
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 315 | 100.00% | 1 | 100.00% |
Total | 315 | 100.00% | 1 | 100.00% |
static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
void *p;
int rc;
si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
if (p == NULL) {
rc = -ENOMEM;
dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n",
__func__, rc);
return rc;
}
si->si_ptrs.pcfg = p;
rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size,
si->si_ptrs.pcfg);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read pcfg data r=%d\n",
__func__, rc);
return rc;
}
si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh
& CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl);
si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh
& CY_PCFG_ORIGIN_X_MASK);
si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh
& CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl);
si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh
& CY_PCFG_ORIGIN_Y_MASK);
si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh,
si->si_ptrs.pcfg->max_zl);
cyttsp4_pr_buf(cd->dev, cd->pr_buf,
(u8 *)si->si_ptrs.pcfg,
si->si_ofs.pcfg_size, "sysinfo_pcfg_data");
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 306 | 100.00% | 1 | 100.00% |
Total | 306 | 100.00% | 1 | 100.00% |
static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
struct cyttsp4_tch_abs_params *tch;
struct cyttsp4_tch_rec_params *tch_old, *tch_new;
enum cyttsp4_tch_abs abs;
int i;
void *p;
int rc;
si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__);
rc = -ENOMEM;
goto cyttsp4_si_get_opcfg_data_exit;
}
si->si_ptrs.opcfg = p;
rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size,
si->si_ptrs.opcfg);
if (rc < 0) {
dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
__func__, rc);
goto cyttsp4_si_get_opcfg_data_exit;
}
si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) +
si->si_ptrs.opcfg->rep_szl;
si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns;
si->si_ofs.num_btn_regs = (si->si_ofs.num_btns +
CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG;
si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs;
si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0;
si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs &
CY_BYTE_OFS_MASK;
si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size &
CY_BYTE_OFS_MASK;
/* Get the old touch fields */
for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) {
tch = &si->si_ofs.tch_abs[abs];
tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs];
tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK;
tch->size = cyttsp4_bits_2_bytes(tch_old->size,
&tch->max);
tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
}
/* button fields */
si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size;
si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs;
si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size;
if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
/* Get the extended touch fields */
for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) {
tch = &si->si_ofs.tch_abs[abs];
tch_new = &si->si_ptrs.opcfg->tch_rec_new[i];
tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK;
tch->size = cyttsp4_bits_2_bytes(tch_new->size,
&tch->max);
tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
}
}
for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) {
dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__,
cyttsp4_tch_abs_string[abs]);
dev_dbg(cd->dev, "%s: ofs =%2zd\n", __func__,
si->si_ofs.tch_abs[abs].ofs);
dev_dbg(cd->dev, "%s: siz =%2zd\n", __func__,
si->si_ofs.tch_abs[abs].size);
dev_dbg(cd->dev, "%s: max =%2zd\n", __func__,
si->si_ofs.tch_abs[abs].max);
dev_dbg(cd->dev, "%s: bofs=%2zd\n", __func__,
si->si_ofs.tch_abs[abs].bofs);
}
si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1;
si->si_ofs.data_size = si->si_ofs.max_tchs *
si->si_ptrs.opcfg->tch_rec_size;
cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
cyttsp4_si_get_opcfg_data_exit:
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 722 | 99.45% | 1 | 50.00% |
Alexey Dobriyan | 4 | 0.55% | 1 | 50.00% |
Total | 726 | 100.00% | 2 | 100.00% |
static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
void *p;
int rc;
si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs;
p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL);
if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__);
return -ENOMEM;
}
si->si_ptrs.ddata = p;
rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size,
si->si_ptrs.ddata);
if (rc < 0)
dev_err(cd->dev, "%s: fail read ddata data r=%d\n",
__func__, rc);
else
cyttsp4_pr_buf(cd->dev, cd->pr_buf,
(u8 *)si->si_ptrs.ddata,
si->si_ofs.ddata_size, "sysinfo_ddata");
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ferruh Yigit | 173 | 100.00% | 1 | 100.00% |
Total | 173 | 100.00% | 1 | 100.00% |
static int cyttsp4_si_get_mdata(struct cyttsp4 *cd)
{
struct cyttsp4_sysinfo *si = &cd->sysinfo;
void *p