cregit-Linux how code gets into the kernel

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

PersonTokensPropCommitsCommitProp
Ferruh Yigit22100.00%1100.00%
Total22100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit132100.00%1100.00%
Total132100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit94100.00%1100.00%
Total94100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit73100.00%1100.00%
Total73100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit59100.00%1100.00%
Total59100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit65100.00%1100.00%
Total65100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit36100.00%1100.00%
Total36100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit2996.67%150.00%
Dan Carpenter13.33%150.00%
Total30100.00%2100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit269100.00%1100.00%
Total269100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit40999.76%150.00%
Alexey Dobriyan10.24%150.00%
Total410100.00%2100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit315100.00%1100.00%
Total315100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit306100.00%1100.00%
Total306100.00%1100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit72299.45%150.00%
Alexey Dobriyan40.55%150.00%
Total726100.00%2100.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

PersonTokensPropCommitsCommitProp
Ferruh Yigit173100.00%1100.00%
Total173100.00%1100.00%


static int cyttsp4_si_get_mdata(struct cyttsp4 *cd) { struct cyttsp4_sysinfo *si = &cd->sysinfo; void *p