1
0
Fork 0

rM2: input: touchscreen: Copy rM2 cyttsp5 driver

Copy the rM2 zero-sugar branch
(https://github.com/reMarkable/linux/tree/zero-sugar) to the new kernel.

Signed-off-by: Alistair Francis <alistair@alistair23.me>
5.4-rM2-2.2.x-imx-deep-sleep
Alistair Francis 2021-02-07 09:37:17 -08:00
parent 8508afa801
commit c222fce7d8
20 changed files with 18593 additions and 0 deletions

View File

@ -289,6 +289,225 @@ config TOUCHSCREEN_CYTTSP4_SPI
To compile this driver as a module, choose M here: the
module will be called cyttsp4_spi.
config TOUCHSCREEN_CYPRESS_CYTTSP5
tristate "Parade TrueTouch Gen5 Touchscreen Driver"
help
Core driver for Parade TrueTouch(tm) Standard Product
Geneartion5 touchscreen controllers.
Say Y here if you have a Parade Gen5 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
bool "Enable Device Tree support"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5 && OF
help
Say Y here to enable support for device tree.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG
bool "Enable debug output"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable debug output for Parade TrueTouch(tm)
Standard Product Generation5 drivers set.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_VDEBUG
bool "Enable verbose debug output"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG
help
Say Y here to enable verbose debug output for Parade TrueTouch(tm)
Standard Product Generation5 drivers set.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_I2C
tristate "Parade TrueTouch Gen5 I2C"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
select I2C
help
Say Y here to enable I2C bus interface to Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say Y.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_i2c.
config TOUCHSCREEN_CYPRESS_CYTTSP5_SPI
tristate "Parade TrueTouch Gen5 SPI"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
select SPI
help
Say Y here to enable SPI bus interface to Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_spi.
choice
bool "Parade TrueTouch Gen5 MultiTouch Protocol"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
default TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
help
This option controls which MultiTouch protocol will be used to
report the touch events.
config TOUCHSCREEN_CYPRESS_CYTTSP5_MT_A
bool "Protocol A"
help
Select to enable MultiTouch touch reporting using protocol A
on Parade TrueTouch(tm) Standard Product Generation4 touchscreen
controller.
config TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
bool "Protocol B"
help
Select to enable MultiTouch touch reporting using protocol B
on Parade TrueTouch(tm) Standard Product Generation4 touchscreen
controller.
endchoice
config TOUCHSCREEN_CYPRESS_CYTTSP5_BUTTON
bool "Parade TrueTouch Gen5 MultiTouch CapSense Button"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable CapSense reporting on Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_PROXIMITY
bool "Parade TrueTouch Gen5 Proximity"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable proximity reporting on Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS
tristate "Parade TrueTouch Gen5 MultiTouch Device Access"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable Parade TrueTouch(tm) Standard Product
Generation5 touchscreen controller device access module.
This modules adds an interface to access touchscreen
controller using driver sysfs nodes.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_device_access.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS_API
bool "Enable Device Access kernel API"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS
help
Say Y here to enable Device access kernel API which provides
access to Parade TrueTouch(tm) Standard Product Generation5
touchscreen controller for other modules.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_TEST_DEVICE_ACCESS_API
tristate "Simple Test module for Device Access kernel API"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS_API
help
Say Y here to enable test module for Device access kernel API.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_test_device_access_api.
config TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
tristate "Parade TrueTouch Gen5 MultiTouch Loader"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable Parade TrueTouch(tm) Standard Product
Generation5 touchscreen controller FW Loader module.
This module enables support for Firmware upgrade.
If unsure, say Y.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_loader.
config TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
bool "FW upgrade from header file"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to include Parade TrueTouch(tm) Standard Product
Generation5 device Firmware into driver.
Need proper header file for this.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
bool "FW upgrade from binary file"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to include Parade TrueTouch(tm) Standard Product
Generation5 device Firmware into kernel as binary blob.
This should be enabled for manual FW upgrade support.
If unsure, say Y.
config TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
bool "TT Configuration upgrade from header file"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to include Parade TrueTouch(tm) Standard Product
Generation5 device TrueTouch Configuration into kernel itself.
Need proper header file for this.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
bool "TT Configuration upgrade via SysFs"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to provide a SysFs interface to upgrade TrueTouch
Configuration with a binary configuration file.
Need proper binary version of config file for this
feature.
If unsure, say Y.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG_MDL
tristate "Parade TrueTouch Gen5 MultiTouch Debug Module"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable Parade TrueTouch(tm) Standard Product
Generation5 Debug module.
This module adds support for verbose printing touch
information.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_debug.
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X

View File

@ -114,3 +114,50 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5) += cyttsp5.o
cyttsp5-y := cyttsp5_core.o cyttsp5_mt_common.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_A) += cyttsp5_mta.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B) += cyttsp5_mtb.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BUTTON) += cyttsp5_btn.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PROXIMITY) += cyttsp5_proximity.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT) += cyttsp5_devtree.o
ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5
obj-y += cyttsp5_platform.o
endif
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_I2C) += cyttsp5_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_SPI) += cyttsp5_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG_MDL) += cyttsp5_debug.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER) += cyttsp5_loader.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS) += cyttsp5_device_access.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_TEST_DEVICE_ACCESS_API) += cyttsp5_test_device_access_api.o
ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG),y)
CFLAGS_cyttsp5_core.o += -DDEBUG
CFLAGS_cyttsp5_i2c.o += -DDEBUG
CFLAGS_cyttsp5_spi.o += -DDEBUG
CFLAGS_cyttsp5_mta.o += -DDEBUG
CFLAGS_cyttsp5_mtb.o += -DDEBUG
CFLAGS_cyttsp5_mt_common.o += -DDEBUG
CFLAGS_cyttsp5_btn.o += -DDEBUG
CFLAGS_cyttsp5_proximity.o += -DDEBUG
CFLAGS_cyttsp5_device_access.o += -DDEBUG
CFLAGS_cyttsp5_loader.o += -DDEBUG
CFLAGS_cyttsp5_debug.o += -DDEBUG
CFLAGS_cyttsp5_devtree.o += -DDEBUG
CFLAGS_cyttsp5_platform.o += -DDEBUG
endif
ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_VDEBUG),y)
CFLAGS_cyttsp5_core.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_i2c.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_spi.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_mta.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_mtb.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_mt_common.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_btn.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_proximity.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_device_access.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_loader.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_debug.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_devtree.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_platform.o += -DVERBOSE_DEBUG
endif

View File

