input/touchscreen: Initial support for cyttsp5
Signed-off-by: Alistair Francis <alistair@alistair23.me>rM2-mainline-working-wifi
parent
3045ba7b4d
commit
109ec03f21
|
@ -288,6 +288,207 @@ config TOUCHSCREEN_CYTTSP4_SPI
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called cyttsp4_spi.
|
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_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
|
config TOUCHSCREEN_DA9034
|
||||||
tristate "Touchscreen support for Dialog Semiconductor DA9034"
|
tristate "Touchscreen support for Dialog Semiconductor DA9034"
|
||||||
depends on PMIC_DA903X
|
depends on PMIC_DA903X
|
||||||
|
|
|
@ -112,3 +112,19 @@ obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
|
obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
|
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o
|
obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.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
|
||||||
|
|
|
@ -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
|
@ -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
|
@ -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>");
|
|
@ -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
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
@ -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>");
|
|
@ -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>");
|
|
@ -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 */
|
|
@ -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 */
|
Loading…
Reference in New Issue