@ -0,0 +1,367 @@
/*
* cyttsp5_btn.c
* Parade TrueTouch(TM) Standard Product V5 CapSense Reports Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_BTN_NAME "cyttsp5_btn"
static inline void cyttsp5_btn_key_action(struct cyttsp5_btn_data *bd,
int btn_no, int btn_state)
{
struct device *dev = bd->dev;
struct cyttsp5_sysinfo *si = bd->si;
if (!si->btn[btn_no].enabled ||
si->btn[btn_no].state == btn_state)
return;
si->btn[btn_no].state = btn_state;
input_report_key(bd->input, si->btn[btn_no].key_code, btn_state);
input_sync(bd->input);
dev_dbg(dev, "%s: btn=%d key_code=%d %s\n", __func__,
btn_no, si->btn[btn_no].key_code,
btn_state == CY_BTN_PRESSED ?
"PRESSED" : "RELEASED");
}
static void cyttsp5_get_btn_touches(struct cyttsp5_btn_data *bd)
{
struct cyttsp5_sysinfo *si = bd->si;
int num_btns = si->num_btns;
int cur_btn;
int cur_btn_state;
for (cur_btn = 0; cur_btn < num_btns; cur_btn++) {
/* Get current button state */
cur_btn_state = (si->xy_data[0] >> (cur_btn * CY_BITS_PER_BTN))
& CY_NUM_BTN_EVENT_ID;
cyttsp5_btn_key_action(bd, cur_btn, cur_btn_state);
}
}
static void cyttsp5_btn_lift_all(struct cyttsp5_btn_data *bd)
{
struct cyttsp5_sysinfo *si = bd->si;
int i;
if (!si || si->num_btns == 0)
return;
for (i = 0; i < si->num_btns; i++)
cyttsp5_btn_key_action(bd, i, CY_BTN_RELEASED);
}
#ifdef VERBOSE_DEBUG
static void cyttsp5_log_btn_data(struct cyttsp5_btn_data *bd)
{
struct device *dev = bd->dev;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
u8 *pr_buf = cd->pr_buf;
struct cyttsp5_sysinfo *si = bd->si;
int cur;
int value;
for (cur = 0; cur < si->num_btns; cur++) {
pr_buf[0] = 0;
if (si->xy_data[0] & (1 << cur))
value = 1;
else
value = 0;
snprintf(pr_buf, CY_MAX_PRBUF_SIZE, "btn_rec[%d]=0x", cur);
snprintf(pr_buf, CY_MAX_PRBUF_SIZE, "%s%X (%02X)",
pr_buf, value,
le16_to_cpu(si->xy_data[1 + cur * 2]));
dev_vdbg(dev, "%s: %s\n", __func__, pr_buf);
}
}
#endif
/* read xy_data for all current CapSense button touches */
static int cyttsp5_xy_worker(struct cyttsp5_btn_data *bd)
{
struct cyttsp5_sysinfo *si = bd->si;
/* extract button press/release touch information */
if (si->num_btns > 0) {
cyttsp5_get_btn_touches(bd);
#ifdef VERBOSE_DEBUG
/* log button press/release touch information */
cyttsp5_log_btn_data(bd);
#endif
}
return 0;
}
static int cyttsp5_btn_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
int rc;
if (bd->si->xy_mode[2] != bd->si->desc.btn_report_id)
return 0;
/* core handles handshake */
mutex_lock(&bd->btn_lock);
rc = cyttsp5_xy_worker(bd);
mutex_unlock(&bd->btn_lock);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static int cyttsp5_startup_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
mutex_lock(&bd->btn_lock);
cyttsp5_btn_lift_all(bd);
mutex_unlock(&bd->btn_lock);
return 0;
}
static int cyttsp5_btn_suspend_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
mutex_lock(&bd->btn_lock);
cyttsp5_btn_lift_all(bd);
bd->is_suspended = true;
mutex_unlock(&bd->btn_lock);
pm_runtime_put(dev);
return 0;
}
static int cyttsp5_btn_resume_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
pm_runtime_get(dev);
mutex_lock(&bd->btn_lock);
bd->is_suspended = false;
mutex_unlock(&bd->btn_lock);
return 0;
}
static int cyttsp5_btn_open(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
pm_runtime_get_sync(dev);
mutex_lock(&bd->btn_lock);
bd->is_suspended = false;
mutex_unlock(&bd->btn_lock);
dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_BTN_NAME,
cyttsp5_btn_attention, CY_MODE_OPERATIONAL);
/* set up startup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
cyttsp5_startup_attention, 0);
/* set up suspend call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_BTN_NAME,
cyttsp5_btn_suspend_attention, 0);
/* set up resume call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_BTN_NAME,
cyttsp5_btn_resume_attention, 0);
return 0;
}
static void cyttsp5_btn_close(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_BTN_NAME,
cyttsp5_btn_attention, CY_MODE_OPERATIONAL);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
cyttsp5_startup_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_BTN_NAME,
cyttsp5_btn_suspend_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_BTN_NAME,
cyttsp5_btn_resume_attention, 0);
mutex_lock(&bd->btn_lock);
if (!bd->is_suspended) {
pm_runtime_put(dev);
bd->is_suspended = true;
}
mutex_unlock(&bd->btn_lock);
}
static int cyttsp5_setup_input_device(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
int i;
int rc;
dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
__set_bit(EV_KEY, bd->input->evbit);
dev_vdbg(dev, "%s: Number of buttons %d\n", __func__, bd->si->num_btns);
for (i = 0; i < bd->si->num_btns; i++) {
dev_vdbg(dev, "%s: btn:%d keycode:%d\n",
__func__, i, bd->si->btn[i].key_code);
__set_bit(bd->si->btn[i].key_code, bd->input->keybit);
}
rc = input_register_device(bd->input);
if (rc < 0)
dev_err(dev, "%s: Error, failed register input device r=%d\n",
__func__, rc);
else
bd->input_device_registered = true;
return rc;
}
static int cyttsp5_setup_input_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
int rc;
bd->si = _cyttsp5_request_sysinfo(dev);
if (!bd->si)
return -1;
rc = cyttsp5_setup_input_device(dev);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
cyttsp5_setup_input_attention, 0);
return rc;
}
int cyttsp5_btn_probe(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp5_btn_platform_data *btn_pdata;
int rc = 0;
if (!pdata || !pdata->btn_pdata) {
dev_err(dev, "%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
btn_pdata = pdata->btn_pdata;
mutex_init(&bd->btn_lock);
bd->dev = dev;
bd->pdata = btn_pdata;
/* Create the input device and register it. */
dev_vdbg(dev, "%s: Create the input device and register it\n",
__func__);
bd->input = input_allocate_device();
if (!bd->input) {
dev_err(dev, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
}
if (bd->pdata->inp_dev_name)
bd->input->name = bd->pdata->inp_dev_name;
else
bd->input->name = CYTTSP5_BTN_NAME;
scnprintf(bd->phys, sizeof(bd->phys), "%s/input%d", dev_name(dev),
cd->phys_num++);
bd->input->phys = bd->phys;
bd->input->dev.parent = bd->dev;
bd->input->open = cyttsp5_btn_open;
bd->input->close = cyttsp5_btn_close;
input_set_drvdata(bd->input, bd);
/* get sysinfo */
bd->si = _cyttsp5_request_sysinfo(dev);
if (bd->si) {
rc = cyttsp5_setup_input_device(dev);
if (rc)
goto error_init_input;
} else {
dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, bd->si);
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_BTN_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
error_init_input:
input_free_device(bd->input);
error_alloc_failed:
error_no_pdata:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
int cyttsp5_btn_release(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
if (bd->input_device_registered) {
input_unregister_device(bd->input);
} else {
input_free_device(bd->input);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_BTN_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,393 @@
/*
* cyttsp5_debug.c
* Parade TrueTouch(TM) Standard Product V5 Debug Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_DEBUG_NAME "cyttsp5_debug"
struct cyttsp5_debug_data {
struct device *dev;
struct cyttsp5_sysinfo *si;
uint32_t interrupt_count;
uint32_t formated_output;
struct mutex sysfs_lock;
u8 pr_buf[CY_MAX_PRBUF_SIZE];
};
static struct cyttsp5_core_commands *cmd;
static struct cyttsp5_module debug_module;
static inline struct cyttsp5_debug_data *cyttsp5_get_debug_data(
struct device *dev)
{
return cyttsp5_get_module_data(dev, &debug_module);
}
/*
* This function provide output of combined xy_mode and xy_data.
* Required by TTHE.
*/
static void cyttsp5_pr_buf_op_mode(struct cyttsp5_debug_data *dd, u8 *pr_buf,
struct cyttsp5_sysinfo *si, u8 cur_touch)
{
const char fmt[] = "%02X ";
int max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
u8 report_id = si->xy_mode[2];
int header_size = 0;
int report_size = 0;
int total_size = 0;
int i, k;
if (report_id == si->desc.tch_report_id) {
header_size = si->desc.tch_header_size;
report_size = cur_touch * si->desc.tch_record_size;
} else if (report_id == si->desc.btn_report_id) {
header_size = BTN_INPUT_HEADER_SIZE;
report_size = BTN_REPORT_SIZE;
}
total_size = header_size + report_size;
pr_buf[0] = 0;
for (i = k = 0; i < header_size && i < max; i++, k += 3)
scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_mode[i]);
for (i = 0; i < report_size && i < max; i++, k += 3)
scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_data[i]);
pr_info("%s=%s%s\n", "cyttsp5_OpModeData", pr_buf,
total_size <= max ? "" : CY_PR_TRUNCATED);
}
static void cyttsp5_debug_print(struct device *dev, u8 *pr_buf, u8 *sptr,
int size, const char *data_name)
{
int i, j;
int elem_size = sizeof("XX ") - 1;
int max = (CY_MAX_PRBUF_SIZE - 1) / elem_size;
int limit = size < max ? size : max;
if (limit < 0)
limit = 0;
pr_buf[0] = 0;
for (i = j = 0; i < limit; i++, j += elem_size)
scnprintf(pr_buf + j, CY_MAX_PRBUF_SIZE - j, "%02X ", sptr[i]);
if (size)
pr_info("%s[0..%d]=%s%s\n", data_name, size - 1, pr_buf,
size <= max ? "" : CY_PR_TRUNCATED);
else
pr_info("%s[]\n", data_name);
}
static void cyttsp5_debug_formated(struct device *dev, u8 *pr_buf,
struct cyttsp5_sysinfo *si, u8 num_cur_tch)
{
u8 report_id = si->xy_mode[2];
int header_size = 0;
int report_size = 0;
u8 data_name[] = "touch[99]";
int max_print_length = 20;
int i;
if (report_id == si->desc.tch_report_id) {
header_size = si->desc.tch_header_size;
report_size = num_cur_tch * si->desc.tch_record_size;
} else if (report_id == si->desc.btn_report_id) {
header_size = BTN_INPUT_HEADER_SIZE;
report_size = BTN_REPORT_SIZE;
}
/* xy_mode */
cyttsp5_debug_print(dev, pr_buf, si->xy_mode, header_size, "xy_mode");
/* xy_data */
if (report_size > max_print_length) {
pr_info("xy_data[0..%d]:\n", report_size);
for (i = 0; i < report_size - max_print_length;
i += max_print_length) {
cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
max_print_length, " ");
}
if (report_size - i)
cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
report_size - i, " ");
} else {
cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
"xy_data");
}
/* touches */
if (report_id == si->desc.tch_report_id) {
for (i = 0; i < num_cur_tch; i++) {
scnprintf(data_name, sizeof(data_name) - 1,
"touch[%u]", i);
cyttsp5_debug_print(dev, pr_buf,
si->xy_data + (i * si->desc.tch_record_size),
si->desc.tch_record_size, data_name);
}
}
/* buttons */
if (report_id == si->desc.btn_report_id)
cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
"button");
}
/* read xy_data for all touches for debug */
static int cyttsp5_xy_worker(struct cyttsp5_debug_data *dd)
{
struct device *dev = dd->dev;
struct cyttsp5_sysinfo *si = dd->si;
u8 report_reg = si->xy_mode[TOUCH_COUNT_BYTE_OFFSET];
u8 num_cur_tch = GET_NUM_TOUCHES(report_reg);
uint32_t formated_output;
mutex_lock(&dd->sysfs_lock);
dd->interrupt_count++;
formated_output = dd->formated_output;
mutex_unlock(&dd->sysfs_lock);
/* Interrupt */
pr_info("Interrupt(%u)\n", dd->interrupt_count);
if (formated_output)
cyttsp5_debug_formated(dev, dd->pr_buf, si, num_cur_tch);
else
/* print data for TTHE */
cyttsp5_pr_buf_op_mode(dd, dd->pr_buf, si, num_cur_tch);
pr_info("\n");
return 0;
}
static int cyttsp5_debug_attention(struct device *dev)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
struct cyttsp5_sysinfo *si = dd->si;
u8 report_id = si->xy_mode[2];
int rc = 0;
if (report_id != si->desc.tch_report_id
&& report_id != si->desc.btn_report_id)
return 0;
/* core handles handshake */
rc = cyttsp5_xy_worker(dd);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static ssize_t cyttsp5_interrupt_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
int val;
mutex_lock(&dd->sysfs_lock);
val = dd->interrupt_count;
mutex_unlock(&dd->sysfs_lock);
return scnprintf(buf, CY_MAX_PRBUF_SIZE, "Interrupt Count: %d\n", val);
}
static ssize_t cyttsp5_interrupt_count_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
mutex_lock(&dd->sysfs_lock);
dd->interrupt_count = 0;
mutex_unlock(&dd->sysfs_lock);
return size;
}
static DEVICE_ATTR(int_count, S_IRUSR | S_IWUSR,
cyttsp5_interrupt_count_show, cyttsp5_interrupt_count_store);
static ssize_t cyttsp5_formated_output_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
int val;
mutex_lock(&dd->sysfs_lock);
val = dd->formated_output;
mutex_unlock(&dd->sysfs_lock);
return scnprintf(buf, CY_MAX_PRBUF_SIZE,
"Formated debug output: %x\n", val);
}
static ssize_t cyttsp5_formated_output_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
unsigned long value;
int rc;
rc = kstrtoul(buf, 10, &value);
if (rc < 0) {
dev_err(dev, "%s: Invalid value\n", __func__);
return size;
}
/* Expecting only 0 or 1 */
if (value != 0 && value != 1) {
dev_err(dev, "%s: Invalid value %lu\n", __func__, value);
return size;
}
mutex_lock(&dd->sysfs_lock);
dd->formated_output = value;
mutex_unlock(&dd->sysfs_lock);
return size;
}
static DEVICE_ATTR(formated_output, S_IRUSR | S_IWUSR,
cyttsp5_formated_output_show, cyttsp5_formated_output_store);
static int cyttsp5_debug_probe(struct device *dev, void **data)
{
struct cyttsp5_debug_data *dd;
int rc;
/* get context and debug print buffers */
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
if (!dd) {
rc = -ENOMEM;
goto cyttsp5_debug_probe_alloc_failed;
}
rc = device_create_file(dev, &dev_attr_int_count);
if (rc) {
dev_err(dev, "%s: Error, could not create int_count\n",
__func__);
goto cyttsp5_debug_probe_create_int_count_failed;
}
rc = device_create_file(dev, &dev_attr_formated_output);
if (rc) {
dev_err(dev, "%s: Error, could not create formated_output\n",
__func__);
goto cyttsp5_debug_probe_create_formated_failed;
}
mutex_init(&dd->sysfs_lock);
dd->dev = dev;
*data = dd;
dd->si = cmd->request_sysinfo(dev);
if (!dd->si) {
dev_err(dev, "%s: Fail get sysinfo pointer from core\n",
__func__);
rc = -ENODEV;
goto cyttsp5_debug_probe_sysinfo_failed;
}
rc = cmd->subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
if (rc < 0) {
dev_err(dev, "%s: Error, could not subscribe attention cb\n",
__func__);
goto cyttsp5_debug_probe_subscribe_failed;
}
return 0;
cyttsp5_debug_probe_subscribe_failed:
cyttsp5_debug_probe_sysinfo_failed:
device_remove_file(dev, &dev_attr_formated_output);
cyttsp5_debug_probe_create_formated_failed:
device_remove_file(dev, &dev_attr_int_count);
cyttsp5_debug_probe_create_int_count_failed:
kfree(dd);
cyttsp5_debug_probe_alloc_failed:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
static void cyttsp5_debug_release(struct device *dev, void *data)
{
struct cyttsp5_debug_data *dd = data;
int rc;
rc = cmd->unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
if (rc < 0) {
dev_err(dev, "%s: Error, could not un-subscribe attention\n",
__func__);
goto cyttsp5_debug_release_exit;
}
cyttsp5_debug_release_exit:
device_remove_file(dev, &dev_attr_formated_output);
device_remove_file(dev, &dev_attr_int_count);
kfree(dd);
}
static struct cyttsp5_module debug_module = {
.name = CYTTSP5_DEBUG_NAME,
.probe = cyttsp5_debug_probe,
.release = cyttsp5_debug_release,
};
static int __init cyttsp5_debug_init(void)
{
int rc;
cmd = cyttsp5_get_commands();
if (!cmd)
return -EINVAL;
rc = cyttsp5_register_module(&debug_module);
if (rc < 0) {
pr_err("%s: Error, failed registering module\n",
__func__);
return rc;
}
pr_info("%s: Parade TTSP Debug Driver (Built %s) rc=%d\n",
__func__, CY_DRIVER_VERSION, rc);
return 0;
}
module_init(cyttsp5_debug_init);
static void __exit cyttsp5_debug_exit(void)
{
cyttsp5_unregister_module(&debug_module);
}
module_exit(cyttsp5_debug_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Debug Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,750 @@
/*
* cyttsp5_devtree.c
* Parade TrueTouch(TM) Standard Product V5 Device Tree Support Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
/* cyttsp */
#include "cyttsp5_regs.h"
#include <linux/platform_data/cyttsp5.h>
#define ENABLE_VIRTUAL_KEYS
#define MAX_NAME_LENGTH 64
enum cyttsp5_device_type {
DEVICE_MT,
DEVICE_BTN,
DEVICE_PROXIMITY,
DEVICE_TYPE_MAX,
};
struct cyttsp5_device_pdata_func {
void * (*create_and_get_pdata)(struct device_node *);
void (*free_pdata)(void *);
};
struct cyttsp5_pdata_ptr {
void **pdata;
};
#ifdef ENABLE_VIRTUAL_KEYS
static struct kobject *board_properties_kobj;
struct cyttsp5_virtual_keys {
struct kobj_attribute kobj_attr;
u16 *data;
int size;
};
#endif
struct cyttsp5_extended_mt_platform_data {
struct cyttsp5_mt_platform_data pdata;
#ifdef ENABLE_VIRTUAL_KEYS
struct cyttsp5_virtual_keys vkeys;
#endif
};
static inline int get_inp_dev_name(struct device_node *dev_node,
const char **inp_dev_name)
{
return of_property_read_string(dev_node, "cy,inp_dev_name",
inp_dev_name);
}
static s16 *create_and_get_u16_array(struct device_node *dev_node,
const char *name, int *size)
{
const __be32 *values;
s16 *val_array;
int len;
int sz;
int rc;
int i;
values = of_get_property(dev_node, name, &len);
if (values == NULL)
return NULL;
sz = len / sizeof(u32);
pr_debug("%s: %s size:%d\n", __func__, name, sz);
val_array = kcalloc(sz, sizeof(s16), GFP_KERNEL);
if (!val_array) {
rc = -ENOMEM;
goto fail;
}
for (i = 0; i < sz; i++)
val_array[i] = (s16)be32_to_cpup(values++);
*size = sz;
return val_array;
fail:
return ERR_PTR(rc);
}
static struct touch_framework *create_and_get_touch_framework(
struct device_node *dev_node)
{
struct touch_framework *frmwrk;
s16 *abs;
int size;
int rc;
abs = create_and_get_u16_array(dev_node, "cy,abs", &size);
if (IS_ERR_OR_NULL(abs))
return (void *)abs;
/* Check for valid abs size */
if (size % CY_NUM_ABS_SET) {
rc = -EINVAL;
goto fail_free_abs;
}
frmwrk = kzalloc(sizeof(*frmwrk), GFP_KERNEL);
if (!frmwrk) {
rc = -ENOMEM;
goto fail_free_abs;
}
frmwrk->abs = abs;
frmwrk->size = size;
return frmwrk;
fail_free_abs:
kfree(abs);
return ERR_PTR(rc);
}
static void free_touch_framework(struct touch_framework *frmwrk)
{
kfree(frmwrk->abs);
kfree(frmwrk);
}
#ifdef ENABLE_VIRTUAL_KEYS
#define VIRTUAL_KEY_ELEMENT_SIZE 5
static ssize_t virtual_keys_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct cyttsp5_virtual_keys *vkeys = container_of(attr,
struct cyttsp5_virtual_keys, kobj_attr);
u16 *data = vkeys->data;
int size = vkeys->size;
int index;
int i;
index = 0;
for (i = 0; i < size; i += VIRTUAL_KEY_ELEMENT_SIZE)
index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
"0x01:%d:%d:%d:%d:%d\n",
data[i], data[i+1], data[i+2], data[i+3], data[i+4]);
return index;
}
static int setup_virtual_keys(struct device_node *dev_node,
const char *inp_dev_name, struct cyttsp5_virtual_keys *vkeys)
{
char *name;
u16 *data;
int size;
int rc;
data = create_and_get_u16_array(dev_node, "cy,virtual_keys", &size);
if (data == NULL)
return 0;
else if (IS_ERR(data)) {
rc = PTR_ERR(data);
goto fail;
}
/* Check for valid virtual keys size */
if (size % VIRTUAL_KEY_ELEMENT_SIZE) {
rc = -EINVAL;
goto fail_free_data;
}
name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
if (!name) {
rc = -ENOMEM;
goto fail_free_data;
}
snprintf(name, MAX_NAME_LENGTH, "virtualkeys.%s", inp_dev_name);
vkeys->data = data;
vkeys->size = size;
/* TODO: Instantiate in board file and export it */
if (board_properties_kobj == NULL)
board_properties_kobj =
kobject_create_and_add("board_properties", NULL);
if (board_properties_kobj == NULL) {
pr_err("%s: Cannot get board_properties kobject!\n", __func__);
rc = -EINVAL;
goto fail_free_name;
}
/* Initialize dynamic SysFs attribute */
sysfs_attr_init(&vkeys->kobj_attr.attr);
vkeys->kobj_attr.attr.name = name;
vkeys->kobj_attr.attr.mode = S_IRUGO;
vkeys->kobj_attr.show = virtual_keys_show;
rc = sysfs_create_file(board_properties_kobj, &vkeys->kobj_attr.attr);
if (rc)
goto fail_del_kobj;
return 0;
fail_del_kobj:
kobject_del(board_properties_kobj);
fail_free_name:
kfree(name);
vkeys->kobj_attr.attr.name = NULL;
fail_free_data:
kfree(data);
vkeys->data = NULL;
fail:
return rc;
}
static void free_virtual_keys(struct cyttsp5_virtual_keys *vkeys)
{
if (board_properties_kobj)
sysfs_remove_file(board_properties_kobj,
&vkeys->kobj_attr.attr);
kobject_del(board_properties_kobj);
board_properties_kobj = NULL;
kfree(vkeys->data);
kfree(vkeys->kobj_attr.attr.name);
}
#endif
static void *create_and_get_mt_pdata(struct device_node *dev_node)
{
struct cyttsp5_extended_mt_platform_data *ext_pdata;
struct cyttsp5_mt_platform_data *pdata;
u32 value;
int rc;
ext_pdata = kzalloc(sizeof(*ext_pdata), GFP_KERNEL);
if (!ext_pdata) {
rc = -ENOMEM;
goto fail;
}
pdata = &ext_pdata->pdata;
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
/* Optional fields */
rc = of_property_read_u32(dev_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = of_property_read_u32(dev_node, "cy,vkeys_x", &value);
if (!rc)
pdata->vkeys_x = value;
rc = of_property_read_u32(dev_node, "cy,vkeys_y", &value);
if (!rc)
pdata->vkeys_y = value;
/* Required fields */
pdata->frmwrk = create_and_get_touch_framework(dev_node);
if (pdata->frmwrk == NULL) {
rc = -EINVAL;
goto fail_free_pdata;
} else if (IS_ERR(pdata->frmwrk)) {
rc = PTR_ERR(pdata->frmwrk);
goto fail_free_pdata;
}
#ifdef ENABLE_VIRTUAL_KEYS
rc = setup_virtual_keys(dev_node, pdata->inp_dev_name,
&ext_pdata->vkeys);
if (rc) {
pr_err("%s: Cannot setup virtual keys!\n", __func__);
goto fail_free_pdata;
}
#endif
return pdata;
fail_free_pdata:
kfree(ext_pdata);
fail:
return ERR_PTR(rc);
}
static void free_mt_pdata(void *pdata)
{
struct cyttsp5_mt_platform_data *mt_pdata =
(struct cyttsp5_mt_platform_data *)pdata;
struct cyttsp5_extended_mt_platform_data *ext_mt_pdata =
container_of(mt_pdata,
struct cyttsp5_extended_mt_platform_data, pdata);
free_touch_framework(mt_pdata->frmwrk);
#ifdef ENABLE_VIRTUAL_KEYS
free_virtual_keys(&ext_mt_pdata->vkeys);
#endif
kfree(ext_mt_pdata);
}
static void *create_and_get_btn_pdata(struct device_node *dev_node)
{
struct cyttsp5_btn_platform_data *pdata;
int rc;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
rc = -ENOMEM;
goto fail;
}
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
return pdata;
fail_free_pdata:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_btn_pdata(void *pdata)
{
struct cyttsp5_btn_platform_data *btn_pdata =
(struct cyttsp5_btn_platform_data *)pdata;
kfree(btn_pdata);
}
static void *create_and_get_proximity_pdata(struct device_node *dev_node)
{
struct cyttsp5_proximity_platform_data *pdata;
int rc;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
rc = -ENOMEM;
goto fail;
}
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
pdata->frmwrk = create_and_get_touch_framework(dev_node);
if (pdata->frmwrk == NULL) {
rc = -EINVAL;
goto fail_free_pdata;
} else if (IS_ERR(pdata->frmwrk)) {
rc = PTR_ERR(pdata->frmwrk);
goto fail_free_pdata;
}
return pdata;
fail_free_pdata:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_proximity_pdata(void *pdata)
{
struct cyttsp5_proximity_platform_data *proximity_pdata =
(struct cyttsp5_proximity_platform_data *)pdata;
free_touch_framework(proximity_pdata->frmwrk);
kfree(proximity_pdata);
}
static struct cyttsp5_device_pdata_func device_pdata_funcs[DEVICE_TYPE_MAX] = {
[DEVICE_MT] = {
.create_and_get_pdata = create_and_get_mt_pdata,
.free_pdata = free_mt_pdata,
},
[DEVICE_BTN] = {
.create_and_get_pdata = create_and_get_btn_pdata,
.free_pdata = free_btn_pdata,
},
[DEVICE_PROXIMITY] = {
.create_and_get_pdata = create_and_get_proximity_pdata,
.free_pdata = free_proximity_pdata,
},
};
static struct cyttsp5_pdata_ptr pdata_ptr[DEVICE_TYPE_MAX];
static const char *device_names[DEVICE_TYPE_MAX] = {
[DEVICE_MT] = "cy,mt",
[DEVICE_BTN] = "cy,btn",
[DEVICE_PROXIMITY] = "cy,proximity",
};
static void set_pdata_ptr(struct cyttsp5_platform_data *pdata)
{
pdata_ptr[DEVICE_MT].pdata = (void **)&pdata->mt_pdata;
pdata_ptr[DEVICE_BTN].pdata = (void **)&pdata->btn_pdata;
pdata_ptr[DEVICE_PROXIMITY].pdata = (void **)&pdata->prox_pdata;
}
static int get_device_type(struct device_node *dev_node,
enum cyttsp5_device_type *type)
{
const char *name;
enum cyttsp5_device_type t;
int rc;
rc = of_property_read_string(dev_node, "name", &name);
if (rc)
return rc;
for (t = 0; t < DEVICE_TYPE_MAX; t++)
if (!strncmp(name, device_names[t], MAX_NAME_LENGTH)) {
*type = t;
return 0;
}
return -EINVAL;
}
static inline void *create_and_get_device_pdata(struct device_node *dev_node,
enum cyttsp5_device_type type)
{
return device_pdata_funcs[type].create_and_get_pdata(dev_node);
}
static inline void free_device_pdata(enum cyttsp5_device_type type)
{
device_pdata_funcs[type].free_pdata(*pdata_ptr[type].pdata);
}
static struct touch_settings *create_and_get_touch_setting(
struct device_node *core_node, const char *name)
{
struct touch_settings *setting;
char *tag_name;
u32 tag_value;
u16 *data;
int size;
int rc;
data = create_and_get_u16_array(core_node, name, &size);
if (IS_ERR_OR_NULL(data))
return (void *)data;
pr_debug("%s: Touch setting:'%s' size:%d\n", __func__, name, size);
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
if (!setting) {
rc = -ENOMEM;
goto fail_free_data;
}
setting->data = (u8 *)data;
setting->size = size;
tag_name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
if (!tag_name) {
rc = -ENOMEM;
goto fail_free_setting;
}
snprintf(tag_name, MAX_NAME_LENGTH, "%s-tag", name);
rc = of_property_read_u32(core_node, tag_name, &tag_value);
if (!rc)
setting->tag = tag_value;
kfree(tag_name);
return setting;
fail_free_setting:
kfree(setting);
fail_free_data:
kfree(data);
return ERR_PTR(rc);
}
static void free_touch_setting(struct touch_settings *setting)
{
if (setting) {
kfree(setting->data);
kfree(setting);
}
}
static char *touch_setting_names[CY_IC_GRPNUM_NUM] = {
NULL, /* CY_IC_GRPNUM_RESERVED */
"cy,cmd_regs", /* CY_IC_GRPNUM_CMD_REGS */
"cy,tch_rep", /* CY_IC_GRPNUM_TCH_REP */
"cy,data_rec", /* CY_IC_GRPNUM_DATA_REC */
"cy,test_rec", /* CY_IC_GRPNUM_TEST_REC */
"cy,pcfg_rec", /* CY_IC_GRPNUM_PCFG_REC */
"cy,tch_parm_val", /* CY_IC_GRPNUM_TCH_PARM_VAL */
"cy,tch_parm_size", /* CY_IC_GRPNUM_TCH_PARM_SIZE */
NULL, /* CY_IC_GRPNUM_RESERVED1 */
NULL, /* CY_IC_GRPNUM_RESERVED2 */
"cy,opcfg_rec", /* CY_IC_GRPNUM_OPCFG_REC */
"cy,ddata_rec", /* CY_IC_GRPNUM_DDATA_REC */
"cy,mdata_rec", /* CY_IC_GRPNUM_MDATA_REC */
"cy,test_regs", /* CY_IC_GRPNUM_TEST_REGS */
"cy,btn_keys", /* CY_IC_GRPNUM_BTN_KEYS */
NULL, /* CY_IC_GRPNUM_TTHE_REGS */
};
static struct cyttsp5_core_platform_data *create_and_get_core_pdata(
struct device_node *core_node)
{
struct cyttsp5_core_platform_data *pdata;
u32 value;
int rc;
int i;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
rc = -ENOMEM;
goto fail;
}
/* Required fields */
pdata->irq_gpio = of_get_named_gpio(core_node, "cy,irq_gpio", 0);
if (!gpio_is_valid(pdata->irq_gpio)) {
rc = -ENODEV;
pr_err("Invalid irq_gpio");
goto fail_free;
}
rc = of_property_read_u32(core_node, "cy,hid_desc_register", &value);
if (rc)
goto fail_free;
pdata->hid_desc_register = value;
/* Optional fields */
/* rst_gpio is optional since a platform may use
* power cycling instead of using the XRES pin
*/
pdata->rst_gpio = of_get_named_gpio(core_node, "cy,rst_gpio", 0);
rc = of_property_read_u32(core_node, "cy,level_irq_udelay", &value);
if (!rc)
pdata->level_irq_udelay = value;
rc = of_property_read_u32(core_node, "cy,vendor_id", &value);
if (!rc)
pdata->vendor_id = value;
rc = of_property_read_u32(core_node, "cy,product_id", &value);
if (!rc)
pdata->product_id = value;
rc = of_property_read_u32(core_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = of_property_read_u32(core_node, "cy,easy_wakeup_gesture", &value);
if (!rc)
pdata->easy_wakeup_gesture = (u8)value;
pdata->fb_blanking_disabled = of_property_read_bool(core_node, "cy,fb_blanking_disabled");
for (i = 0; (unsigned int)i < ARRAY_SIZE(touch_setting_names); i++) {
if (touch_setting_names[i] == NULL)
continue;
pdata->sett[i] = create_and_get_touch_setting(core_node,
touch_setting_names[i]);
if (IS_ERR(pdata->sett[i])) {
rc = PTR_ERR(pdata->sett[i]);
goto fail_free_sett;
} else if (pdata->sett[i] == NULL)
pr_debug("%s: No data for setting '%s'\n", __func__,
touch_setting_names[i]);
}
pr_debug("%s: irq_gpio:%d rst_gpio:%d\n"
"hid_desc_register:%d level_irq_udelay:%d vendor_id:%d product_id:%d\n"
"flags:%d easy_wakeup_gesture:%d\n", __func__,
pdata->irq_gpio, pdata->rst_gpio,
pdata->hid_desc_register,
pdata->level_irq_udelay, pdata->vendor_id, pdata->product_id,
pdata->flags, pdata->easy_wakeup_gesture);
pdata->xres = cyttsp5_xres;
pdata->init = cyttsp5_init;
pdata->power = cyttsp5_power;
pdata->detect = cyttsp5_detect;
pdata->irq_stat = cyttsp5_irq_stat;
return pdata;
fail_free_sett:
for (i--; i >= 0; i--)
free_touch_setting(pdata->sett[i]);
fail_free:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_core_pdata(void *pdata)
{
struct cyttsp5_core_platform_data *core_pdata = pdata;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(touch_setting_names); i++)
free_touch_setting(core_pdata->sett[i]);
kfree(core_pdata);
}
int cyttsp5_devtree_create_and_get_pdata(struct device *adap_dev)
{
struct cyttsp5_platform_data *pdata;
struct device_node *core_node, *dev_node, *dev_node_fail;
enum cyttsp5_device_type type;
int count = 0;
int rc = 0;
if (!adap_dev->of_node)
return 0;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
adap_dev->platform_data = pdata;
set_pdata_ptr(pdata);
/* There should be only one core node */
for_each_child_of_node(adap_dev->of_node, core_node) {
const char *name;
rc = of_property_read_string(core_node, "name", &name);
if (!rc)
pr_debug("%s: name:%s\n", __func__, name);
pdata->core_pdata = create_and_get_core_pdata(core_node);
if (IS_ERR(pdata->core_pdata)) {
rc = PTR_ERR(pdata->core_pdata);
break;
}
/* Increment reference count */
of_node_get(core_node);
for_each_child_of_node(core_node, dev_node) {
count++;
rc = get_device_type(dev_node, &type);
if (rc)
break;
*pdata_ptr[type].pdata
= create_and_get_device_pdata(dev_node, type);
if (IS_ERR(*pdata_ptr[type].pdata))
rc = PTR_ERR(*pdata_ptr[type].pdata);
if (rc)
break;
/* Increment reference count */
of_node_get(dev_node);
}
if (rc) {
free_core_pdata(pdata->core_pdata);
of_node_put(core_node);
for_each_child_of_node(core_node, dev_node_fail) {
if (dev_node == dev_node_fail)
break;
rc = get_device_type(dev_node, &type);
if (rc)
break;
free_device_pdata(type);
of_node_put(dev_node);
}
break;
}
pdata->loader_pdata = &_cyttsp5_loader_platform_data;
}
pr_debug("%s: %d child node(s) found\n", __func__, count);
return rc;
}
EXPORT_SYMBOL_GPL(cyttsp5_devtree_create_and_get_pdata);
int cyttsp5_devtree_clean_pdata(struct device *adap_dev)
{
struct cyttsp5_platform_data *pdata;
struct device_node *core_node, *dev_node;
enum cyttsp5_device_type type;
int rc = 0;
if (!adap_dev->of_node)
return 0;
pdata = dev_get_platdata(adap_dev);
set_pdata_ptr(pdata);
for_each_child_of_node(adap_dev->of_node, core_node) {
free_core_pdata(pdata->core_pdata);
of_node_put(core_node);
for_each_child_of_node(core_node, dev_node) {
rc = get_device_type(dev_node, &type);
if (rc)
break;
free_device_pdata(type);
of_node_put(dev_node);
}
}
return rc;
}
EXPORT_SYMBOL_GPL(cyttsp5_devtree_clean_pdata);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product DeviceTree Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View File

@ -0,0 +1,221 @@
/*
* cyttsp5_i2c.c
* Parade TrueTouch(TM) Standard Product V5 I2C Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/i2c.h>
#include <linux/version.h>
#define CY_I2C_DATA_SIZE (2 * 256)
static int cyttsp5_i2c_read_default(struct device *dev, void *buf, int size)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
if (!buf || !size || size > CY_I2C_DATA_SIZE)
return -EINVAL;
rc = i2c_master_recv(client, buf, size);
return (rc < 0) ? rc : rc != size ? -EIO : 0;
}
static int cyttsp5_i2c_read_default_nosize(struct device *dev, u8 *buf, u32 max)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msgs[2];
u8 msg_count = 1;
int rc;
u32 size;
if (!buf)
return -EINVAL;
msgs[0].addr = client->addr;
msgs[0].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
msgs[0].len = 2;
msgs[0].buf = buf;
rc = i2c_transfer(client->adapter, msgs, msg_count);
if (rc < 0 || rc != msg_count)
return (rc < 0) ? rc : -EIO;
size = get_unaligned_le16(&buf[0]);
if (!size || size == 2 || size >= CY_PIP_1P7_EMPTY_BUF)
/* Before PIP 1.7, empty buffer is 0x0002;
From PIP 1.7, empty buffer is 0xFFXX */
return 0;
if (size > max)
return -EINVAL;
rc = i2c_master_recv(client, buf, size);
return (rc < 0) ? rc : rc != (int)size ? -EIO : 0;
}
static int cyttsp5_i2c_write_read_specific(struct device *dev, u8 write_len,
u8 *write_buf, u8 *read_buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msgs[2];
u8 msg_count = 1;
int rc;
if (!write_buf || !write_len)
return -EINVAL;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags & I2C_M_TEN;
msgs[0].len = write_len;
msgs[0].buf = write_buf;
rc = i2c_transfer(client->adapter, msgs, msg_count);
if (rc < 0 || rc != msg_count)
return (rc < 0) ? rc : -EIO;
rc = 0;
if (read_buf)
rc = cyttsp5_i2c_read_default_nosize(dev, read_buf,
CY_I2C_DATA_SIZE);
return rc;
}
static struct cyttsp5_bus_ops cyttsp5_i2c_bus_ops = {
.bustype = BUS_I2C,
.read_default = cyttsp5_i2c_read_default,
.read_default_nosize = cyttsp5_i2c_read_default_nosize,
.write_read_specific = cyttsp5_i2c_write_read_specific,
};
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
static const struct of_device_id cyttsp5_i2c_of_match[] = {
{ .compatible = "cy,cyttsp5_i2c_adapter", },
{ }
};
MODULE_DEVICE_TABLE(of, cyttsp5_i2c_of_match);
#endif
static int cyttsp5_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct device *dev = &client->dev;
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
int rc;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "I2C functionality not Supported\n");
return -EIO;
}
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev);
if (match) {
rc = cyttsp5_devtree_create_and_get_pdata(dev);
if (rc < 0)
return rc;
}
#endif
rc = cyttsp5_probe(&cyttsp5_i2c_bus_ops, &client->dev, client->irq,
CY_I2C_DATA_SIZE);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
if (rc && match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return rc;
}
static int cyttsp5_i2c_remove(struct i2c_client *client)
{
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
struct device *dev = &client->dev;
const struct of_device_id *match;
#endif
struct cyttsp5_core_data *cd = i2c_get_clientdata(client);
cyttsp5_release(cd);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev);
if (match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return 0;
}
static const struct i2c_device_id cyttsp5_i2c_id[] = {
{ CYTTSP5_I2C_NAME, 0, },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
static struct i2c_driver cyttsp5_i2c_driver = {
.driver = {
.name = CYTTSP5_I2C_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp5_pm_ops,
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
.of_match_table = cyttsp5_i2c_of_match,
#endif
},
.probe = cyttsp5_i2c_probe,
.remove = cyttsp5_i2c_remove,
.id_table = cyttsp5_i2c_id,
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
module_i2c_driver(cyttsp5_i2c_driver);
#else
static int __init cyttsp5_i2c_init(void)
{
int rc = i2c_add_driver(&cyttsp5_i2c_driver);
pr_info("%s: Parade TTSP I2C Driver (Built %s) rc=%d\n",
__func__, CY_DRIVER_VERSION, rc);
return rc;
}
module_init(cyttsp5_i2c_init);
static void __exit cyttsp5_i2c_exit(void)
{
i2c_del_driver(&cyttsp5_i2c_driver);
}
module_exit(cyttsp5_i2c_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product I2C driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,758 @@
/*
* cyttsp5_mt_common.c
* Parade TrueTouch(TM) Standard Product V5 Multi-Touch Reports Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_MT_NAME "cyttsp5_mt"
#define MT_PARAM_SIGNAL(md, sig_ost) PARAM_SIGNAL(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_MIN(md, sig_ost) PARAM_MIN(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_MAX(md, sig_ost) PARAM_MAX(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_FUZZ(md, sig_ost) PARAM_FUZZ(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_FLAT(md, sig_ost) PARAM_FLAT(md->pdata->frmwrk, sig_ost)
void cyttsp5_pr_buf_debug(struct device *dev, u8 *dptr, int size,
const char *data_name)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
u8 *pr_buf = cd->pr_buf;
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]);
if (size)
dev_err(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name,
size - 1, pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
else
dev_err(dev, "%s: %s[]\n", __func__, data_name);
}
static void cyttsp5_mt_lift_all(struct cyttsp5_mt_data *md)
{
int max = md->si->tch_abs[CY_TCH_T].max;
if (md->num_prv_rec != 0) {
if (md->mt_function.report_slot_liftoff)
md->mt_function.report_slot_liftoff(md, max);
input_sync(md->input);
md->num_prv_rec = 0;
}
}
static void cyttsp5_get_touch_axis(struct cyttsp5_mt_data *md,
int *axis, int size, int max, u8 *xy_data, int bofs)
{
int nbyte;
int next;
for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
dev_vdbg(md->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 + ((xy_data[next] >> bofs) << (nbyte * 8));
next++;
}
*axis &= max - 1;
dev_vdbg(md->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]);
}
static void cyttsp5_get_touch_hdr(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *touch, u8 *xy_mode)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
enum cyttsp5_tch_hdr hdr;
for (hdr = CY_TCH_TIME; hdr < CY_TCH_NUM_HDR; hdr++) {
if (!si->tch_hdr[hdr].report)
continue;
cyttsp5_get_touch_axis(md, &touch->hdr[hdr],
si->tch_hdr[hdr].size,
si->tch_hdr[hdr].max,
xy_mode + si->tch_hdr[hdr].ofs,
si->tch_hdr[hdr].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_hdr_string[hdr],
touch->hdr[hdr], touch->hdr[hdr]);
}
dev_dbg(dev,
"%s: time=%X tch_num=%d lo=%d noise=%d counter=%d\n",
__func__,
touch->hdr[CY_TCH_TIME],
touch->hdr[CY_TCH_NUM],
touch->hdr[CY_TCH_LO],
touch->hdr[CY_TCH_NOISE],
touch->hdr[CY_TCH_COUNTER]);
}
static void cyttsp5_get_touch_record(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *touch, u8 *xy_data)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
enum cyttsp5_tch_abs abs;
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
if (!si->tch_abs[abs].report)
continue;
cyttsp5_get_touch_axis(md, &touch->abs[abs],
si->tch_abs[abs].size,
si->tch_abs[abs].max,
xy_data + si->tch_abs[abs].ofs,
si->tch_abs[abs].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_abs_string[abs],
touch->abs[abs], touch->abs[abs]);
}
}
static void cyttsp5_mt_process_touch(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *touch)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
int tmp;
bool flipped;
/* Orientation is signed */
touch->abs[CY_TCH_OR] = (int8_t)touch->abs[CY_TCH_OR];
if (md->pdata->flags & CY_MT_FLAG_FLIP) {
tmp = touch->abs[CY_TCH_X];
touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
touch->abs[CY_TCH_Y] = tmp;
if (touch->abs[CY_TCH_OR] > 0)
touch->abs[CY_TCH_OR] =
md->or_max - touch->abs[CY_TCH_OR];
else
touch->abs[CY_TCH_OR] =
md->or_min - touch->abs[CY_TCH_OR];
flipped = true;
} else
flipped = false;
if (md->pdata->flags & CY_MT_FLAG_INV_X) {
if (flipped)
touch->abs[CY_TCH_X] = si->sensing_conf_data.res_y -
touch->abs[CY_TCH_X];
else
touch->abs[CY_TCH_X] = si->sensing_conf_data.res_x -
touch->abs[CY_TCH_X];
touch->abs[CY_TCH_OR] *= -1;
}
if (md->pdata->flags & CY_MT_FLAG_INV_Y) {
if (flipped)
touch->abs[CY_TCH_Y] = si->sensing_conf_data.res_x -
touch->abs[CY_TCH_Y];
else
touch->abs[CY_TCH_Y] = si->sensing_conf_data.res_y -
touch->abs[CY_TCH_Y];
touch->abs[CY_TCH_OR] *= -1;
}
/* Convert MAJOR/MINOR from mm to resolution */
tmp = touch->abs[CY_TCH_MAJ] * 100 * si->sensing_conf_data.res_x;
touch->abs[CY_TCH_MAJ] = tmp / si->sensing_conf_data.len_x;
tmp = touch->abs[CY_TCH_MIN] * 100 * si->sensing_conf_data.res_x;
touch->abs[CY_TCH_MIN] = tmp / si->sensing_conf_data.len_x;
dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
__func__, flipped ? "true" : "false",
md->pdata->flags & CY_MT_FLAG_INV_X ? "true" : "false",
md->pdata->flags & CY_MT_FLAG_INV_Y ? "true" : "false",
touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
}
static void cyttsp5_report_event(struct cyttsp5_mt_data *md, int event,
int value)
{
int sig = MT_PARAM_SIGNAL(md, event);
if (sig != CY_IGNORE_VALUE)
input_report_abs(md->input, sig, value);
}
static void cyttsp5_get_mt_touches(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *tch, int num_cur_tch)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
int sig;
int i, j, t = 0;
DECLARE_BITMAP(ids, si->tch_abs[CY_TCH_T].max);
int mt_sync_count = 0;
u8 *tch_addr;
bitmap_zero(ids, si->tch_abs[CY_TCH_T].max);
memset(tch->abs, 0, sizeof(tch->abs));
for (i = 0; i < num_cur_tch; i++) {
tch_addr = si->xy_data + (i * si->desc.tch_record_size);
cyttsp5_get_touch_record(md, tch, tch_addr);
/* Discard proximity event */
if (tch->abs[CY_TCH_O] == CY_OBJ_PROXIMITY) {
dev_vdbg(dev, "%s: Discarding proximity event\n",
__func__);
continue;
}
/* Validate track_id */
t = tch->abs[CY_TCH_T];
if (t < md->t_min || t > md->t_max) {
dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
__func__, i, t, md->t_max);
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
mt_sync_count++;
cyttsp5_pr_buf_debug(dev, si->xy_mode, si->desc.tch_header_size,
"Err xy_mode");
cyttsp5_pr_buf_debug(dev, si->xy_data,
num_cur_tch* si->desc.tch_record_size, "Err xy_data");
continue;
}
/* Lift-off */
if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF) {
dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
__func__, t, tch->abs[CY_TCH_E]);
goto cyttsp5_get_mt_touches_pr_tch;
}
/* Process touch */
cyttsp5_mt_process_touch(md, tch);
/* use 0 based track id's */
t -= md->t_min;
sig = MT_PARAM_SIGNAL(md, CY_ABS_ID_OST);
if (sig != CY_IGNORE_VALUE) {
if (md->mt_function.input_report)
md->mt_function.input_report(md->input, sig,
t, tch->abs[CY_TCH_O]);
__set_bit(t, ids);
}
/* If touch type is hover, send P as distance, reset P */
if (tch->abs[CY_TCH_O] == CY_OBJ_HOVER) {
/* CY_ABS_D_OST signal must be in touch framework */
cyttsp5_report_event(md, CY_ABS_D_OST,
tch->abs[CY_TCH_P]);
tch->abs[CY_TCH_P] = 0;
} else
cyttsp5_report_event(md, CY_ABS_D_OST, 0);
/* all devices: position and pressure fields */
for (j = 0; j <= CY_ABS_W_OST; j++) {
if (!si->tch_abs[j].report)
continue;
cyttsp5_report_event(md, CY_ABS_X_OST + j,
tch->abs[CY_TCH_X + j]);
}
/* Get the extended touch fields */
for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
if (!si->tch_abs[CY_ABS_MAJ_OST + j].report)
continue;
cyttsp5_report_event(md, CY_ABS_MAJ_OST + j,
tch->abs[CY_TCH_MAJ + j]);
}
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
mt_sync_count++;
cyttsp5_get_mt_touches_pr_tch:
dev_dbg(dev,
"%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d obj=%d tip=%d\n",
__func__, t,
tch->abs[CY_TCH_X],
tch->abs[CY_TCH_Y],
tch->abs[CY_TCH_P],
tch->abs[CY_TCH_MAJ],
tch->abs[CY_TCH_MIN],
tch->abs[CY_TCH_OR],
tch->abs[CY_TCH_E],
tch->abs[CY_TCH_O],
tch->abs[CY_TCH_TIP]);
}
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input,
si->tch_abs[CY_TCH_T].max, mt_sync_count, ids);
md->num_prv_rec = num_cur_tch;
}
/* read xy_data for all current touches */
static int cyttsp5_xy_worker(struct cyttsp5_mt_data *md)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
int max_tch = si->sensing_conf_data.max_tch;
struct cyttsp5_touch tch;
u8 num_cur_tch;
int rc = 0;
cyttsp5_get_touch_hdr(md, &tch, si->xy_mode + 3);
num_cur_tch = tch.hdr[CY_TCH_NUM];
if (num_cur_tch > max_tch) {
dev_err(dev, "%s: Num touch err detected (n=%d)\n",
__func__, num_cur_tch);
num_cur_tch = max_tch;
}
if (tch.hdr[CY_TCH_LO]) {
dev_dbg(dev, "%s: Large area detected\n", __func__);
if (md->pdata->flags & CY_MT_FLAG_NO_TOUCH_ON_LO)
num_cur_tch = 0;
}
if (num_cur_tch == 0 && md->num_prv_rec == 0)
goto cyttsp5_xy_worker_exit;
/* extract xy_data for all currently reported touches */
dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
num_cur_tch);
if (num_cur_tch)
cyttsp5_get_mt_touches(md, &tch, num_cur_tch);
else
cyttsp5_mt_lift_all(md);
rc = 0;
cyttsp5_xy_worker_exit:
return rc;
}
static void cyttsp5_mt_send_dummy_event(struct cyttsp5_core_data *cd,
struct cyttsp5_mt_data *md)
{
#ifndef EASYWAKE_TSG6
/* TSG5 EasyWake */
unsigned long ids = 0;
/* for easy wakeup */
if (md->mt_function.input_report)
md->mt_function.input_report(md->input, ABS_MT_TRACKING_ID,
0, CY_OBJ_STANDARD_FINGER);
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input, 0, 1, &ids);
if (md->mt_function.report_slot_liftoff)
md->mt_function.report_slot_liftoff(md, 1);
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input, 1, 1, &ids);
#else
/* TSG6 FW1.3 EasyWake */
u8 key_value;
switch (cd->gesture_id) {
case GESTURE_DOUBLE_TAP:
key_value = KEY_F1;
break;
case GESTURE_TWO_FINGERS_SLIDE:
key_value = KEY_F2;
break;
case GESTURE_TOUCH_DETECTED:
key_value = KEY_F3;
break;
case GESTURE_PUSH_BUTTON:
key_value = KEY_F4;
break;
case GESTURE_SINGLE_SLIDE_DE_TX:
key_value = KEY_F5;
break;
case GESTURE_SINGLE_SLIDE_IN_TX:
key_value = KEY_F6;
break;
case GESTURE_SINGLE_SLIDE_DE_RX:
key_value = KEY_F7;
break;
case GESTURE_SINGLE_SLIDE_IN_RX:
key_value = KEY_F8;
break;
default:
break;
}
input_report_key(md->input, key_value, 1);
mdelay(10);
input_report_key(md->input, key_value, 0);
input_sync(md->input);
#endif
}
static int cyttsp5_mt_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
int rc;
if (md->si->xy_mode[2] != md->si->desc.tch_report_id)
return 0;
/* core handles handshake */
mutex_lock(&md->mt_lock);
rc = cyttsp5_xy_worker(md);
mutex_unlock(&md->mt_lock);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static int cyttsp5_mt_wake_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
cyttsp5_mt_send_dummy_event(cd, md);
mutex_unlock(&md->mt_lock);
return 0;
}
static int cyttsp5_startup_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
cyttsp5_mt_lift_all(md);
mutex_unlock(&md->mt_lock);
return 0;
}
static int cyttsp5_mt_suspend_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
cyttsp5_mt_lift_all(md);
md->is_suspended = true;
mutex_unlock(&md->mt_lock);
pm_runtime_put(dev);
return 0;
}
static int cyttsp5_mt_resume_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
pm_runtime_get(dev);
mutex_lock(&md->mt_lock);
md->is_suspended = false;
mutex_unlock(&md->mt_lock);
return 0;
}
static int cyttsp5_mt_open(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
pm_runtime_get_sync(dev);
mutex_lock(&md->mt_lock);
md->is_suspended = false;
mutex_unlock(&md->mt_lock);
dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_MT_NAME,
cyttsp5_mt_attention, CY_MODE_OPERATIONAL);
/* set up startup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_MT_NAME,
cyttsp5_startup_attention, 0);
/* set up wakeup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_WAKE, CYTTSP5_MT_NAME,
cyttsp5_mt_wake_attention, 0);
/* set up suspend call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_MT_NAME,
cyttsp5_mt_suspend_attention, 0);
/* set up resume call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_MT_NAME,
cyttsp5_mt_resume_attention, 0);
return 0;
}
static void cyttsp5_mt_close(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_MT_NAME,
cyttsp5_mt_attention, CY_MODE_OPERATIONAL);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_MT_NAME,
cyttsp5_startup_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_WAKE, CYTTSP5_MT_NAME,
cyttsp5_mt_wake_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_MT_NAME,
cyttsp5_mt_suspend_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_MT_NAME,
cyttsp5_mt_resume_attention, 0);
mutex_lock(&md->mt_lock);
if (!md->is_suspended) {
pm_runtime_put(dev);
md->is_suspended = true;
}
mutex_unlock(&md->mt_lock);
}
static int cyttsp5_setup_input_device(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
int signal = CY_IGNORE_VALUE;
int max_x, max_y, max_p, min, max;
int max_x_tmp, max_y_tmp;
int i;
int rc;
dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
__set_bit(EV_ABS, md->input->evbit);
__set_bit(EV_REL, md->input->evbit);
__set_bit(EV_KEY, md->input->evbit);
#ifdef INPUT_PROP_DIRECT
__set_bit(INPUT_PROP_DIRECT, md->input->propbit);
#endif
/* If virtualkeys enabled, don't use all screen */
if (md->pdata->flags & CY_MT_FLAG_VKEYS) {
max_x_tmp = md->pdata->vkeys_x;
max_y_tmp = md->pdata->vkeys_y;
} else {
max_x_tmp = md->si->sensing_conf_data.res_x;
max_y_tmp = md->si->sensing_conf_data.res_y;
}
/* get maximum values from the sysinfo data */
if (md->pdata->flags & CY_MT_FLAG_FLIP) {
max_x = max_y_tmp - 1;
max_y = max_x_tmp - 1;
} else {
max_x = max_x_tmp - 1;
max_y = max_y_tmp - 1;
}
max_p = md->si->sensing_conf_data.max_z;
/* set event signal capabilities */
for (i = 0; i < NUM_SIGNALS(md->pdata->frmwrk); i++) {
signal = MT_PARAM_SIGNAL(md, i);
if (signal != CY_IGNORE_VALUE) {
__set_bit(signal, md->input->absbit);
min = MT_PARAM_MIN(md, i);
max = MT_PARAM_MAX(md, i);
if (i == CY_ABS_ID_OST) {
/* shift track ids down to start at 0 */
max = max - min;
min = min - min;
} else if (i == CY_ABS_X_OST)
max = max_x;
else if (i == CY_ABS_Y_OST)
max = max_y;
else if (i == CY_ABS_P_OST)
max = max_p;
input_set_abs_params(md->input, signal, min, max,
MT_PARAM_FUZZ(md, i), MT_PARAM_FLAT(md, i));
dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
__func__, signal, min, max);
}
}
md->or_min = MT_PARAM_MIN(md, CY_ABS_OR_OST);
md->or_max = MT_PARAM_MAX(md, CY_ABS_OR_OST);
md->t_min = MT_PARAM_MIN(md, CY_ABS_ID_OST);
md->t_max = MT_PARAM_MAX(md, CY_ABS_ID_OST);
rc = md->mt_function.input_register_device(md->input,
md->si->tch_abs[CY_TCH_T].max);
if (rc < 0)
dev_err(dev, "%s: Error, failed register input device r=%d\n",
__func__, rc);
else
md->input_device_registered = true;
#ifdef EASYWAKE_TSG6
input_set_capability(md->input, EV_KEY, KEY_F1);
input_set_capability(md->input, EV_KEY, KEY_F2);
input_set_capability(md->input, EV_KEY, KEY_F3);
input_set_capability(md->input, EV_KEY, KEY_F4);
input_set_capability(md->input, EV_KEY, KEY_F5);
input_set_capability(md->input, EV_KEY, KEY_F6);
input_set_capability(md->input, EV_KEY, KEY_F7);
input_set_capability(md->input, EV_KEY, KEY_F8);
#endif
return rc;
}
static int cyttsp5_setup_input_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
int rc;
md->si = _cyttsp5_request_sysinfo(dev);
if (!md->si)
return -EINVAL;
rc = cyttsp5_setup_input_device(dev);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_MT_NAME,
cyttsp5_setup_input_attention, 0);
return rc;
}
int cyttsp5_mt_probe(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp5_mt_platform_data *mt_pdata;
int rc = 0;
if (!pdata || !pdata->mt_pdata) {
dev_err(dev, "%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
mt_pdata = pdata->mt_pdata;
cyttsp5_init_function_ptrs(md);
mutex_init(&md->mt_lock);
md->dev = dev;
md->pdata = mt_pdata;
/* Create the input device and register it. */
dev_vdbg(dev, "%s: Create the input device and register it\n",
__func__);
md->input = input_allocate_device();
if (!md->input) {
dev_err(dev, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
}
if (md->pdata->inp_dev_name)
md->input->name = md->pdata->inp_dev_name;
else
md->input->name = CYTTSP5_MT_NAME;
scnprintf(md->phys, sizeof(md->phys), "%s/input%d", dev_name(dev),
cd->phys_num++);
md->input->phys = md->phys;
md->input->dev.parent = md->dev;
md->input->open = cyttsp5_mt_open;
md->input->close = cyttsp5_mt_close;
input_set_drvdata(md->input, md);
/* get sysinfo */
md->si = _cyttsp5_request_sysinfo(dev);
if (md->si) {
rc = cyttsp5_setup_input_device(dev);
if (rc)
goto error_init_input;
} else {
dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, md->si);
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_MT_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
error_init_input:
input_free_device(md->input);
error_alloc_failed:
error_no_pdata:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
int cyttsp5_mt_release(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
if (md->input_device_registered) {
input_unregister_device(md->input);
} else {
input_free_device(md->input);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_MT_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
}

View File

@ -0,0 +1,85 @@
/*
* cyttsp5_mta.c
* Parade TrueTouch(TM) Standard Product V5 Multi-Touch Protocol A Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
static void cyttsp5_final_sync(struct input_dev *input, int max_slots,
int mt_sync_count, unsigned long *ids)
{
if (mt_sync_count)
input_sync(input);
}
static void cyttsp5_input_sync(struct input_dev *input)
{
input_mt_sync(input);
}
static void cyttsp5_input_report(struct input_dev *input, int sig,
int t, int type)
{
if (type == CY_OBJ_STANDARD_FINGER || type == CY_OBJ_GLOVE
|| type == CY_OBJ_HOVER) {
input_report_key(input, BTN_TOOL_FINGER, CY_BTN_PRESSED);
input_report_key(input, BTN_TOOL_PEN, CY_BTN_RELEASED);
} else if (type == CY_OBJ_STYLUS) {
input_report_key(input, BTN_TOOL_PEN, CY_BTN_PRESSED);
input_report_key(input, BTN_TOOL_FINGER, CY_BTN_RELEASED);
}
if (type != CY_OBJ_HOVER)
input_report_key(input, BTN_TOUCH, CY_BTN_PRESSED);
input_report_abs(input, sig, t);
}
static void cyttsp5_report_slot_liftoff(struct cyttsp5_mt_data *md,
int max_slots)
{
input_report_key(md->input, BTN_TOUCH, CY_BTN_RELEASED);
input_report_key(md->input, BTN_TOOL_FINGER, CY_BTN_RELEASED);
input_report_key(md->input, BTN_TOOL_PEN, CY_BTN_RELEASED);
}
static int cyttsp5_input_register_device(struct input_dev *input, int max_slots)
{
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
__set_bit(BTN_TOOL_PEN, input->keybit);
return input_register_device(input);
}
void cyttsp5_init_function_ptrs(struct cyttsp5_mt_data *md)
{
md->mt_function.report_slot_liftoff = cyttsp5_report_slot_liftoff;
md->mt_function.final_sync = cyttsp5_final_sync;
md->mt_function.input_sync = cyttsp5_input_sync;
md->mt_function.input_report = cyttsp5_input_report;
md->mt_function.input_register_device = cyttsp5_input_register_device;
}

View File

@ -0,0 +1,93 @@
/*
* cyttsp5_mtb.c
* Parade TrueTouch(TM) Standard Product V5 Multi-Touch Protocol B Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/input/mt.h>
#include <linux/version.h>
static void cyttsp5_final_sync(struct input_dev *input, int max_slots,
int mt_sync_count, unsigned long *ids)
{
int t;
for (t = 0; t < max_slots; t++) {
if (test_bit(t, ids))
continue;
input_mt_slot(input, t);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
}
input_sync(input);
}
static void cyttsp5_input_report(struct input_dev *input, int sig,
int t, int type)
{
input_mt_slot(input, t);
if (type == CY_OBJ_STANDARD_FINGER || type == CY_OBJ_GLOVE
|| type == CY_OBJ_HOVER)
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
else if (type == CY_OBJ_STYLUS)
input_mt_report_slot_state(input, MT_TOOL_PEN, true);
}
static void cyttsp5_report_slot_liftoff(struct cyttsp5_mt_data *md,
int max_slots)
{
int t;
if (md->num_prv_rec == 0)
return;
for (t = 0; t < max_slots; t++) {
input_mt_slot(md->input, t);
input_mt_report_slot_state(md->input,
MT_TOOL_FINGER, false);
}
}
static int cyttsp5_input_register_device(struct input_dev *input, int max_slots)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
input_mt_init_slots(input, max_slots, 0);
#else
input_mt_init_slots(input, max_slots);
#endif
return input_register_device(input);
}
void cyttsp5_init_function_ptrs(struct cyttsp5_mt_data *md)
{
md->mt_function.report_slot_liftoff = cyttsp5_report_slot_liftoff;
md->mt_function.final_sync = cyttsp5_final_sync;
md->mt_function.input_sync = NULL;
md->mt_function.input_report = cyttsp5_input_report;
md->mt_function.input_register_device = cyttsp5_input_register_device;
}

View File

@ -0,0 +1,288 @@
/*
* cyttsp5_platform.c
* Parade TrueTouch(TM) Standard Product V5 Platform Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/platform_data/cyttsp5.h>
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
/* FW for Panel ID = 0x00 */
#include "cyttsp5_fw_pid00.h"
static struct cyttsp5_touch_firmware cyttsp5_firmware_pid00 = {
.img = cyttsp4_img_pid00,
.size = ARRAY_SIZE(cyttsp4_img_pid00),
.ver = cyttsp4_ver_pid00,
.vsize = ARRAY_SIZE(cyttsp4_ver_pid00),
.panel_id = 0x00,
};
/* FW for Panel ID = 0x01 */
#include "cyttsp5_fw_pid01.h"
static struct cyttsp5_touch_firmware cyttsp5_firmware_pid01 = {
.img = cyttsp4_img_pid01,
.size = ARRAY_SIZE(cyttsp4_img_pid01),
.ver = cyttsp4_ver_pid01,
.vsize = ARRAY_SIZE(cyttsp4_ver_pid01),
.panel_id = 0x01,
};
/* FW for Panel ID not enabled (legacy) */
#include "cyttsp5_fw.h"
static struct cyttsp5_touch_firmware cyttsp5_firmware = {
.img = cyttsp4_img,
.size = ARRAY_SIZE(cyttsp4_img),
.ver = cyttsp4_ver,
.vsize = ARRAY_SIZE(cyttsp4_ver),
};
#else
/* FW for Panel ID not enabled (legacy) */
static struct cyttsp5_touch_firmware cyttsp5_firmware = {
.img = NULL,
.size = 0,
.ver = NULL,
.vsize = 0,
};
#endif
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
/* TT Config for Panel ID = 0x00 */
#include "cyttsp5_params_pid00.h"
static struct touch_settings cyttsp5_sett_param_regs_pid00 = {
.data = (uint8_t *)&cyttsp4_param_regs_pid00[0],
.size = ARRAY_SIZE(cyttsp4_param_regs_pid00),
.tag = 0,
};
static struct touch_settings cyttsp5_sett_param_size_pid00 = {
.data = (uint8_t *)&cyttsp4_param_size_pid00[0],
.size = ARRAY_SIZE(cyttsp4_param_size_pid00),
.tag = 0,
};
static struct cyttsp5_touch_config cyttsp5_ttconfig_pid00 = {
.param_regs = &cyttsp5_sett_param_regs_pid00,
.param_size = &cyttsp5_sett_param_size_pid00,
.fw_ver = ttconfig_fw_ver_pid00,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver_pid00),
.panel_id = 0x00,
};
/* TT Config for Panel ID = 0x01 */
#include "cyttsp5_params_pid01.h"
static struct touch_settings cyttsp5_sett_param_regs_pid01 = {
.data = (uint8_t *)&cyttsp4_param_regs_pid01[0],
.size = ARRAY_SIZE(cyttsp4_param_regs_pid01),
.tag = 0,
};
static struct touch_settings cyttsp5_sett_param_size_pid01 = {
.data = (uint8_t *)&cyttsp4_param_size_pid01[0],
.size = ARRAY_SIZE(cyttsp4_param_size_pid01),
.tag = 0,
};
static struct cyttsp5_touch_config cyttsp5_ttconfig_pid01 = {
.param_regs = &cyttsp5_sett_param_regs_pid01,
.param_size = &cyttsp5_sett_param_size_pid01,
.fw_ver = ttconfig_fw_ver_pid01,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver_pid01),
.panel_id = 0x01,
};
/* TT Config for Panel ID not enabled (legacy)*/
#include "cyttsp5_params.h"
static struct touch_settings cyttsp5_sett_param_regs = {
.data = (uint8_t *)&cyttsp4_param_regs[0],
.size = ARRAY_SIZE(cyttsp4_param_regs),
.tag = 0,
};
static struct touch_settings cyttsp5_sett_param_size = {
.data = (uint8_t *)&cyttsp4_param_size[0],
.size = ARRAY_SIZE(cyttsp4_param_size),
.tag = 0,
};
static struct cyttsp5_touch_config cyttsp5_ttconfig = {
.param_regs = &cyttsp5_sett_param_regs,
.param_size = &cyttsp5_sett_param_size,
.fw_ver = ttconfig_fw_ver,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver),
};
#else
/* TT Config for Panel ID not enabled (legacy)*/
static struct cyttsp5_touch_config cyttsp5_ttconfig = {
.param_regs = NULL,
.param_size = NULL,
.fw_ver = NULL,
.fw_vsize = 0,
};
#endif
static struct cyttsp5_touch_firmware *cyttsp5_firmwares[] = {
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
&cyttsp5_firmware_pid00,
&cyttsp5_firmware_pid01,
#endif
NULL, /* Last item should always be NULL */
};
static struct cyttsp5_touch_config *cyttsp5_ttconfigs[] = {
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
&cyttsp5_ttconfig_pid00,
&cyttsp5_ttconfig_pid01,
#endif
NULL, /* Last item should always be NULL */
};
struct cyttsp5_loader_platform_data _cyttsp5_loader_platform_data = {
.fw = &cyttsp5_firmware,
.ttconfig = &cyttsp5_ttconfig,
.fws = cyttsp5_firmwares,
.ttconfigs = cyttsp5_ttconfigs,
.flags = CY_LOADER_FLAG_NONE,
};
int cyttsp5_xres(struct cyttsp5_core_platform_data *pdata,
struct device *dev)
{
int rst_gpio = pdata->rst_gpio;
int rc = 0;
gpio_set_value(rst_gpio, 1);
msleep(20);
gpio_set_value(rst_gpio, 0);
msleep(40);
gpio_set_value(rst_gpio, 1);
msleep(20);
dev_info(dev,
"%s: RESET CYTTSP gpio=%d r=%d\n", __func__,
pdata->rst_gpio, rc);
return rc;
}
int cyttsp5_init(struct cyttsp5_core_platform_data *pdata,
int on, struct device *dev)
{
int rst_gpio = pdata->rst_gpio;
int irq_gpio = pdata->irq_gpio;
int rc = 0;
if (on) {
rc = gpio_request(rst_gpio, NULL);
if (rc < 0) {
gpio_free(rst_gpio);
rc = gpio_request(rst_gpio, NULL);
}
if (rc < 0) {
dev_err(dev,
"%s: Fail request gpio=%d\n", __func__,
rst_gpio);
} else {
rc = gpio_direction_output(rst_gpio, 1);
if (rc < 0) {
pr_err("%s: Fail set output gpio=%d\n",
__func__, rst_gpio);
gpio_free(rst_gpio);
} else {
rc = gpio_request(irq_gpio, NULL);
if (rc < 0) {
gpio_free(irq_gpio);
rc = gpio_request(irq_gpio,
NULL);
}
if (rc < 0) {
dev_err(dev,
"%s: Fail request gpio=%d\n",
__func__, irq_gpio);
gpio_free(rst_gpio);
} else {
gpio_direction_input(irq_gpio);
}
}
}
} else {
gpio_free(rst_gpio);
gpio_free(irq_gpio);
}
dev_info(dev, "%s: INIT CYTTSP RST gpio=%d and IRQ gpio=%d r=%d\n",
__func__, rst_gpio, irq_gpio, rc);
return rc;
}
static int cyttsp5_wakeup(struct cyttsp5_core_platform_data *pdata,
struct device *dev, atomic_t *ignore_irq)
{
return 0;
}
static int cyttsp5_sleep(struct cyttsp5_core_platform_data *pdata,
struct device *dev, atomic_t *ignore_irq)
{
return 0;
}
int cyttsp5_power(struct cyttsp5_core_platform_data *pdata,
int on, struct device *dev, atomic_t *ignore_irq)
{
if (on)
return cyttsp5_wakeup(pdata, dev, ignore_irq);
return cyttsp5_sleep(pdata, dev, ignore_irq);
}
int cyttsp5_irq_stat(struct cyttsp5_core_platform_data *pdata,
struct device *dev)
{
return gpio_get_value(pdata->irq_gpio);
}
#ifdef CYTTSP5_DETECT_HW
int cyttsp5_detect(struct cyttsp5_core_platform_data *pdata,
struct device *dev, cyttsp5_platform_read read)
{
int retry = 3;
int rc;
char buf[1];
while (retry--) {
/* Perform reset, wait for 100 ms and perform read */
dev_vdbg(dev, "%s: Performing a reset\n", __func__);
pdata->xres(pdata, dev);
msleep(100);
rc = read(dev, buf, 1);
if (!rc)
return 0;
dev_vdbg(dev, "%s: Read unsuccessful, try=%d\n",
__func__, 3 - retry);
}
return rc;
}
#endif

View File

@ -0,0 +1,553 @@
/*
* cyttsp5_proximity.c
* Parade TrueTouch(TM) Standard Product V5 Proximity Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_PROXIMITY_NAME "cyttsp5_proximity"
/* Timeout value in ms. */
#define CYTTSP5_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT 1000
#define CYTTSP5_PROXIMITY_ON 0
#define CYTTSP5_PROXIMITY_OFF 1
static inline struct cyttsp5_proximity_data *get_prox_data(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
return &cd->pd;
}
static void cyttsp5_report_proximity(struct cyttsp5_proximity_data *pd,
bool on)
{
int val = on ? CYTTSP5_PROXIMITY_ON : CYTTSP5_PROXIMITY_OFF;
input_report_abs(pd->input, ABS_DISTANCE, val);
input_sync(pd->input);
}
static void cyttsp5_get_touch_axis(struct cyttsp5_proximity_data *pd,
int *axis, int size, int max, u8 *xy_data, int bofs)
{
int nbyte;
int next;
for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
dev_vdbg(pd->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 + ((xy_data[next] >> bofs) << (nbyte * 8));
next++;
}
*axis &= max - 1;
dev_vdbg(pd->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]);
}
static void cyttsp5_get_touch_hdr(struct cyttsp5_proximity_data *pd,
struct cyttsp5_touch *touch, u8 *xy_mode)
{
struct device *dev = pd->dev;
struct cyttsp5_sysinfo *si = pd->si;
enum cyttsp5_tch_hdr hdr;
for (hdr = CY_TCH_TIME; hdr < CY_TCH_NUM_HDR; hdr++) {
if (!si->tch_hdr[hdr].report)
continue;
cyttsp5_get_touch_axis(pd, &touch->hdr[hdr],
si->tch_hdr[hdr].size,
si->tch_hdr[hdr].max,
xy_mode + si->tch_hdr[hdr].ofs,
si->tch_hdr[hdr].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_hdr_string[hdr],
touch->hdr[hdr], touch->hdr[hdr]);
}
}
static void cyttsp5_get_touch(struct cyttsp5_proximity_data *pd,
struct cyttsp5_touch *touch, u8 *xy_data)
{
struct device *dev = pd->dev;
struct cyttsp5_sysinfo *si = pd->si;
enum cyttsp5_tch_abs abs;
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
if (!si->tch_abs[abs].report)
continue;
cyttsp5_get_touch_axis(pd, &touch->abs[abs],
si->tch_abs[abs].size,
si->tch_abs[abs].max,
xy_data + si->tch_abs[abs].ofs,
si->tch_abs[abs].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_abs_string[abs],
touch->abs[abs], touch->abs[abs]);
}
dev_vdbg(dev, "%s: x=%04X(%d) y=%04X(%d)\n", __func__,
touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
}
static void cyttsp5_get_proximity_touch(struct cyttsp5_proximity_data *pd,
struct cyttsp5_touch *tch, int num_cur_tch)
{
struct cyttsp5_sysinfo *si = pd->si;
int i;
for (i = 0; i < num_cur_tch; i++) {
cyttsp5_get_touch(pd, tch, si->xy_data +
(i * si->desc.tch_record_size));
/* Check for proximity event */
if (tch->abs[CY_TCH_O] == CY_OBJ_PROXIMITY) {
if (tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN)
cyttsp5_report_proximity(pd, true);
else if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF)
cyttsp5_report_proximity(pd, false);
break;
}
}
}
/* read xy_data for all current touches */
static int cyttsp5_xy_worker(struct cyttsp5_proximity_data *pd)
{
struct device *dev = pd->dev;
struct cyttsp5_sysinfo *si = pd->si;
struct cyttsp5_touch tch;
u8 num_cur_tch;
cyttsp5_get_touch_hdr(pd, &tch, si->xy_mode + 3);
num_cur_tch = tch.hdr[CY_TCH_NUM];
if (num_cur_tch > si->sensing_conf_data.max_tch) {
dev_err(dev, "%s: Num touch err detected (n=%d)\n",
__func__, num_cur_tch);
num_cur_tch = si->sensing_conf_data.max_tch;
}
if (tch.hdr[CY_TCH_LO])
dev_dbg(dev, "%s: Large area detected\n", __func__);
/* extract xy_data for all currently reported touches */
dev_vdbg(dev, "%s: extract data num_cur_rec=%d\n", __func__,
num_cur_tch);
if (num_cur_tch)
cyttsp5_get_proximity_touch(pd, &tch, num_cur_tch);
else
cyttsp5_report_proximity(pd, false);
return 0;
}
static int cyttsp5_proximity_attention(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int rc = 0;
if (pd->si->xy_mode[2] != pd->si->desc.tch_report_id)
return 0;
mutex_lock(&pd->prox_lock);
rc = cyttsp5_xy_worker(pd);
mutex_unlock(&pd->prox_lock);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static int cyttsp5_startup_attention(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
mutex_lock(&pd->prox_lock);
cyttsp5_report_proximity(pd, false);
mutex_unlock(&pd->prox_lock);
return 0;
}
static int _cyttsp5_set_proximity_via_touchmode_enabled(
struct cyttsp5_proximity_data *pd, bool enable)
{
struct device *dev = pd->dev;
u32 touchmode_enabled;
int rc;
rc = cyttsp5_request_nonhid_get_param(dev, 0,
CY_RAM_ID_TOUCHMODE_ENABLED, &touchmode_enabled);
if (rc)
return rc;
if (enable)
touchmode_enabled |= 0x80;
else
touchmode_enabled &= 0x7F;
rc = cyttsp5_request_nonhid_set_param(dev, 0,
CY_RAM_ID_TOUCHMODE_ENABLED, touchmode_enabled,
CY_RAM_ID_TOUCHMODE_ENABLED_SIZE);
return rc;
}
static int _cyttsp5_set_proximity_via_proximity_enable(
struct cyttsp5_proximity_data *pd, bool enable)
{
struct device *dev = pd->dev;
u32 proximity_enable;
int rc;
rc = cyttsp5_request_nonhid_get_param(dev, 0,
CY_RAM_ID_PROXIMITY_ENABLE, &proximity_enable);
if (rc)
return rc;
if (enable)
proximity_enable |= 0x01;
else
proximity_enable &= 0xFE;
rc = cyttsp5_request_nonhid_set_param(dev, 0,
CY_RAM_ID_PROXIMITY_ENABLE, proximity_enable,
CY_RAM_ID_PROXIMITY_ENABLE_SIZE);
return rc;
}
static int _cyttsp5_set_proximity(struct cyttsp5_proximity_data *pd,
bool enable)
{
if (!IS_PIP_VER_GE(pd->si, 1, 4))
return _cyttsp5_set_proximity_via_touchmode_enabled(pd,
enable);
return _cyttsp5_set_proximity_via_proximity_enable(pd, enable);
}
static int _cyttsp5_proximity_enable(struct cyttsp5_proximity_data *pd)
{
struct device *dev = pd->dev;
int rc = 0;
pm_runtime_get_sync(dev);
rc = cyttsp5_request_exclusive(dev,
CYTTSP5_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
if (rc < 0) {
dev_err(dev, "%s: Error on request exclusive r=%d\n",
__func__, rc);
goto exit;
}
rc = _cyttsp5_set_proximity(pd, true);
if (rc < 0) {
dev_err(dev, "%s: Error on request enable proximity scantype r=%d\n",
__func__, rc);
goto exit_release;
}
dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_PROXIMITY_NAME,
cyttsp5_proximity_attention, CY_MODE_OPERATIONAL);
/* set up startup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_startup_attention, 0);
exit_release:
cyttsp5_release_exclusive(dev);
exit:
return rc;
}
static int _cyttsp5_proximity_disable(struct cyttsp5_proximity_data *pd,
bool force)
{
struct device *dev = pd->dev;
int rc = 0;
rc = cyttsp5_request_exclusive(dev,
CYTTSP5_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
if (rc < 0) {
dev_err(dev, "%s: Error on request exclusive r=%d\n",
__func__, rc);
goto exit;
}
rc = _cyttsp5_set_proximity(pd, false);
if (rc < 0) {
dev_err(dev, "%s: Error on request disable proximity scan r=%d\n",
__func__, rc);
goto exit_release;
}
exit_release:
cyttsp5_release_exclusive(dev);
exit:
if (!rc || force) {
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ,
CYTTSP5_PROXIMITY_NAME, cyttsp5_proximity_attention,
CY_MODE_OPERATIONAL);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_startup_attention, 0);
}
pm_runtime_put(dev);
return rc;
}
static ssize_t cyttsp5_proximity_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int val = 0;
mutex_lock(&pd->sysfs_lock);
val = pd->enable_count;
mutex_unlock(&pd->sysfs_lock);
return scnprintf(buf, CY_MAX_PRBUF_SIZE, "%d\n", val);
}
static ssize_t cyttsp5_proximity_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
unsigned long value;
int rc;
rc = kstrtoul(buf, 10, &value);
if (rc < 0 || (value != 0 && value != 1)) {
dev_err(dev, "%s: Invalid value\n", __func__);
return -EINVAL;
}
mutex_lock(&pd->sysfs_lock);
if (value) {
if (pd->enable_count++) {
dev_vdbg(dev, "%s: '%s' already enabled\n", __func__,
pd->input->name);
} else {
rc = _cyttsp5_proximity_enable(pd);
if (rc)
pd->enable_count--;
}
} else {
if (--pd->enable_count) {
if (pd->enable_count < 0) {
dev_err(dev, "%s: '%s' unbalanced disable\n",
__func__, pd->input->name);
pd->enable_count = 0;
}
} else {
rc = _cyttsp5_proximity_disable(pd, false);
if (rc)
pd->enable_count++;
}
}
mutex_unlock(&pd->sysfs_lock);
if (rc)
return rc;
return size;
}
static DEVICE_ATTR(prox_enable, S_IRUSR | S_IWUSR,
cyttsp5_proximity_enable_show,
cyttsp5_proximity_enable_store);
static int cyttsp5_setup_input_device_and_sysfs(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int signal = CY_IGNORE_VALUE;
int i;
int rc;
rc = device_create_file(dev, &dev_attr_prox_enable);
if (rc) {
dev_err(dev, "%s: Error, could not create enable\n",
__func__);
goto exit;
}
dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
__set_bit(EV_ABS, pd->input->evbit);
/* set event signal capabilities */
for (i = 0; i < NUM_SIGNALS(pd->pdata->frmwrk); i++) {
signal = PARAM_SIGNAL(pd->pdata->frmwrk, i);
if (signal != CY_IGNORE_VALUE) {
input_set_abs_params(pd->input, signal,
PARAM_MIN(pd->pdata->frmwrk, i),
PARAM_MAX(pd->pdata->frmwrk, i),
PARAM_FUZZ(pd->pdata->frmwrk, i),
PARAM_FLAT(pd->pdata->frmwrk, i));
}
}
rc = input_register_device(pd->input);
if (rc) {
dev_err(dev, "%s: Error, failed register input device r=%d\n",
__func__, rc);
goto unregister_enable;
}
pd->input_device_registered = true;
return rc;
unregister_enable:
device_remove_file(dev, &dev_attr_prox_enable);
exit:
return rc;
}
static int cyttsp5_setup_input_attention(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int rc;
pd->si = _cyttsp5_request_sysinfo(dev);
if (!pd->si)
return -EINVAL;
rc = cyttsp5_setup_input_device_and_sysfs(dev);
if (!rc)
rc = _cyttsp5_set_proximity(pd, false);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_setup_input_attention, 0);
return rc;
}
int cyttsp5_proximity_probe(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_proximity_data *pd = &cd->pd;
struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp5_proximity_platform_data *prox_pdata;
int rc = 0;
if (!pdata || !pdata->prox_pdata) {
dev_err(dev, "%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
prox_pdata = pdata->prox_pdata;
mutex_init(&pd->prox_lock);
mutex_init(&pd->sysfs_lock);
pd->dev = dev;
pd->pdata = prox_pdata;
/* Create the input device and register it. */
dev_vdbg(dev, "%s: Create the input device and register it\n",
__func__);
pd->input = input_allocate_device();
if (!pd->input) {
dev_err(dev, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
}
if (pd->pdata->inp_dev_name)
pd->input->name = pd->pdata->inp_dev_name;
else
pd->input->name = CYTTSP5_PROXIMITY_NAME;
scnprintf(pd->phys, sizeof(pd->phys), "%s/input%d", dev_name(dev),
cd->phys_num++);
pd->input->phys = pd->phys;
pd->input->dev.parent = pd->dev;
input_set_drvdata(pd->input, pd);
/* get sysinfo */
pd->si = _cyttsp5_request_sysinfo(dev);
if (pd->si) {
rc = cyttsp5_setup_input_device_and_sysfs(dev);
if (rc)
goto error_init_input;
rc = _cyttsp5_set_proximity(pd, false);
} else {
dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, pd->si);
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_setup_input_attention,
0);
}
return 0;
error_init_input:
input_free_device(pd->input);
error_alloc_failed:
error_no_pdata:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
int cyttsp5_proximity_release(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
if (pd->input_device_registered) {
/* Disable proximity sensing */
mutex_lock(&pd->sysfs_lock);
if (pd->enable_count)
_cyttsp5_proximity_disable(pd, true);
mutex_unlock(&pd->sysfs_lock);
device_remove_file(dev, &dev_attr_prox_enable);
input_unregister_device(pd->input);
} else {
input_free_device(pd->input);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_setup_input_attention,
0);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,254 @@
/*
* cyttsp5_spi.c
* Parade TrueTouch(TM) Standard Product V5 SPI Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/spi/spi.h>
#include <linux/version.h>
#define CY_SPI_WR_OP 0x00 /* r/~w */
#define CY_SPI_RD_OP 0x01
#define CY_SPI_BITS_PER_WORD 8
#define CY_SPI_SYNC_ACK 0x62
#define CY_SPI_CMD_BYTES 0
#define CY_SPI_DATA_SIZE (2 * 256)
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
static void cyttsp5_spi_add_rw_msg(struct spi_message *msg,
struct spi_transfer *xfer, u8 *w_header, u8 *r_header, u8 op)
{
xfer->tx_buf = w_header;
xfer->rx_buf = r_header;
w_header[0] = op;
xfer->len = 1;
spi_message_add_tail(xfer, msg);
}
static int cyttsp5_spi_xfer(struct device *dev, u8 op, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
u8 w_header[2];
u8 r_header[2];
int rc;
memset(xfer, 0, sizeof(xfer));
spi_message_init(&msg);
cyttsp5_spi_add_rw_msg(&msg, &xfer[0], w_header, r_header, op);
switch (op) {
case CY_SPI_RD_OP:
xfer[1].rx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
case CY_SPI_WR_OP:
xfer[1].tx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
default:
rc = -EIO;
goto exit;
}
rc = spi_sync(spi, &msg);
exit:
if (rc < 0)
dev_vdbg(dev, "%s: spi_sync() error %d\n", __func__, rc);
if (r_header[0] != CY_SPI_SYNC_ACK)
return -EIO;
return rc;
}
static int cyttsp5_spi_read_default(struct device *dev, void *buf, int size)
{
if (!buf || !size)
return 0;
return cyttsp5_spi_xfer(dev, CY_SPI_RD_OP, buf, size);
}
static int cyttsp5_spi_read_default_nosize(struct device *dev, u8 *buf, u32 max)
{
u32 size;
int rc;
if (!buf)
return 0;
rc = cyttsp5_spi_xfer(dev, CY_SPI_RD_OP, buf, 2);
if (rc < 0)
return rc;
size = get_unaligned_le16(&buf[0]);
if (!size)
return rc;
if (size > max)
return -EINVAL;
return cyttsp5_spi_read_default(dev, buf, size);
}
static int cyttsp5_spi_write_read_specific(struct device *dev, u8 write_len,
u8 *write_buf, u8 *read_buf)
{
int rc;
rc = cyttsp5_spi_xfer(dev, CY_SPI_WR_OP, write_buf, write_len);
if (rc < 0)
return rc;
if (read_buf)
rc = cyttsp5_spi_read_default_nosize(dev, read_buf,
CY_SPI_DATA_SIZE);
return rc;
}
static struct cyttsp5_bus_ops cyttsp5_spi_bus_ops = {
.bustype = BUS_SPI,
.read_default = cyttsp5_spi_read_default,
.read_default_nosize = cyttsp5_spi_read_default_nosize,
.write_read_specific = cyttsp5_spi_write_read_specific,
};
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
static const struct of_device_id cyttsp5_spi_of_match[] = {
{ .compatible = "cy,cyttsp5_spi_adapter", },
{ }
};
MODULE_DEVICE_TABLE(of, cyttsp5_spi_of_match);
#endif
static int cyttsp5_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
int rc;
/* Set up SPI*/
spi->bits_per_word = CY_SPI_BITS_PER_WORD;
spi->mode = SPI_MODE_0;
rc = spi_setup(spi);
if (rc < 0) {
dev_err(dev, "%s: SPI setup error %d\n", __func__, rc);
return rc;
}
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_spi_of_match), dev);
if (match) {
rc = cyttsp5_devtree_create_and_get_pdata(dev);
if (rc < 0)
return rc;
}
#endif
rc = cyttsp5_probe(&cyttsp5_spi_bus_ops, &spi->dev, spi->irq,
CY_SPI_DATA_BUF_SIZE);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
if (rc && match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return rc;
}
static int cyttsp5_spi_remove(struct spi_device *spi)
{
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
struct device *dev = &spi->dev;
const struct of_device_id *match;
#endif
struct cyttsp5_core_data *cd = dev_get_drvdata(&spi->dev);
cyttsp5_release(cd);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_spi_of_match), dev);
if (match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return 0;
}
static const struct spi_device_id cyttsp5_spi_id[] = {
{ CYTTSP5_SPI_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, cyttsp5_spi_id);
static struct spi_driver cyttsp5_spi_driver = {
.driver = {
.name = CYTTSP5_SPI_NAME,
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &cyttsp5_pm_ops,
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
.of_match_table = cyttsp5_spi_of_match,
#endif
},
.probe = cyttsp5_spi_probe,
.remove = (cyttsp5_spi_remove),
.id_table = cyttsp5_spi_id,
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
module_spi_driver(cyttsp5_spi_driver);
#else
static int __init cyttsp5_spi_init(void)
{
int err = spi_register_driver(&cyttsp5_spi_driver);
pr_info("%s: Parade TTSP SPI Driver (Built %s) rc=%d\n",
__func__, CY_DRIVER_VERSION, err);
return err;
}
module_init(cyttsp5_spi_init);
static void __exit cyttsp5_spi_exit(void)
{
spi_unregister_driver(&cyttsp5_spi_driver);
}
module_exit(cyttsp5_spi_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product SPI Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View File

@ -0,0 +1,442 @@
/*
* cyttsp5_test_device_access_api.c
* Parade TrueTouch(TM) Standard Product V5 Device Access API test module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include <linux/module.h>
#include <linux/uapi/cyttsp5.h>
#include <asm/unaligned.h>
#define BUFFER_SIZE 256
#define COMMAND_GET_SYSTEM_INFO 2
#define COMMAND_SUSPEND_SCANNING 3
#define COMMAND_RESUME_SCANNING 4
#define COMMAND_GET_PARAMETER 5
#define COMMAND_SET_PARAMETER 6
#define PARAMETER_ACTIVE_DISTANCE_2 0x0B
struct tt_output_report {
__le16 reg_address;
__le16 length;
u8 report_id;
u8 reserved;
u8 command;
u8 parameters[0];
} __packed;
struct tt_input_report {
__le16 length;
u8 report_id;
u8 reserved;
u8 command;
u8 return_data[0];
} __packed;
static int prepare_tt_output_report(struct tt_output_report *out,
u16 length, u8 command)
{
put_unaligned_le16(0x04, &out->reg_address);
put_unaligned_le16(5 + length, &out->length);
out->report_id = 0x2f;
out->reserved = 0x00;
out->command = command;
return 7 + length;
}
static int check_and_parse_tt_input_report(struct tt_input_report *in,
u16 *length, u8 *command)
{
if (in->report_id != 0x1f)
return -EINVAL;
*length = get_unaligned_le16(&in->length);
*command = in->command & 0x7f;
return 0;
}
static int prepare_get_system_info_report(u8 *buf)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
return prepare_tt_output_report(out, 0, COMMAND_GET_SYSTEM_INFO);
}
static int check_get_system_info_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
if (read_length != 51)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_GET_SYSTEM_INFO
|| length != 51)
return -EINVAL;
pr_info("PIP Major Version: %d\n", in->return_data[0]);
pr_info("PIP Minor Version: %d\n", in->return_data[1]);
pr_info("Touch Firmware Product Id: %d\n",
get_unaligned_le16(&in->return_data[2]));
pr_info("Touch Firmware Major Version: %d\n", in->return_data[4]);
pr_info("Touch Firmware Minor Version: %d\n", in->return_data[5]);
pr_info("Touch Firmware Internal Revision Control Number: %d\n",
get_unaligned_le32(&in->return_data[6]));
pr_info("Customer Specified Firmware/Configuration Version: %d\n",
get_unaligned_le16(&in->return_data[10]));
pr_info("Bootloader Major Version: %d\n", in->return_data[12]);
pr_info("Bootloader Minor Version: %d\n", in->return_data[13]);
pr_info("Family ID: 0x%02x\n", in->return_data[14]);
pr_info("Revision ID: 0x%02x\n", in->return_data[15]);
pr_info("Silicon ID: 0x%02x\n",
get_unaligned_le16(&in->return_data[16]));
pr_info("Parade Manufacturing ID[0]: 0x%02x\n", in->return_data[18]);
pr_info("Parade Manufacturing ID[1]: 0x%02x\n", in->return_data[19]);
pr_info("Parade Manufacturing ID[2]: 0x%02x\n", in->return_data[20]);
pr_info("Parade Manufacturing ID[3]: 0x%02x\n", in->return_data[21]);
pr_info("Parade Manufacturing ID[4]: 0x%02x\n", in->return_data[22]);
pr_info("Parade Manufacturing ID[5]: 0x%02x\n", in->return_data[23]);
pr_info("Parade Manufacturing ID[6]: 0x%02x\n", in->return_data[24]);
pr_info("Parade Manufacturing ID[7]: 0x%02x\n", in->return_data[25]);
pr_info("POST Result Code: 0x%02x\n",
get_unaligned_le16(&in->return_data[26]));
pr_info("Number of X Electrodes: %d\n", in->return_data[28]);
pr_info("Number of Y Electrodes: %d\n", in->return_data[29]);
pr_info("Panel X Axis Length: %d\n",
get_unaligned_le16(&in->return_data[30]));
pr_info("Panel Y Axis Length: %d\n",
get_unaligned_le16(&in->return_data[32]));
pr_info("Panel X Axis Resolution: %d\n",
get_unaligned_le16(&in->return_data[34]));
pr_info("Panel Y Axis Resolution: %d\n",
get_unaligned_le16(&in->return_data[36]));
pr_info("Panel Pressure Resolution: %d\n",
get_unaligned_le16(&in->return_data[38]));
pr_info("X_ORG: %d\n", in->return_data[40]);
pr_info("Y_ORG: %d\n", in->return_data[41]);
pr_info("Panel ID: %d\n", in->return_data[42]);
pr_info("Buttons: 0x%02x\n", in->return_data[43]);
pr_info("BAL SELF MC: 0x%02x\n", in->return_data[44]);
pr_info("Max Number of Touch Records per Refresh Cycle: %d\n",
in->return_data[45]);
return 0;
}
static int prepare_get_parameter_report(u8 *buf, u8 parameter_id)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
out->parameters[0] = parameter_id;
return prepare_tt_output_report(out, 1, COMMAND_GET_PARAMETER);
}
static int check_get_parameter_response(u8 *buf, u16 read_length,
u32 *parameter_value)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
u32 param_value = 0;
u8 param_id;
u8 param_size = 0;
if (read_length != 8 && read_length != 9 && read_length != 11)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_GET_PARAMETER
|| (length != 8 && length != 9 && length != 11))
return -EINVAL;
param_id = in->return_data[0];
param_size = in->return_data[1];
if (param_size == 1)
param_value = in->return_data[2];
else if (param_size == 2)
param_value = get_unaligned_le16(&in->return_data[2]);
else if (param_size == 4)
param_value = get_unaligned_le32(&in->return_data[2]);
else
return -EINVAL;
pr_info("%s: Parameter ID: 0x%02x Value: 0x%02x\n",
__func__, param_id, param_value);
if (parameter_value)
*parameter_value = param_value;
return 0;
}
static int prepare_set_parameter_report(u8 *buf, u8 parameter_id,
u8 parameter_size, u32 parameter_value)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
out->parameters[0] = parameter_id;
out->parameters[1] = parameter_size;
if (parameter_size == 1)
out->parameters[2] = (u8)parameter_value;
else if (parameter_size == 2)
put_unaligned_le16(parameter_value, &out->parameters[2]);
else if (parameter_size == 4)
put_unaligned_le32(parameter_value, &out->parameters[2]);
else
return -EINVAL;
return prepare_tt_output_report(out, 2 + parameter_size,
COMMAND_SET_PARAMETER);
}
static int check_set_parameter_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
u8 param_id;
u8 param_size = 0;
if (read_length != 7)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_SET_PARAMETER
|| length != 7)
return -EINVAL;
param_id = in->return_data[0];
param_size = in->return_data[1];
pr_info("%s: Parameter ID: 0x%02x Size: 0x%02x\n",
__func__, param_id, param_size);
return 0;
}
static int prepare_suspend_scanning_report(u8 *buf)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
return prepare_tt_output_report(out, 0, COMMAND_SUSPEND_SCANNING);
}
static int check_suspend_scanning_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
if (read_length != 5)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_SUSPEND_SCANNING
|| length != 5)
return -EINVAL;
return 0;
}
static int prepare_resume_scanning_report(u8 *buf)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
return prepare_tt_output_report(out, 0, COMMAND_RESUME_SCANNING);
}
static int check_resume_scanning_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
if (read_length != 5)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_RESUME_SCANNING
|| length != 5)
return -EINVAL;
return 0;
}
void cyttsp5_user_command_async_cont(const char *core_name,
u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
u16 actual_read_length, int rc)
{
if (rc) {
pr_err("%s: suspend scan fails\n", __func__);
goto exit;
}
rc = check_suspend_scanning_response(read_buf, actual_read_length);
if (rc) {
pr_err("%s: check suspend scanning response fails\n", __func__);
goto exit;
}
pr_info("%s: suspend scanning succeeds\n", __func__);
exit:
return;
}
/* Read and write buffers */
static u8 write_buf[BUFFER_SIZE];
static u8 read_buf[BUFFER_SIZE];
static uint active_distance;
module_param(active_distance, uint, 0);
static int __init cyttsp5_test_device_access_api_init(void)
{
u32 initial_active_distance;
u16 actual_read_len;
int write_len;
int rc;
pr_info("%s: Enter\n", __func__);
/* CASE 1: Run get system information */
write_len = prepare_get_system_info_report(write_buf);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_get_system_info_response(read_buf, actual_read_len);
if (rc)
goto exit;
/* CASE 2: Run get parameter (Active distance) */
write_len = prepare_get_parameter_report(write_buf,
PARAMETER_ACTIVE_DISTANCE_2);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_get_parameter_response(read_buf, actual_read_len,
&initial_active_distance);
if (rc)
goto exit;
pr_info("%s: Initial Active Distance: %d\n",
__func__, initial_active_distance);
/* CASE 3: Run set parameter (Active distance) */
write_len = prepare_set_parameter_report(write_buf,
PARAMETER_ACTIVE_DISTANCE_2, 1,
active_distance);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_set_parameter_response(read_buf, actual_read_len);
if (rc)
goto exit;
pr_info("%s: Active Distance set to %d\n", __func__, active_distance);
/* CASE 4: Run get parameter (Active distance) */
write_len = prepare_get_parameter_report(write_buf,
PARAMETER_ACTIVE_DISTANCE_2);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_get_parameter_response(read_buf, actual_read_len,
&active_distance);
if (rc)
goto exit;
pr_info("%s: New Active Distance: %d\n", __func__, active_distance);
/* CASE 5: Run suspend scanning asynchronously */
write_len = prepare_suspend_scanning_report(write_buf);
preempt_disable();
rc = cyttsp5_device_access_user_command_async(NULL,
sizeof(read_buf), read_buf, write_len, write_buf,
cyttsp5_user_command_async_cont);
preempt_enable();
if (rc)
goto exit;
exit:
return rc;
}
module_init(cyttsp5_test_device_access_api_init);
static void __exit cyttsp5_test_device_access_api_exit(void)
{
u16 actual_read_len;
int write_len;
int rc;
/* CASE 6: Run resume scanning */
write_len = prepare_resume_scanning_report(write_buf);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_resume_scanning_response(read_buf, actual_read_len);
if (rc)
goto exit;
pr_info("%s: resume scanning succeeds\n", __func__);
exit:
return;
}
module_exit(cyttsp5_test_device_access_api_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Device Access Driver API Tester");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View File

@ -0,0 +1,60 @@
/*
* cyttsp5_platform.h
* Parade TrueTouch(TM) Standard Product V5 Platform Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#ifndef _LINUX_CYTTSP5_PLATFORM_H
#define _LINUX_CYTTSP5_PLATFORM_H
#include <linux/platform_data/cyttsp5.h>
#if defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5) \
|| defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MODULE)
extern struct cyttsp5_loader_platform_data _cyttsp5_loader_platform_data;
int cyttsp5_xres(struct cyttsp5_core_platform_data *pdata, struct device *dev);
int cyttsp5_init(struct cyttsp5_core_platform_data *pdata, int on,
struct device *dev);
int cyttsp5_power(struct cyttsp5_core_platform_data *pdata, int on,
struct device *dev, atomic_t *ignore_irq);
#ifdef CYTTSP5_DETECT_HW
int cyttsp5_detect(struct cyttsp5_core_platform_data *pdata,
struct device *dev, cyttsp5_platform_read read);
#else
#define cyttsp5_detect NULL
#endif
int cyttsp5_irq_stat(struct cyttsp5_core_platform_data *pdata,
struct device *dev);
#else /* !CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5 */
static struct cyttsp5_loader_platform_data _cyttsp5_loader_platform_data;
#define cyttsp5_xres NULL
#define cyttsp5_init NULL
#define cyttsp5_power NULL
#define cyttsp5_irq_stat NULL
#define cyttsp5_detect NULL
#endif /* CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5 */
#endif /* _LINUX_CYTTSP5_PLATFORM_H */

View File

@ -0,0 +1,180 @@
/*
* cyttsp5_core.h
* Parade TrueTouch(TM) Standard Product V5 Core Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#ifndef _LINUX_CYTTSP5_CORE_H
#define _LINUX_CYTTSP5_CORE_H
#include <linux/stringify.h>
#define CYTTSP5_I2C_NAME "cyttsp5_i2c_adapter"
#define CYTTSP5_SPI_NAME "cyttsp5_spi_adapter"
#define CYTTSP5_CORE_NAME "cyttsp5_core"
#define CYTTSP5_MT_NAME "cyttsp5_mt"
#define CYTTSP5_BTN_NAME "cyttsp5_btn"
#define CYTTSP5_PROXIMITY_NAME "cyttsp5_proximity"
#define CY_DRIVER_NAME TTDA
#define CY_DRIVER_MAJOR 03
#define CY_DRIVER_MINOR 07
#define CY_DRIVER_REVCTRL 844339
#define CY_DRIVER_VERSION \
__stringify(CY_DRIVER_NAME) \
"." __stringify(CY_DRIVER_MAJOR) \
"." __stringify(CY_DRIVER_MINOR) \
"." __stringify(CY_DRIVER_REVCTRL)
#define CY_DRIVER_DATE "20150715" /* YYYYMMDD */
/* abs settings */
#define CY_IGNORE_VALUE -1
enum cyttsp5_core_platform_flags {
CY_CORE_FLAG_NONE,
CY_CORE_FLAG_POWEROFF_ON_SLEEP = 0x02,
CY_CORE_FLAG_RESTORE_PARAMETERS = 0x04,
};
enum cyttsp5_core_platform_easy_wakeup_gesture {
CY_CORE_EWG_NONE,
CY_CORE_EWG_TAP_TAP,
CY_CORE_EWG_TWO_FINGER_SLIDE,
CY_CORE_EWG_RESERVED,
CY_CORE_EWG_WAKE_ON_INT_FROM_HOST = 0xFF,
};
enum cyttsp5_loader_platform_flags {
CY_LOADER_FLAG_NONE,
CY_LOADER_FLAG_CALIBRATE_AFTER_FW_UPGRADE,
/* Use CONFIG_VER field in TT_CFG to decide TT_CFG update */
CY_LOADER_FLAG_CHECK_TTCONFIG_VERSION,
CY_LOADER_FLAG_CALIBRATE_AFTER_TTCONFIG_UPGRADE,
};
struct touch_settings {
const uint8_t *data;
uint32_t size;
uint8_t tag;
};
struct cyttsp5_touch_firmware {
const uint8_t *img;
uint32_t size;
const uint8_t *ver;
uint8_t vsize;
uint8_t panel_id;
};
struct cyttsp5_touch_config {
struct touch_settings *param_regs;
struct touch_settings *param_size;
const uint8_t *fw_ver;
uint8_t fw_vsize;
uint8_t panel_id;
};
struct cyttsp5_loader_platform_data {
struct cyttsp5_touch_firmware *fw;
struct cyttsp5_touch_config *ttconfig;
struct cyttsp5_touch_firmware **fws;
struct cyttsp5_touch_config **ttconfigs;
u32 flags;
};
typedef int (*cyttsp5_platform_read) (struct device *dev, void *buf, int size);
#define CY_TOUCH_SETTINGS_MAX 32
struct cyttsp5_core_platform_data {
int irq_gpio;
int rst_gpio;
int level_irq_udelay;
u16 hid_desc_register;
u16 vendor_id;
u16 product_id;
int (*xres)(struct cyttsp5_core_platform_data *pdata,
struct device *dev);
int (*init)(struct cyttsp5_core_platform_data *pdata,
int on, struct device *dev);
int (*power)(struct cyttsp5_core_platform_data *pdata,
int on, struct device *dev, atomic_t *ignore_irq);
int (*detect)(struct cyttsp5_core_platform_data *pdata,
struct device *dev, cyttsp5_platform_read read);
int (*irq_stat)(struct cyttsp5_core_platform_data *pdata,
struct device *dev);
struct touch_settings *sett[CY_TOUCH_SETTINGS_MAX];
u32 flags;
u8 easy_wakeup_gesture;
bool fb_blanking_disabled;
};
struct touch_framework {
const int16_t *abs;
uint8_t size;
uint8_t enable_vkeys;
} __packed;
enum cyttsp5_mt_platform_flags {
CY_MT_FLAG_NONE,
CY_MT_FLAG_HOVER = 0x04,
CY_MT_FLAG_FLIP = 0x08,
CY_MT_FLAG_INV_X = 0x10,
CY_MT_FLAG_INV_Y = 0x20,
CY_MT_FLAG_VKEYS = 0x40,
CY_MT_FLAG_NO_TOUCH_ON_LO = 0x80,
};
struct cyttsp5_mt_platform_data {
struct touch_framework *frmwrk;
unsigned short flags;
char const *inp_dev_name;
int vkeys_x;
int vkeys_y;
};
struct cyttsp5_btn_platform_data {
char const *inp_dev_name;
};
struct cyttsp5_proximity_platform_data {
struct touch_framework *frmwrk;
char const *inp_dev_name;
};
struct cyttsp5_platform_data {
struct cyttsp5_core_platform_data *core_pdata;
struct cyttsp5_mt_platform_data *mt_pdata;
struct cyttsp5_btn_platform_data *btn_pdata;
struct cyttsp5_proximity_platform_data *prox_pdata;
struct cyttsp5_loader_platform_data *loader_pdata;
};
#endif /* _LINUX_CYTTSP5_CORE_H */

View File

@ -0,0 +1,44 @@
/*
* cyttsp5_device_access-api.h
* Parade TrueTouch(TM) Standard Product V5 Device Access API module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 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 Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#ifndef _LINUX_CYTTSP5_DEVICE_ACCESS_API_H
#define _LINUX_CYTTSP5_DEVICE_ACCESS_API_H
#include <linux/types.h>
#include <linux/device.h>
int cyttsp5_device_access_user_command(const char *core_name, u16 read_len,
u8 *read_buf, u16 write_len, u8 *write_buf,
u16 *actual_read_len);
int cyttsp5_device_access_user_command_async(const char *core_name,
u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
void (*cont)(const char *core_name, u16 read_len, u8 *read_buf,
u16 write_len, u8 *write_buf, u16 actual_read_length,
int rc));
#endif /* _LINUX_CYTTSP5_DEVICE_ACCESS_API_H */