1
0
Fork 0

touch: imported pt (Parade TrueTouch Gen5 Touchscreen Driver)

zero-sugar
Michal Koziel 2021-04-09 09:56:06 +02:00 committed by mkemlogic
parent 521acadc4d
commit 2ac5ccb2db
19 changed files with 37839 additions and 1 deletions

View File

@ -0,0 +1,135 @@
pt_i2c_adaptor bindings
Required properties:
- compatible: "parade,pt_i2c_adaptor"
- reg: i2c address of the chip
- interrupt-parent: a phandle for the interrupt controller
- interrupts: Interrupt GPIO
- parade,adapter_id: adaptor name
- core,name: name of core
- core,irq_gpio: IRQ GPIO
- core,hid_desc_register: Default HID register
- core,flags: Special flags
- core,mt,name: name of multi-touch module
- core,mt,inp_dev_name: input device name
- core,mt,flags: MT flags
- core,mt,abs: ABS_MT_* event names
Optional properties:
- core,rst_gpio: Reset GPIO
- core,easy_wakeup_gesture: Default wakeup gesture
- core,panel_id_support: panel ID support
- core,btn_keys: Virtual button key codes
- core,btn_keys-tag: Button Tag
- core,mt,vkeys-x: X coordinate for virtual button area
- core,mt,vkeys-y: Y coordinate for virtual button area
- core,mt,virtual_keys: Keycode CenterX CenterY Width Height
[1]: Documentation/devicetree/bindings/input/parade-touchscreen.txt
Example:
i2c@0 {
status = "ok";
tsc@24 {
compatible = "parade,pt_i2c_adapter";
reg = <0x24>;
interrupt-parent = <&msmgpio>;
interrupts = <59 0x2>;
parade,adapter_id = "pt_i2c_adapter";
pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release";
pinctrl-0 = <&ts_int_active>, <&ts_reset_active>;
pinctrl-1 = <&ts_int_suspend>, <&ts_reset_suspend>;
pinctrl-2 = <&ts_release>;
parade,core {
parade,name = "pt_core";
parade,irq_gpio = <59>;
parade,rst_gpio = <13>;
parade,runfw_gpio = <64>;
parade,hid_desc_register = <1>;
/*
* PT_CORE_FLAG_NONE = 0x00
* PT_CORE_FLAG_POWEROFF_ON_SLEEP = 0x02
* PT_CORE_FLAG_RESTORE_PARAMETERS = 0x04
* PT_CORE_FLAG_DEEP_STANDBY = 0x08
* PT_CORE_FLAG_SKIP_SYS_SLEEP = 0x10
* PT_CORE_FLAG_SKIP_RUNTIME = 0x20
* PT_CORE_FLAG_SKIP_RESUME = 0x40
*/
parade,flags = <4>;
/* PT_CORE_EWG_NONE */
parade,easy_wakeup_gesture = <0>;
/* 0:AUTO 1:PIP1_ONLY 2:PIP2_CAPABLE*/
parade,config_dut_generation = <2>;
/* 0:False 1:True*/
parade,watchdog_force_stop = <0>;
/*
* PT_PANEL_ID_DISABLE = 0x00
* PT_PANEL_ID_BY_BL = 0x01
* PT_PANEL_ID_BY_SYS_INFO = 0x02
* PT_PANEL_ID_BY_MFG_DATA = 0x04
*/
parade,panel_id_support = <0>;
parade,btn_keys = <172 /* KEY_HOMEPAGE */
/* previously was KEY_HOME, new Android versions use KEY_HOMEPAGE */
139 /* KEY_MENU */
158 /* KEY_BACK */
217 /* KEY_SEARCH */
114 /* KEY_VOLUMEDOWN */
115 /* KEY_VOLUMEUP */
212 /* KEY_CAMERA */
116>; /* KEY_POWER */
parade,btn_keys-tag = <0>;
parade,mt {
parade,name = "pt_mt";
parade,inp_dev_name = "pt_mt";
/*
* PT_MT_FLAG_NONE = 0x00
* PT_MT_FLAG_FLIP = 0x08
* PT_MT_FLAG_INV_X = 0x10
* PT_MT_FLAG_INV_Y = 0x20
* PT_MT_FLAG_VKEYS = 0x40
*/
parade,flags = <0x00>;
parade,abs =
/* ABS_MT_POSITION_X, PT_ABS_MIN_X, PT_ABS_MAX_X, 0, 0 */
<0x35 0 880 0 0
/* ABS_MT_POSITION_Y, PT_ABS_MIN_Y, PT_ABS_MAX_Y, 0, 0 */
0x36 0 1280 0 0
/* ABS_MT_PRESSURE, PT_ABS_MIN_P, PT_ABS_MAX_P, 0, 0 */
0x3a 0 255 0 0
/* PT_IGNORE_VALUE, PT_ABS_MIN_W, PT_ABS_MAX_W, 0, 0 */
0xffff 0 255 0 0
/* ABS_MT_TRACKING_ID, PT_ABS_MIN_T, PT_ABS_MAX_T, 0, 0 */
0x39 0 15 0 0
/* ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0 */
0x30 0 255 0 0
/* ABS_MT_TOUCH_MINOR, 0, 255, 0, 0 */
0x31 0 255 0 0
/* ABS_MT_ORIENTATION, -127, 127, 0, 0 */
0x34 0xffffff81 127 0 0
/* ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0 */
0x37 0 1 0 0
/* ABS_DISTANCE, 0, 255, 0, 0 */
0x19 0 255 0 0>;
parade,vkeys_x = <720>;
parade,vkeys_y = <1280>;
parade,virtual_keys = /* KeyCode CenterX CenterY Width Height */
/* KEY_BACK */
<158 90 1360 160 180
/* KEY_MENU */
139 270 1360 160 180
/* KEY_HOMEPAGE */
172 450 1360 160 180
/* KEY SEARCH */
217 630 1360 160 180>;
};
};
};
};

View File

@ -252,7 +252,7 @@ config TOUCHSCREEN_CYTTSP4_SPI
module will be called cyttsp4_spi.
config TOUCHSCREEN_CYPRESS_CYTTSP5
tristate "Parade TrueTouch Gen5 Touchscreen Driver"
tristate "Parade TrueTouch Gen5 Touchscreen Driver (cyttsp5)"
help
Core driver for Parade TrueTouch(tm) Standard Product
Geneartion5 touchscreen controllers.
@ -470,6 +470,202 @@ config TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG_MDL
module will be called cyttsp5_debug.
config TOUCHSCREEN_PARADE
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 pt.
config TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
bool "Enable Device Tree support"
depends on TOUCHSCREEN_PARADE && OF
help
Say Y here to enable support for device tree.
If unsure, say N.
config TOUCHSCREEN_PARADE_DEBUG
bool "Enable debug output"
depends on TOUCHSCREEN_PARADE
help
Say Y here to enable debug output for Parade TrueTouch(tm)
Standard Product Generation5 drivers set.
If unsure, say N.
config TOUCHSCREEN_PARADE_VDEBUG
bool "Enable verbose debug output"
depends on TOUCHSCREEN_PARADE_DEBUG
help
Say Y here to enable verbose debug output for Parade TrueTouch(tm)
Standard Product Generation5 drivers set.
If unsure, say N.
config TOUCHSCREEN_PARADE_I2C
tristate "Parade TrueTouch Gen5 I2C"
depends on TOUCHSCREEN_PARADE
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 pt_i2c.
config TOUCHSCREEN_PARADE_SPI
tristate "Parade TrueTouch Gen5 SPI"
depends on TOUCHSCREEN_PARADE
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 pt_spi.
choice
bool "Parade TrueTouch Gen5 MultiTouch Protocol"
depends on TOUCHSCREEN_PARADE
default TOUCHSCREEN_PARADE_MT_B
help
This option controls which MultiTouch protocol will be used to
report the touch events.
config TOUCHSCREEN_PARADE_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_PARADE_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_PARADE_BUTTON
bool "Parade TrueTouch Gen5 MultiTouch CapSense Button"
depends on TOUCHSCREEN_PARADE
help
Say Y here to enable CapSense reporting on Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_PARADE_PROXIMITY
bool "Parade TrueTouch Gen5 Proximity"
depends on TOUCHSCREEN_PARADE
help
Say Y here to enable proximity reporting on Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_PARADE_DEVICE_ACCESS
tristate "Parade TrueTouch Gen5 MultiTouch Device Access"
depends on TOUCHSCREEN_PARADE
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 pt_device_access.
config TOUCHSCREEN_PARADE_LOADER
tristate "Parade TrueTouch Gen5 MultiTouch Loader"
depends on TOUCHSCREEN_PARADE
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 pt_loader.
config TOUCHSCREEN_PARADE_PLATFORM_FW_UPGRADE
bool "FW upgrade from header file"
depends on TOUCHSCREEN_PARADE_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_PARADE_BINARY_FW_UPGRADE
bool "FW upgrade from binary file"
depends on TOUCHSCREEN_PARADE_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_PARADE_PLATFORM_TTCONFIG_UPGRADE
bool "TT Configuration upgrade from header file"
depends on TOUCHSCREEN_PARADE_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_PARADE_MANUAL_TTCONFIG_UPGRADE
bool "TT Configuration upgrade via SysFs"
depends on TOUCHSCREEN_PARADE_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_PARADE_DEBUG_MDL
tristate "Parade TrueTouch Gen5 MultiTouch Debug Module"
depends on TOUCHSCREEN_PARADE
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 pt_debug.
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X

View File

@ -157,3 +157,53 @@ CFLAGS_cyttsp5_devtree.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_platform.o += -DVERBOSE_DEBUG
endif
GCOV_PROFILE := y
obj-$(CONFIG_TOUCHSCREEN_PARADE) += pt.o
pt-y := pt_core.o pt_mt_common.o
pt-$(CONFIG_TOUCHSCREEN_PARADE_MT_A) += pt_mta.o
pt-$(CONFIG_TOUCHSCREEN_PARADE_MT_B) += pt_mtb.o
pt-$(CONFIG_TOUCHSCREEN_PARADE_BUTTON) += pt_btn.o
pt-$(CONFIG_TOUCHSCREEN_PARADE_PROXIMITY) += pt_proximity.o
obj-$(CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT) += pt_devtree.o
ifdef CONFIG_TOUCHSCREEN_PARADE
obj-y += pt_platform.o
endif
obj-$(CONFIG_TOUCHSCREEN_PARADE_I2C) += pt_i2c.o
obj-$(CONFIG_TOUCHSCREEN_PARADE_SPI) += pt_spi.o
obj-$(CONFIG_TOUCHSCREEN_PARADE_DEBUG_MDL) += pt_debug.o
obj-$(CONFIG_TOUCHSCREEN_PARADE_LOADER) += pt_loader.o
obj-$(CONFIG_TOUCHSCREEN_PARADE_DEVICE_ACCESS) += pt_device_access.o
ifeq ($(CONFIG_TOUCHSCREEN_PARADE_DEBUG),y)
CFLAGS_pt_core.o += -DDEBUG
CFLAGS_pt_i2c.o += -DDEBUG
CFLAGS_pt_spi.o += -DDEBUG
CFLAGS_pt_mta.o += -DDEBUG
CFLAGS_pt_mtb.o += -DDEBUG
CFLAGS_pt_mt_common.o += -DDEBUG
CFLAGS_pt_btn.o += -DDEBUG
CFLAGS_pt_proximity.o += -DDEBUG
CFLAGS_pt_device_access.o += -DDEBUG
CFLAGS_pt_loader.o += -DDEBUG
CFLAGS_pt_debug.o += -DDEBUG
CFLAGS_pt_devtree.o += -DDEBUG
CFLAGS_pt_platform.o += -DDEBUG
endif
ifeq ($(CONFIG_TOUCHSCREEN_PARADE_VDEBUG),y)
CFLAGS_pt_core.o += -DVERBOSE_DEBUG
CFLAGS_pt_i2c.o += -DVERBOSE_DEBUG
CFLAGS_pt_spi.o += -DVERBOSE_DEBUG
CFLAGS_pt_mta.o += -DVERBOSE_DEBUG
CFLAGS_pt_mtb.o += -DVERBOSE_DEBUG
CFLAGS_pt_mt_common.o += -DVERBOSE_DEBUG
CFLAGS_pt_btn.o += -DVERBOSE_DEBUG
CFLAGS_pt_proximity.o += -DVERBOSE_DEBUG
CFLAGS_pt_device_access.o += -DVERBOSE_DEBUG
CFLAGS_pt_loader.o += -DVERBOSE_DEBUG
CFLAGS_pt_debug.o += -DVERBOSE_DEBUG
CFLAGS_pt_devtree.o += -DVERBOSE_DEBUG
CFLAGS_pt_platform.o += -DVERBOSE_DEBUG
endif

View File

@ -0,0 +1,522 @@
/*
* pt_btn.c
* Parade TrueTouch(TM) Standard Product CapSense Reports Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
/*******************************************************************************
* FUNCTION: pt_btn_key_action
*
* SUMMARY: Reports key event
*
* PARAMETERS:
* *bd - pointer to button data structure
* btn_no - number of button
* btn_state - state of button
******************************************************************************/
static inline void pt_btn_key_action(struct pt_btn_data *bd,
int btn_no, int btn_state)
{
struct device *dev = bd->dev;
struct pt_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);
pt_debug(dev, DL_INFO, "%s: btn=%d key_code=%d %s\n",
__func__, btn_no, si->btn[btn_no].key_code,
btn_state == PT_BTN_PRESSED ?
"PRESSED" : "RELEASED");
}
/*******************************************************************************
* FUNCTION: pt_get_btn_touches
*
* SUMMARY: Parse and report key event
*
* PARAMETERS:
* *bd - pointer to button data structure
******************************************************************************/
static void pt_get_btn_touches(struct pt_btn_data *bd)
{
struct pt_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 * PT_BITS_PER_BTN))
& PT_NUM_BTN_EVENT_ID;
pt_btn_key_action(bd, cur_btn, cur_btn_state);
}
}
/*******************************************************************************
* FUNCTION: pt_btn_lift_all
*
* SUMMARY: Reports button liftoff action
*
* PARAMETERS:
* *bd - pointer to button data structure
******************************************************************************/
static void pt_btn_lift_all(struct pt_btn_data *bd)
{
struct pt_sysinfo *si = bd->si;
int i;
if (!si || si->num_btns == 0)
return;
for (i = 0; i < si->num_btns; i++)
pt_btn_key_action(bd, i, PT_BTN_RELEASED);
}
/*******************************************************************************
* FUNCTION: pt_xy_worker
*
* SUMMARY: Read xy_data for all current CapSense button touches
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *bd - pointer to button data structure
******************************************************************************/
static int pt_xy_worker(struct pt_btn_data *bd)
{
struct pt_sysinfo *si = bd->si;
/* extract button press/release touch information */
if (si->num_btns > 0)
pt_get_btn_touches(bd);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_btn_attention
*
* SUMMARY: Wrapper function for pt_xy_worker() that register to TTDL attention
* list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_btn_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_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 = pt_xy_worker(bd);
mutex_unlock(&bd->btn_lock);
if (rc < 0)
pt_debug(dev, DL_ERROR,
"%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_startup_attention
*
* SUMMARY: Wrapper function for pt_btn_lift_all() that register to TTDL
* attention list.
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_startup_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
mutex_lock(&bd->btn_lock);
pt_btn_lift_all(bd);
mutex_unlock(&bd->btn_lock);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_btn_suspend_attention
*
* SUMMARY: Function for button to enter suspend state that as following steps:
* 1) Lift all button
* 2) Set flag with suspend state
* 3) Decrese pm system count
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_btn_suspend_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
mutex_lock(&bd->btn_lock);
pt_btn_lift_all(bd);
bd->is_suspended = true;
mutex_unlock(&bd->btn_lock);
pm_runtime_put(dev);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_btn_resume_attention
*
* SUMMARY: Function for button to leave suspend state that as following steps:
* 1) Increse pm system count
* 2) Clear suspend state flag
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_btn_resume_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_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;
}
/*******************************************************************************
* FUNCTION: pt_btn_open
*
* SUMMARY: Open method for input device(button) that sets up call back
* functions to TTDL attention list
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *input - pointer to input_dev structure
******************************************************************************/
static int pt_btn_open(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
pm_runtime_get_sync(dev);
mutex_lock(&bd->btn_lock);
bd->is_suspended = false;
mutex_unlock(&bd->btn_lock);
pt_debug(dev, DL_INFO, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_pt_subscribe_attention(dev, PT_ATTEN_IRQ, PT_BTN_NAME,
pt_btn_attention, PT_MODE_OPERATIONAL);
/* set up startup call back */
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP, PT_BTN_NAME,
pt_startup_attention, 0);
/* set up suspend call back */
_pt_subscribe_attention(dev, PT_ATTEN_SUSPEND, PT_BTN_NAME,
pt_btn_suspend_attention, 0);
/* set up resume call back */
_pt_subscribe_attention(dev, PT_ATTEN_RESUME, PT_BTN_NAME,
pt_btn_resume_attention, 0);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_btn_close
*
* SUMMARY: Close method for input device(button) that clears call back
* functions from TTDL attention list.
*
* PARAMETERS:
* *input - pointer to input_dev structure
******************************************************************************/
static void pt_btn_close(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
_pt_unsubscribe_attention(dev, PT_ATTEN_IRQ, PT_BTN_NAME,
pt_btn_attention, PT_MODE_OPERATIONAL);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP, PT_BTN_NAME,
pt_startup_attention, 0);
_pt_unsubscribe_attention(dev, PT_ATTEN_SUSPEND, PT_BTN_NAME,
pt_btn_suspend_attention, 0);
_pt_unsubscribe_attention(dev, PT_ATTEN_RESUME, PT_BTN_NAME,
pt_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);
}
/*******************************************************************************
* FUNCTION: pt_setup_input_device
*
* SUMMARY: Set up resolution, event signal capabilities and register input
* device for button.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_setup_input_device(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
int i;
int rc;
pt_debug(dev, DL_INFO, "%s: Initialize event signals\n",
__func__);
__set_bit(EV_KEY, bd->input->evbit);
pt_debug(dev, DL_INFO, "%s: Number of buttons %d\n",
__func__, bd->si->num_btns);
for (i = 0; i < bd->si->num_btns; i++) {
pt_debug(dev, DL_INFO, "%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)
pt_debug(dev, DL_ERROR,
"%s: Error, failed register input device r=%d\n",
__func__, rc);
else
bd->input_device_registered = true;
return rc;
}
/*******************************************************************************
* FUNCTION: pt_setup_input_attention
*
* SUMMARY: Wrapper function for pt_setup_input_device() register to TTDL
* attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_setup_input_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
int rc;
bd->si = _pt_request_sysinfo(dev);
if (!bd->si)
return -1;
rc = pt_setup_input_device(dev);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP, PT_BTN_NAME,
pt_setup_input_attention, 0);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_btn_probe
*
* SUMMARY: The probe function for button input device
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
int pt_btn_probe(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_btn_data *bd = &cd->bd;
struct pt_platform_data *pdata = dev_get_platdata(dev);
struct pt_btn_platform_data *btn_pdata;
int rc = 0;
if (!pdata || !pdata->btn_pdata) {
pt_debug(dev, DL_ERROR,
"%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. */
pt_debug(dev, DL_INFO,
"%s: Create the input device and register it\n", __func__);
bd->input = input_allocate_device();
if (!bd->input) {
pt_debug(dev, DL_ERROR,
"%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
} else
bd->input_device_allocated = true;
if (bd->pdata->inp_dev_name)
bd->input->name = bd->pdata->inp_dev_name;
else
bd->input->name = PT_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 = pt_btn_open;
bd->input->close = pt_btn_close;
input_set_drvdata(bd->input, bd);
/* get sysinfo */
bd->si = _pt_request_sysinfo(dev);
if (bd->si) {
rc = pt_setup_input_device(dev);
if (rc)
goto error_init_input;
} else {
pt_debug(dev, DL_ERROR,
"%s: Fail get sysinfo pointer from core p=%p\n",
__func__, bd->si);
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
PT_BTN_NAME, pt_setup_input_attention, 0);
}
return 0;
error_init_input:
input_free_device(bd->input);
bd->input_device_allocated = false;
error_alloc_failed:
error_no_pdata:
pt_debug(dev, DL_ERROR, "%s failed.\n", __func__);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_btn_release
*
* SUMMARY: The release function for button input device
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
int pt_btn_release(struct device *dev)
{
struct pt_core_data *cd;
struct pt_btn_data *bd;
/* Ensure valid pointers before de-referencing them */
if (dev) {
cd = dev_get_drvdata(dev);
if (cd)
bd = &cd->bd;
else
return 0;
} else {
return 0;
}
/*
* Second call this function may cause kernel panic if probe fail.
* Use input_device_registered & input_device_allocated variable to
* avoid unregister or free unavailable devive.
*/
if (bd && bd->input_device_registered) {
bd->input_device_registered = false;
input_unregister_device(bd->input);
/* Unregistering device will free the device too */
bd->input_device_allocated = false;
} else if (bd && bd->input_device_allocated) {
bd->input_device_allocated = false;
input_free_device(bd->input);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
PT_BTN_NAME, pt_setup_input_attention, 0);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,556 @@
/*
* pt_debug.c
* Parade TrueTouch(TM) Standard Product Debug Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
#define PT_DEBUG_NAME "pt_debug"
struct pt_debug_data {
struct device *dev;
struct pt_sysinfo *si;
uint32_t interrupt_count;
uint32_t formated_output;
struct mutex sysfs_lock;
u8 pr_buf[PT_MAX_PRBUF_SIZE];
};
static struct pt_core_commands *cmd;
static struct pt_module debug_module;
/*******************************************************************************
* FUNCTION: pt_get_debug_data
*
* SUMMARY: Inline function to get pt_debug_data pointer from debug module.
*
* RETURN:
* pointer to pt_debug_data structure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static inline struct pt_debug_data *pt_get_debug_data(
struct device *dev)
{
return pt_get_module_data(dev, &debug_module);
}
/*******************************************************************************
* FUNCTION: pt_pr_buf_op_mode
*
* SUMMARY: Formats touch/button report to pr_buf that combined xy_mode and
* xy_data. The feature is required by TTHE.
*
* PARAMETERS:
* *dd - pointer to pt_debug_data structure
* *pr_buf - pointer to print buffer
* *si - pointer to sysinfo structure
* cur_touch - number of current touch
******************************************************************************/
static void pt_pr_buf_op_mode(struct pt_debug_data *dd, u8 *pr_buf,
struct pt_sysinfo *si, u8 cur_touch)
{
const char fmt[] = "%02X ";
int max = (PT_MAX_PRBUF_SIZE - 1) - sizeof(PT_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, PT_MAX_PRBUF_SIZE, fmt, si->xy_mode[i]);
for (i = 0; i < report_size && i < max; i++, k += 3)
scnprintf(pr_buf + k, PT_MAX_PRBUF_SIZE, fmt, si->xy_data[i]);
pr_info("%s=%s%s\n", "pt_OpModeData", pr_buf,
total_size <= max ? "" : PT_PR_TRUNCATED);
}
/*******************************************************************************
* FUNCTION: pt_debug_print
*
* SUMMARY: This function prints header to show data size and data_name and
* content of "pr_buf" with hex base.
*
* PARAMETERS:
* *dev - pointer to device structure
* *pr_buf - pointer to input buffer which stores the formated data
* *sptr - pointer to the buffer to print
* size - size of data elements
* *data_name - data name to print
******************************************************************************/
static void pt_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 = (PT_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, PT_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 ? "" : PT_PR_TRUNCATED);
else
pr_info("%s[]\n", data_name);
}
/*******************************************************************************
* FUNCTION: pt_debug_formated
*
* SUMMARY: Formats and prints touch & button report.
*
* PARAMETERS:
* *dev - pointer to device structure
* *pr_buf - pointer to print buffer
* *si - pointer to sysinfo structure
* cur_touch - number of current touch
******************************************************************************/
static void pt_debug_formated(struct device *dev, u8 *pr_buf,
struct pt_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 */
pt_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) {
pt_debug_print(dev, pr_buf, si->xy_data + i,
max_print_length, " ");
}
if (report_size - i)
pt_debug_print(dev, pr_buf, si->xy_data + i,
report_size - i, " ");
} else {
pt_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);
pt_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)
pt_debug_print(dev, pr_buf, si->xy_data, report_size,
"button");
}
/*******************************************************************************
* FUNCTION: pt_xy_worker
*
* SUMMARY: Read xy_data for all touches for debug.
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dd - pointer to pt_debug_data structure
******************************************************************************/
static int pt_xy_worker(struct pt_debug_data *dd)
{
struct device *dev = dd->dev;
struct pt_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)
pt_debug_formated(dev, dd->pr_buf, si, num_cur_tch);
else
/* print data for TTHE */
pt_pr_buf_op_mode(dd, dd->pr_buf, si, num_cur_tch);
pr_info("\n");
return 0;
}
/*******************************************************************************
* FUNCTION: pt_debug_attention
*
* SUMMARY: Wrapper funtion for pt_xy_worker() to subcribe into TTDL attention
* list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_debug_attention(struct device *dev)
{
struct pt_debug_data *dd = pt_get_debug_data(dev);
struct pt_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 = pt_xy_worker(dd);
if (rc < 0)
pt_debug(dev, DL_ERROR, "%s: xy_worker error r=%d\n",
__func__, rc);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_status_show
*
* SUMMARY: The show method for the int_count sysfs node. This node displays
* the count of interrupt.
*
* PARAMETERS:
* *dev - pointer to Device structure
* *attr - pointer to the device attribute structure
* *buf - pointer to buffer to print
******************************************************************************/
static ssize_t pt_interrupt_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pt_debug_data *dd = pt_get_debug_data(dev);
int val;
mutex_lock(&dd->sysfs_lock);
val = dd->interrupt_count;
mutex_unlock(&dd->sysfs_lock);
return scnprintf(buf, PT_MAX_PRBUF_SIZE, "Interrupt Count: %d\n", val);
}
/*******************************************************************************
* FUNCTION: pt_interrupt_count_store
*
* SUMMARY: The store method for the int_count sysfs node that allows the count
* of interrput to be cleared.
*
* RETURN: Size of passed in buffer
*
* PARAMETERS:
* *dev - pointer to device structure
* *attr - pointer to device attributes
* *buf - pointer to buffer that hold the command parameters
* size - size of buf
******************************************************************************/
static ssize_t pt_interrupt_count_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct pt_debug_data *dd = pt_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, 0600,
pt_interrupt_count_show, pt_interrupt_count_store);
/*******************************************************************************
* FUNCTION: pt_formated_output_show
*
* SUMMARY: Show method for the formated_output sysfs node that will show
* whether to format data to buffer or print directly.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
* *attr - pointer to device attributes
* *buf - pointer to output buffer
******************************************************************************/
static ssize_t pt_formated_output_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pt_debug_data *dd = pt_get_debug_data(dev);
int val;
mutex_lock(&dd->sysfs_lock);
val = dd->formated_output;
mutex_unlock(&dd->sysfs_lock);
return scnprintf(buf, PT_MAX_PRBUF_SIZE,
"Formated debug output: %x\n", val);
}
/*******************************************************************************
* FUNCTION: pt_formated_output_store
*
* SUMMARY: The store method for the formated_output sysfs node. Allows the
* setting to format data to buffer or print directly.
*
* RETURN: Size of passed in buffer
*
* PARAMETERS:
* *dev - pointer to device structure
* *attr - pointer to device attributes
* *buf - pointer to buffer that hold the command parameters
* size - size of buf
******************************************************************************/
static ssize_t pt_formated_output_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct pt_debug_data *dd = pt_get_debug_data(dev);
unsigned long value;
int rc;
rc = kstrtoul(buf, 10, &value);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Invalid value\n", __func__);
return size;
}
/* Expecting only 0 or 1 */
if (value != 0 && value != 1) {
pt_debug(dev, DL_ERROR, "%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, 0600,
pt_formated_output_show, pt_formated_output_store);
/*******************************************************************************
* FUNCTION: pt_mt_probe
*
* SUMMARY: The probe function for debug module to create sysfs nodes and
* subscribe attention list.
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
* **data - double pointer tothe pt_debug_data structure to be created here
******************************************************************************/
static int pt_debug_probe(struct device *dev, void **data)
{
struct pt_debug_data *dd;
int rc;
/* get context and debug print buffers */
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
if (!dd) {
rc = -ENOMEM;
goto pt_debug_probe_alloc_failed;
}
rc = device_create_file(dev, &dev_attr_int_count);
if (rc) {
pt_debug(dev, DL_ERROR, "%s: Error, could not create int_count\n",
__func__);
goto pt_debug_probe_create_int_count_failed;
}
rc = device_create_file(dev, &dev_attr_formated_output);
if (rc) {
pt_debug(dev, DL_ERROR, "%s: Error, could not create formated_output\n",
__func__);
goto pt_debug_probe_create_formated_failed;
}
mutex_init(&dd->sysfs_lock);
dd->dev = dev;
*data = dd;
dd->si = cmd->request_sysinfo(dev);
if (!dd->si) {
pt_debug(dev, DL_ERROR, "%s: Fail get sysinfo pointer from core\n",
__func__);
rc = -ENODEV;
goto pt_debug_probe_sysinfo_failed;
}
rc = cmd->subscribe_attention(dev, PT_ATTEN_IRQ, PT_DEBUG_NAME,
pt_debug_attention, PT_MODE_OPERATIONAL);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Error, could not subscribe attention cb\n",
__func__);
goto pt_debug_probe_subscribe_failed;
}
return 0;
pt_debug_probe_subscribe_failed:
pt_debug_probe_sysinfo_failed:
device_remove_file(dev, &dev_attr_formated_output);
pt_debug_probe_create_formated_failed:
device_remove_file(dev, &dev_attr_int_count);
pt_debug_probe_create_int_count_failed:
kfree(dd);
pt_debug_probe_alloc_failed:
pt_debug(dev, DL_ERROR, "%s failed.\n", __func__);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_debug_release
*
* SUMMARY: Remove function for debug module that does following cleanup:
* - Unsubscibe all registered attention tasks
* - Removes all created sysfs nodes
*
* PARAMETERS:
* *dev - pointer to device structure
* *data - pointer to the pt_debug_data structure
******************************************************************************/
static void pt_debug_release(struct device *dev, void *data)
{
struct pt_debug_data *dd = data;
int rc;
rc = cmd->unsubscribe_attention(dev, PT_ATTEN_IRQ, PT_DEBUG_NAME,
pt_debug_attention, PT_MODE_OPERATIONAL);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Error, could not un-subscribe attention\n",
__func__);
goto pt_debug_release_exit;
}
pt_debug_release_exit:
device_remove_file(dev, &dev_attr_formated_output);
device_remove_file(dev, &dev_attr_int_count);
kfree(dd);
}
static struct pt_module debug_module = {
.name = PT_DEBUG_NAME,
.probe = pt_debug_probe,
.release = pt_debug_release,
};
/*******************************************************************************
* FUNCTION: pt_debug_init
*
* SUMMARY: Initialize function for debug module which to register
* debug_module into TTDL module list.
*
* RETURN:
* 0 = success
******************************************************************************/
static int __init pt_debug_init(void)
{
int rc;
cmd = pt_get_commands();
if (!cmd)
return -EINVAL;
rc = pt_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__, PT_DRIVER_VERSION, rc);
return 0;
}
module_init(pt_debug_init);
/*******************************************************************************
* FUNCTION: pt_debug_exit
*
* SUMMARY: Exit function for debug module which to unregister debug_module
* from TTDL module list.
*
******************************************************************************/
static void __exit pt_debug_exit(void)
{
pt_unregister_module(&debug_module);
}
module_exit(pt_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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
/*
* pt_i2c.c
* Parade TrueTouch(TM) Standard Product I2C Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
#include <linux/i2c.h>
#include <linux/version.h>
#define PT_I2C_DATA_SIZE (2 * 256)
/*******************************************************************************
* FUNCTION: pt_i2c_read_default
*
* SUMMARY: Read a certain number of bytes from the I2C bus
*
* PARAMETERS:
* *dev - pointer to Device structure
* *buf - pointer to buffer where the data read will be stored
* size - size to be read
******************************************************************************/
static int pt_i2c_read_default(struct device *dev, void *buf, int size)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
int read_size = size;
if (!buf || !size || size > PT_I2C_DATA_SIZE)
return -EINVAL;
rc = i2c_master_recv(client, buf, read_size);
return (rc < 0) ? rc : rc != read_size ? -EIO : 0;
}
/*******************************************************************************
* FUNCTION: pt_i2c_read_default_nosize
*
* SUMMARY: Read from the I2C bus in two transactions first reading the HID
* packet size (2 bytes) followed by reading the rest of the packet based
* on the size initially read.
* NOTE: The empty buffer 'size' was redefined in PIP version 1.7.
*
* PARAMETERS:
* *dev - pointer to Device structure
* *buf - pointer to buffer where the data read will be stored
* max - max size that can be read
******************************************************************************/
static int pt_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 >= PT_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;
}
/*******************************************************************************
* FUNCTION: pt_i2c_write_read_specific
*
* SUMMARY: Write the contents of write_buf to the I2C device and then read
* the response using pt_i2c_read_default_nosize()
*
* PARAMETERS:
* *dev - pointer to Device structure
* write_len - length of data buffer write_buf
* *write_buf - pointer to buffer to write
* *read_buf - pointer to buffer to read response into
******************************************************************************/
static int pt_i2c_write_read_specific(struct device *dev, u16 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;
/* Ensure no packet larger than what the PIP spec allows */
if (write_len > PT_MAX_PIP2_MSG_SIZE)
return -EINVAL;
if (!write_buf || !write_len) {
if (!write_buf)
pt_debug(dev, DL_ERROR,
"%s write_buf is NULL", __func__);
if (!write_len)
pt_debug(dev, DL_ERROR,
"%s write_len is NULL", __func__);
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 = pt_i2c_read_default_nosize(dev, read_buf,
PT_I2C_DATA_SIZE);
}
return rc;
}
static struct pt_bus_ops pt_i2c_bus_ops = {
.bustype = BUS_I2C,
.read_default = pt_i2c_read_default,
.read_default_nosize = pt_i2c_read_default_nosize,
.write_read_specific = pt_i2c_write_read_specific,
};
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
static const struct of_device_id pt_i2c_of_match[] = {
{ .compatible = "parade,pt_i2c_adapter", },
{ }
};
MODULE_DEVICE_TABLE(of, pt_i2c_of_match);
#endif
/*******************************************************************************
* FUNCTION: pt_i2c_probe
*
* SUMMARY: Probe functon for the I2C module
*
* PARAMETERS:
* *client - pointer to i2c client structure
* *i2c_id - pointer to i2c device structure
******************************************************************************/
static int pt_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct device *dev = &client->dev;
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
int rc;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
pt_debug(dev, DL_ERROR, "I2C functionality not Supported\n");
return -EIO;
}
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(pt_i2c_of_match), dev);
if (match) {
rc = pt_devtree_create_and_get_pdata(dev);
if (rc < 0)
return rc;
}
#endif
rc = pt_probe(&pt_i2c_bus_ops, &client->dev, client->irq,
PT_I2C_DATA_SIZE);
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
if (rc && match)
pt_devtree_clean_pdata(dev);
#endif
return rc;
}
/*******************************************************************************
* FUNCTION: pt_i2c_remove
*
* SUMMARY: Remove functon for the I2C module
*
* PARAMETERS:
* *client - pointer to i2c client structure
******************************************************************************/
static int pt_i2c_remove(struct i2c_client *client)
{
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
struct device *dev = &client->dev;
struct pt_core_data *cd = i2c_get_clientdata(client);
pt_release(cd);
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(pt_i2c_of_match), dev);
if (match)
pt_devtree_clean_pdata(dev);
#endif
return 0;
}
static const struct i2c_device_id pt_i2c_id[] = {
{ PT_I2C_NAME, 0, },
{ }
};
MODULE_DEVICE_TABLE(i2c, pt_i2c_id);
static struct i2c_driver pt_i2c_driver = {
.driver = {
.name = PT_I2C_NAME,
.owner = THIS_MODULE,
.pm = &pt_pm_ops,
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
.of_match_table = pt_i2c_of_match,
#endif
},
.probe = pt_i2c_probe,
.remove = pt_i2c_remove,
.id_table = pt_i2c_id,
};
#if (KERNEL_VERSION(3, 3, 0) <= LINUX_VERSION_CODE)
module_i2c_driver(pt_i2c_driver);
#else
/*******************************************************************************
* FUNCTION: pt_i2c_init
*
* SUMMARY: Initialize function to register i2c module to kernel.
*
* RETURN:
* 0 = success
* !0 = failure
******************************************************************************/
static int __init pt_i2c_init(void)
{
int rc = i2c_add_driver(&pt_i2c_driver);
pr_info("%s: Parade TTDL I2C Driver (Build %s) rc=%d\n",
__func__, PT_DRIVER_VERSION, rc);
return rc;
}
module_init(pt_i2c_init);
/*******************************************************************************
* FUNCTION: pt_i2c_exit
*
* SUMMARY: Exit function to unregister i2c module from kernel.
*
******************************************************************************/
static void __exit pt_i2c_exit(void)
{
i2c_del_driver(&pt_i2c_driver);
}
module_exit(pt_i2c_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product I2C driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,998 @@
/*
* pt_mt_common.c
* Parade TrueTouch(TM) Standard Product Multi-Touch Reports Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
#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)
/*******************************************************************************
* FUNCTION: pt_mt_lift_all
*
* SUMMARY: Reports touch liftoff action
*
* PARAMETERS:
* *md - pointer to touch data structure
******************************************************************************/
static void pt_mt_lift_all(struct pt_mt_data *md)
{
int max = md->si->tch_abs[PT_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;
}
}
/*******************************************************************************
* FUNCTION: pt_get_touch_axis
*
* SUMMARY: Calculates touch axis
*
* PARAMETERS:
* *md - pointer to touch data structure
* *axis - pointer to axis calculation result
* size - size in byte
* max - max value of result
* *xy_data - pointer to input data to be parsed
* bofs - bit offset
******************************************************************************/
static void pt_get_touch_axis(struct pt_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++) {
pt_debug(md->dev, DL_DEBUG,
"%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;
pt_debug(md->dev, DL_DEBUG,
"%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]);
}
/*******************************************************************************
* FUNCTION: pt_get_touch_hdr
*
* SUMMARY: Get the header of touch report
*
* PARAMETERS:
* *md - pointer to touch data structure
* *touch - pointer to pt_touch structure
* *xy_mode - pointer to touch mode data
******************************************************************************/
static void pt_get_touch_hdr(struct pt_mt_data *md,
struct pt_touch *touch, u8 *xy_mode)
{
struct device *dev = md->dev;
struct pt_sysinfo *si = md->si;
enum pt_tch_hdr hdr;
for (hdr = PT_TCH_TIME; hdr < PT_TCH_NUM_HDR; hdr++) {
if (!si->tch_hdr[hdr].report)
continue;
pt_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);
pt_debug(dev, DL_DEBUG, "%s: get %s=%04X(%d)\n",
__func__, pt_tch_hdr_string[hdr],
touch->hdr[hdr], touch->hdr[hdr]);
}
pt_debug(dev, DL_INFO,
"%s: time=%X tch_num=%d lo=%d noise=%d counter=%d\n",
__func__,
touch->hdr[PT_TCH_TIME],
touch->hdr[PT_TCH_NUM],
touch->hdr[PT_TCH_LO],
touch->hdr[PT_TCH_NOISE],
touch->hdr[PT_TCH_COUNTER]);
}
/*******************************************************************************
* FUNCTION: pt_get_touch_record
*
* SUMMARY: Gets axis of touch report
*
* PARAMETERS:
* *md - pointer to touch data structure
* *touch - pointer to pt_touch structure
* *xy_data - pointer to touch data
******************************************************************************/
static void pt_get_touch_record(struct pt_mt_data *md,
struct pt_touch *touch, u8 *xy_data)
{
struct device *dev = md->dev;
struct pt_sysinfo *si = md->si;
enum pt_tch_abs abs;
for (abs = PT_TCH_X; abs < PT_TCH_NUM_ABS; abs++) {
if (!si->tch_abs[abs].report)
continue;
pt_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);
pt_debug(dev, DL_DEBUG, "%s: get %s=%04X(%d)\n",
__func__, pt_tch_abs_string[abs],
touch->abs[abs], touch->abs[abs]);
}
}
/*******************************************************************************
* FUNCTION: pt_mt_process_touch
*
* SUMMARY: Process touch includes oritation,axis invert and
* convert MAJOR/MINOR from mm to resolution
*
* PARAMETERS:
* *md - pointer to touch data structure
* *touch - pointer to pt_touch structure
******************************************************************************/
static void pt_mt_process_touch(struct pt_mt_data *md,
struct pt_touch *touch)
{
struct device *dev = md->dev;
struct pt_sysinfo *si = md->si;
int tmp;
bool flipped;
/* Orientation is signed */
touch->abs[PT_TCH_OR] = (int8_t)touch->abs[PT_TCH_OR];
if (md->pdata->flags & PT_MT_FLAG_FLIP) {
tmp = touch->abs[PT_TCH_X];
touch->abs[PT_TCH_X] = touch->abs[PT_TCH_Y];
touch->abs[PT_TCH_Y] = tmp;
if (touch->abs[PT_TCH_OR] > 0)
touch->abs[PT_TCH_OR] =
md->or_max - touch->abs[PT_TCH_OR];
else
touch->abs[PT_TCH_OR] =
md->or_min - touch->abs[PT_TCH_OR];
flipped = true;
} else
flipped = false;
/*
* 1 is subtracted from each touch location to make the location
* 0 based. e.g. If the resolution of touch panel is 1200x1600,
* the FW touch report must be (0~1199,0~1599). The driver
* should register the (min,max) value to Linux input system as
* (0~1199,0~1599). When the host needs to invert the
* coordinates, the driver would incorrectly use the resolution
* to subtract the reported point directly, such as
* 1200-(0~1199). The input system will lose the 0 point report
* and the 1200 point will be ignored.
*/
if (md->pdata->flags & PT_MT_FLAG_INV_X) {
if (flipped)
touch->abs[PT_TCH_X] = si->sensing_conf_data.res_y -
touch->abs[PT_TCH_X] - 1;
else
touch->abs[PT_TCH_X] = si->sensing_conf_data.res_x -
touch->abs[PT_TCH_X] - 1;
touch->abs[PT_TCH_OR] *= -1;
}
if (md->pdata->flags & PT_MT_FLAG_INV_Y) {
if (flipped)
touch->abs[PT_TCH_Y] = si->sensing_conf_data.res_x -
touch->abs[PT_TCH_Y] - 1;
else
touch->abs[PT_TCH_Y] = si->sensing_conf_data.res_y -
touch->abs[PT_TCH_Y] - 1;
touch->abs[PT_TCH_OR] *= -1;
}
/* Convert MAJOR/MINOR from mm to resolution */
tmp = touch->abs[PT_TCH_MAJ] * 100 * si->sensing_conf_data.res_x;
touch->abs[PT_TCH_MAJ] = tmp / si->sensing_conf_data.len_x;
tmp = touch->abs[PT_TCH_MIN] * 100 * si->sensing_conf_data.res_x;
touch->abs[PT_TCH_MIN] = tmp / si->sensing_conf_data.len_x;
pt_debug(dev, DL_INFO,
"%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
__func__, flipped ? "true" : "false",
md->pdata->flags & PT_MT_FLAG_INV_X ? "true" : "false",
md->pdata->flags & PT_MT_FLAG_INV_Y ? "true" : "false",
touch->abs[PT_TCH_X], touch->abs[PT_TCH_X],
touch->abs[PT_TCH_Y], touch->abs[PT_TCH_Y]);
}
/*******************************************************************************
* FUNCTION: pt_report_event
*
* SUMMARY: Reports touch event
*
* PARAMETERS:
* *md - pointer to touch data structure
* event - type of touch event
* value - value of report event
******************************************************************************/
static void pt_report_event(struct pt_mt_data *md, int event,
int value)
{
int sig = MT_PARAM_SIGNAL(md, event);
if (sig != PT_IGNORE_VALUE)
input_report_abs(md->input, sig, value);
}
/*******************************************************************************
* FUNCTION: pt_get_mt_touches
*
* SUMMARY: Parse and report touch event
*
* PARAMETERS:
* *md - pointer to touch data structure
* *tch - pointer to touch structure
* num_cur_tch - number of current touch
******************************************************************************/
static void pt_get_mt_touches(struct pt_mt_data *md,
struct pt_touch *tch, int num_cur_tch)
{
struct device *dev = md->dev;
struct pt_sysinfo *si = md->si;
int sig;
int i, j, t = 0;
DECLARE_BITMAP(ids, si->tch_abs[PT_TCH_T].max);
int mt_sync_count = 0;
u8 *tch_addr;
bitmap_zero(ids, si->tch_abs[PT_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);
pt_get_touch_record(md, tch, tch_addr);
/* Discard proximity event */
if (tch->abs[PT_TCH_O] == PT_OBJ_PROXIMITY) {
pt_debug(dev, DL_INFO,
"%s: Discarding proximity event\n",
__func__);
continue;
}
/* Validate track_id */
t = tch->abs[PT_TCH_T];
if (t < md->t_min || t > md->t_max) {
pt_debug(dev, DL_INFO,
"%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++;
continue;
}
/* Lift-off */
if (tch->abs[PT_TCH_E] == PT_EV_LIFTOFF) {
pt_debug(dev, DL_INFO, "%s: t=%d e=%d lift-off\n",
__func__, t, tch->abs[PT_TCH_E]);
goto pt_get_mt_touches_pr_tch;
}
/* Process touch */
pt_mt_process_touch(md, tch);
/* use 0 based track id's */
t -= md->t_min;
sig = MT_PARAM_SIGNAL(md, PT_ABS_ID_OST);
if (sig != PT_IGNORE_VALUE) {
if (md->mt_function.input_report)
md->mt_function.input_report(md->input, sig,
t, tch->abs[PT_TCH_O]);
__set_bit(t, ids);
}
pt_report_event(md, PT_ABS_D_OST, 0);
/* all devices: position and pressure fields */
for (j = 0; j <= PT_ABS_W_OST; j++) {
if (!si->tch_abs[j].report)
continue;
pt_report_event(md, PT_ABS_X_OST + j,
tch->abs[PT_TCH_X + j]);
}
/* Get the extended touch fields */
for (j = 0; j < PT_NUM_EXT_TCH_FIELDS; j++) {
if (!si->tch_abs[PT_ABS_MAJ_OST + j].report)
continue;
pt_report_event(md, PT_ABS_MAJ_OST + j,
tch->abs[PT_TCH_MAJ + j]);
}
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
mt_sync_count++;
pt_get_mt_touches_pr_tch:
pt_debug(dev, DL_INFO,
"%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[PT_TCH_X],
tch->abs[PT_TCH_Y],
tch->abs[PT_TCH_P],
tch->abs[PT_TCH_MAJ],
tch->abs[PT_TCH_MIN],
tch->abs[PT_TCH_OR],
tch->abs[PT_TCH_E],
tch->abs[PT_TCH_O],
tch->abs[PT_TCH_TIP]);
}
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input,
si->tch_abs[PT_TCH_T].max, mt_sync_count, ids);
md->num_prv_rec = num_cur_tch;
}
/*******************************************************************************
* FUNCTION: pt_xy_worker
*
* SUMMARY: Read xy_data for all current touches
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *md - pointer to touch data structure
******************************************************************************/
static int pt_xy_worker(struct pt_mt_data *md)
{
struct device *dev = md->dev;
struct pt_sysinfo *si = md->si;
int max_tch = si->sensing_conf_data.max_tch;
struct pt_touch tch;
u8 num_cur_tch;
int rc = 0;
pt_get_touch_hdr(md, &tch, si->xy_mode + 3);
num_cur_tch = tch.hdr[PT_TCH_NUM];
if (num_cur_tch > max_tch) {
pt_debug(dev, DL_ERROR, "%s: Num touch err detected (n=%d)\n",
__func__, num_cur_tch);
num_cur_tch = max_tch;
}
if (tch.hdr[PT_TCH_LO]) {
pt_debug(dev, DL_INFO, "%s: Large area detected\n",
__func__);
if (md->pdata->flags & PT_MT_FLAG_NO_TOUCH_ON_LO)
num_cur_tch = 0;
}
if (num_cur_tch == 0 && md->num_prv_rec == 0)
goto pt_xy_worker_exit;
/* extract xy_data for all currently reported touches */
pt_debug(dev, DL_DEBUG, "%s: extract data num_cur_tch=%d\n",
__func__, num_cur_tch);
if (num_cur_tch)
pt_get_mt_touches(md, &tch, num_cur_tch);
else
pt_mt_lift_all(md);
rc = 0;
pt_xy_worker_exit:
return rc;
}
/*******************************************************************************
* FUNCTION: pt_mt_send_dummy_event
*
* SUMMARY: Send dummy/key event to wakeup upper layer of system
*
* PARAMETERS:
* *cd - pointer to core data structure
* *md - pointer to touch data structure
******************************************************************************/
static void pt_mt_send_dummy_event(struct pt_core_data *cd,
struct pt_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, PT_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 and above only. TSG6 FW1.0 - 1.2 does not */
/* support EasyWake, and this function will not be called */
u8 key_value = 0;
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;
}
if (key_value > 0) {
input_report_key(md->input, key_value, 1);
mdelay(10);
input_report_key(md->input, key_value, 0);
input_sync(md->input);
}
/*
* Caution - this debug print is needed by the TTDL automated
* regression test suite
*/
pt_debug(md->dev, DL_INFO, "%s: report key: %d\n",
__func__, key_value);
#endif
}
/*******************************************************************************
* FUNCTION: pt_mt_attention
*
* SUMMARY: Wrapper function for pt_xy_worker() that subscribe into the TTDL
* attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_mt_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_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 = pt_xy_worker(md);
mutex_unlock(&md->mt_lock);
if (rc < 0)
pt_debug(dev, DL_ERROR,
"%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_mt_wake_attention
*
* SUMMARY: Wrapper function for pt_mt_send_dummy_event() that register to
* attention list.
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_mt_wake_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
pt_mt_send_dummy_event(cd, md);
mutex_unlock(&md->mt_lock);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_startup_attention
*
* SUMMARY: Wrapper function for pt_mt_lift_all() that subcribe into the TTDL
* attention list.
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_startup_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
pt_mt_lift_all(md);
mutex_unlock(&md->mt_lock);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_mt_suspend_attention
*
* SUMMARY: Function for touch to enter suspend state that as following steps:
* 1) Lift all touch
* 2) Set flag with suspend state
* 3) Decrese pm system count
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_mt_suspend_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
pt_mt_lift_all(md);
md->is_suspended = true;
mutex_unlock(&md->mt_lock);
pm_runtime_put(dev);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_mt_resume_attention
*
* SUMMARY: Function for touch to leave suspend state that as following steps:
* 1) Increse pm system count
* 2) Clear suspend state flag
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_mt_resume_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_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;
}
/*******************************************************************************
* FUNCTION: pt_mt_open
*
* SUMMARY: Open method for input device(touch) that sets up call back
* functions to TTDL attention list
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *input - pointer to input_dev structure
******************************************************************************/
static int pt_mt_open(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
pm_runtime_get_sync(dev);
mutex_lock(&md->mt_lock);
md->is_suspended = false;
mutex_unlock(&md->mt_lock);
pt_debug(dev, DL_INFO, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_pt_subscribe_attention(dev, PT_ATTEN_IRQ, PT_MT_NAME,
pt_mt_attention, PT_MODE_OPERATIONAL);
/* set up startup call back */
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP, PT_MT_NAME,
pt_startup_attention, 0);
/* set up wakeup call back */
_pt_subscribe_attention(dev, PT_ATTEN_WAKE, PT_MT_NAME,
pt_mt_wake_attention, 0);
/* set up suspend call back */
_pt_subscribe_attention(dev, PT_ATTEN_SUSPEND, PT_MT_NAME,
pt_mt_suspend_attention, 0);
/* set up resume call back */
_pt_subscribe_attention(dev, PT_ATTEN_RESUME, PT_MT_NAME,
pt_mt_resume_attention, 0);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_mt_close
*
* SUMMARY: Close method for input device(touch) that clears call back
* functions from TTDL attention list.
*
* PARAMETERS:
* *input - pointer to input_dev structure
******************************************************************************/
static void pt_mt_close(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
_pt_unsubscribe_attention(dev, PT_ATTEN_IRQ, PT_MT_NAME,
pt_mt_attention, PT_MODE_OPERATIONAL);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP, PT_MT_NAME,
pt_startup_attention, 0);
_pt_unsubscribe_attention(dev, PT_ATTEN_WAKE, PT_MT_NAME,
pt_mt_wake_attention, 0);
_pt_unsubscribe_attention(dev, PT_ATTEN_SUSPEND, PT_MT_NAME,
pt_mt_suspend_attention, 0);
_pt_unsubscribe_attention(dev, PT_ATTEN_RESUME, PT_MT_NAME,
pt_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);
}
/*******************************************************************************
* FUNCTION: pt_setup_input_device
*
* SUMMARY: Set up resolution, event signal capabilities and
* register input device for touch.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_setup_input_device(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
int signal = PT_IGNORE_VALUE;
int max_x, max_y, max_p, min, max;
int max_x_tmp, max_y_tmp;
int i;
int rc;
pt_debug(dev, DL_INFO, "%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 & PT_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 & PT_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 != PT_IGNORE_VALUE) {
__set_bit(signal, md->input->absbit);
min = MT_PARAM_MIN(md, i);
max = MT_PARAM_MAX(md, i);
if (i == PT_ABS_ID_OST) {
/* shift track ids down to start at 0 */
max = max - min;
min = min - min;
} else if (i == PT_ABS_X_OST)
max = max_x;
else if (i == PT_ABS_Y_OST)
max = max_y;
else if (i == PT_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));
pt_debug(dev, DL_INFO,
"%s: register signal=%02X min=%d max=%d\n",
__func__, signal, min, max);
}
}
md->or_min = MT_PARAM_MIN(md, PT_ABS_OR_OST);
md->or_max = MT_PARAM_MAX(md, PT_ABS_OR_OST);
md->t_min = MT_PARAM_MIN(md, PT_ABS_ID_OST);
md->t_max = MT_PARAM_MAX(md, PT_ABS_ID_OST);
rc = md->mt_function.input_register_device(md->input,
md->si->tch_abs[PT_TCH_T].max);
if (rc < 0)
pt_debug(dev, DL_ERROR, "%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;
}
/*******************************************************************************
* FUNCTION: pt_setup_input_attention
*
* SUMMARY: Wrapper function for pt_setup_input_device() register to TTDL
* attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_setup_input_attention(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
int rc;
md->si = _pt_request_sysinfo(dev);
if (!md->si)
return -EINVAL;
rc = pt_setup_input_device(dev);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP, PT_MT_NAME,
pt_setup_input_attention, 0);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_mt_probe
*
* SUMMARY: The probe function for touch input device
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
int pt_mt_probe(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_mt_data *md = &cd->md;
struct pt_platform_data *pdata = dev_get_platdata(dev);
struct pt_mt_platform_data *mt_pdata;
int rc = 0;
pt_debug(dev, DL_INFO,
"%s: >>>>>> Register MT <<<<<<\n", __func__);
if (!pdata || !pdata->mt_pdata) {
pt_debug(dev, DL_ERROR,
"%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
mt_pdata = pdata->mt_pdata;
pt_init_function_ptrs(md);
mutex_init(&md->mt_lock);
md->dev = dev;
md->pdata = mt_pdata;
/* Create the input device and register it. */
pt_debug(dev, DL_INFO,
"%s: Create the input device and register it\n", __func__);
md->input = input_allocate_device();
if (!md->input) {
pt_debug(dev, DL_ERROR, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
} else
md->input_device_allocated = true;
if (md->pdata->inp_dev_name)
md->input->name = md->pdata->inp_dev_name;
else
md->input->name = PT_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 = pt_mt_open;
md->input->close = pt_mt_close;
input_set_drvdata(md->input, md);
/* get sysinfo */
md->si = _pt_request_sysinfo(dev);
if (md->si) {
rc = pt_setup_input_device(dev);
if (rc)
goto error_init_input;
} else {
pt_debug(dev, DL_ERROR, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, md->si);
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
PT_MT_NAME, pt_setup_input_attention, 0);
}
return 0;
error_init_input:
input_free_device(md->input);
md->input_device_allocated = false;
error_alloc_failed:
error_no_pdata:
pt_debug(dev, DL_ERROR, "%s failed.\n", __func__);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_mt_release
*
* SUMMARY: The release function for touch input device
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
int pt_mt_release(struct device *dev)
{
struct pt_core_data *cd;
struct pt_mt_data *md;
/* Ensure valid pointers before de-referencing them */
if (dev) {
cd = dev_get_drvdata(dev);
if (cd)
md = &cd->md;
else
return 0;
} else {
return 0;
}
/*
* Second call this function may cause kernel panic if probe fail.
* Use input_device_registered & input_device_allocated variable to
* avoid unregister or free unavailable devive.
*/
if (md && md->input_device_registered) {
md->input_device_registered = false;
input_unregister_device(md->input);
/* Unregistering device will free the device too */
md->input_device_allocated = false;
} else if (md && md->input_device_allocated) {
md->input_device_allocated = false;
input_free_device(md->input);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
PT_MT_NAME, pt_setup_input_attention, 0);
}
return 0;
}

View File

@ -0,0 +1,143 @@
/*
* pt_mta.c
* Parade TrueTouch(TM) Standard Product Multi-Touch Protocol A Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
/*******************************************************************************
* FUNCTION: pt_final_sync
*
* SUMMARY: Function to create SYN_REPORT
*
* PARAMETERS:
* *input - pointer to input device structure
* max_slots - max support touch number
* mt_sync_count - current valid touch number
* ids - bit map value
******************************************************************************/
static void pt_final_sync(struct input_dev *input, int max_slots,
int mt_sync_count, unsigned long *ids)
{
if (mt_sync_count)
input_sync(input);
}
/*******************************************************************************
* FUNCTION: pt_input_sync
*
* SUMMARY: Function to create SYN_MT_REPORT
*
* PARAMETERS:
* *input - pointer to input device structure
******************************************************************************/
static void pt_input_sync(struct input_dev *input)
{
input_mt_sync(input);
}
/*******************************************************************************
* FUNCTION: pt_input_report
*
* SUMMARY: Function to report coordinate information of touch point
* protocol
*
* PARAMETERS:
* *input - pointer to input device structure
* sig - track id to allow tracking of a touch
* t - event id to indicate an event associated with touch instance
* type - indicate the touch object
******************************************************************************/
static void pt_input_report(struct input_dev *input, int sig,
int t, int type)
{
if (type == PT_OBJ_STANDARD_FINGER || type == PT_OBJ_GLOVE) {
input_report_key(input, BTN_TOOL_FINGER, PT_BTN_PRESSED);
input_report_key(input, BTN_TOOL_PEN, PT_BTN_RELEASED);
} else if (type == PT_OBJ_STYLUS) {
input_report_key(input, BTN_TOOL_PEN, PT_BTN_PRESSED);
input_report_key(input, BTN_TOOL_FINGER, PT_BTN_RELEASED);
}
input_report_key(input, BTN_TOUCH, PT_BTN_PRESSED);
input_report_abs(input, sig, t);
}
/*******************************************************************************
* FUNCTION: pt_report_slot_liftoff
*
* SUMMARY: Function to report all touches are lifted
* protocol
*
* PARAMETERS:
* *md - pointer to input device structure
* max_slots - indicate max number of touch id
******************************************************************************/
static void pt_report_slot_liftoff(struct pt_mt_data *md,
int max_slots)
{
input_report_key(md->input, BTN_TOUCH, PT_BTN_RELEASED);
input_report_key(md->input, BTN_TOOL_FINGER, PT_BTN_RELEASED);
input_report_key(md->input, BTN_TOOL_PEN, PT_BTN_RELEASED);
}
/*******************************************************************************
* FUNCTION: pt_input_register_device
*
* SUMMARY: Function to register input device
* protocol
*
* PARAMETERS:
* *input - pointer to input device structure
* max_slots - indicate max number of touch id
******************************************************************************/
static int pt_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);
}
/*******************************************************************************
* FUNCTION: pt_init_function_ptrs
*
* SUMMARY: Function to init function pointer
*
* PARAMETERS:
* *md - pointer to touch data structure
******************************************************************************/
void pt_init_function_ptrs(struct pt_mt_data *md)
{
md->mt_function.report_slot_liftoff = pt_report_slot_liftoff;
md->mt_function.final_sync = pt_final_sync;
md->mt_function.input_sync = pt_input_sync;
md->mt_function.input_report = pt_input_report;
md->mt_function.input_register_device = pt_input_register_device;
}

View File

@ -0,0 +1,144 @@
/*
* pt_mtb.c
* Parade TrueTouch(TM) Standard Product Multi-Touch Protocol B Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
#include <linux/input/mt.h>
#include <linux/version.h>
/*******************************************************************************
* FUNCTION: pt_final_sync
*
* SUMMARY: Function to create SYN_REPORT
*
* PARAMETERS:
* *input - pointer to input device structure
* max_slots - max support touch number
* mt_sync_count - current valid touch number
* ids - bit map value
******************************************************************************/
static void pt_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);
}
/*******************************************************************************
* FUNCTION: pt_input_report
*
* SUMMARY: Function to report coordinate information of touch point
* protocol
*
* PARAMETERS:
* *input - pointer to input device structure
* sig - track id to allow tracking of a touch
* t - event id to indicate an event associated with touch instance
* type - indicate the touch object
******************************************************************************/
static void pt_input_report(struct input_dev *input, int sig,
int t, int type)
{
input_mt_slot(input, t);
if (type == PT_OBJ_STANDARD_FINGER || type == PT_OBJ_GLOVE)
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
else if (type == PT_OBJ_STYLUS)
input_mt_report_slot_state(input, MT_TOOL_PEN, true);
}
/*******************************************************************************
* FUNCTION: pt_report_slot_liftoff
*
* SUMMARY: Function to report all touches are lifted
* protocol
*
* PARAMETERS:
* *md - pointer to input device structure
* max_slots - indicate max number of touch id
******************************************************************************/
static void pt_report_slot_liftoff(struct pt_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);
}
}
/*******************************************************************************
* FUNCTION: pt_input_register_device
*
* SUMMARY: Function to register input device
* protocol
*
* PARAMETERS:
* *input - pointer to input device structure
* max_slots - indicate max number of touch id
******************************************************************************/
static int pt_input_register_device(struct input_dev *input, int max_slots)
{
#if (KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE)
input_mt_init_slots(input, max_slots, 0);
#else
input_mt_init_slots(input, max_slots);
#endif
return input_register_device(input);
}
/*******************************************************************************
* FUNCTION: pt_init_function_ptrs
*
* SUMMARY: Function to init function pointer
*
* PARAMETERS:
* *md - pointer to touch data structure
******************************************************************************/
void pt_init_function_ptrs(struct pt_mt_data *md)
{
md->mt_function.report_slot_liftoff = pt_report_slot_liftoff;
md->mt_function.final_sync = pt_final_sync;
md->mt_function.input_sync = NULL;
md->mt_function.input_report = pt_input_report;
md->mt_function.input_register_device = pt_input_register_device;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,815 @@
/*
* pt_proximity.c
* Parade TrueTouch(TM) Standard Product Proximity Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
#define PT_PROXIMITY_NAME "pt_proximity"
/* Timeout value in ms. */
#define PT_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT 1000
#define PT_PROXIMITY_ON 0
#define PT_PROXIMITY_OFF 1
/*******************************************************************************
* FUNCTION: get_prox_data
*
* SUMMARY: Gets pointer of proximity data from core data structure
*
* RETURN:
* pointer of pt_proximity_data structure in core data structure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static inline struct pt_proximity_data *get_prox_data(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
return &cd->pd;
}
/*******************************************************************************
* FUNCTION: pt_report_proximity
*
* SUMMARY: Reports proximity event
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* on - state of proximity(true:on; false:off)
******************************************************************************/
static void pt_report_proximity(struct pt_proximity_data *pd,
bool on)
{
int val = on ? PT_PROXIMITY_ON : PT_PROXIMITY_OFF;
input_report_abs(pd->input, ABS_DISTANCE, val);
input_sync(pd->input);
}
/*******************************************************************************
* FUNCTION: pt_get_touch_axis
*
* SUMMARY: Calculates touch axis
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* *axis - pointer to axis calculation result
* size - size in bytes
* max - max value of result
* *xy_data - pointer to input data to be parsed
* bofs - bit offset
******************************************************************************/
static void pt_get_touch_axis(struct pt_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++) {
pt_debug(pd->dev, DL_INFO,
"%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;
pt_debug(pd->dev, DL_INFO,
"%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]);
}
/*******************************************************************************
* FUNCTION: pt_get_touch_hdr
*
* SUMMARY: Gets header of touch report
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* *touch - pointer to pt_touch structure
* *xy_mode - pointer to input mode data
******************************************************************************/
static void pt_get_touch_hdr(struct pt_proximity_data *pd,
struct pt_touch *touch, u8 *xy_mode)
{
struct device *dev = pd->dev;
struct pt_sysinfo *si = pd->si;
enum pt_tch_hdr hdr;
for (hdr = PT_TCH_TIME; hdr < PT_TCH_NUM_HDR; hdr++) {
if (!si->tch_hdr[hdr].report)
continue;
pt_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);
pt_debug(dev, DL_INFO, "%s: get %s=%04X(%d)\n",
__func__, pt_tch_hdr_string[hdr],
touch->hdr[hdr], touch->hdr[hdr]);
}
}
/*******************************************************************************
* FUNCTION: pt_get_touch
*
* SUMMARY: Parse proximity touch event
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* *touch - pointer to touch structure
* xy_data - pointer to touch data
******************************************************************************/
static void pt_get_touch(struct pt_proximity_data *pd,
struct pt_touch *touch, u8 *xy_data)
{
struct device *dev = pd->dev;
struct pt_sysinfo *si = pd->si;
enum pt_tch_abs abs;
for (abs = PT_TCH_X; abs < PT_TCH_NUM_ABS; abs++) {
if (!si->tch_abs[abs].report)
continue;
pt_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);
pt_debug(dev, DL_INFO, "%s: get %s=%04X(%d)\n",
__func__, pt_tch_abs_string[abs],
touch->abs[abs], touch->abs[abs]);
}
pt_debug(dev, DL_INFO, "%s: x=%04X(%d) y=%04X(%d)\n",
__func__, touch->abs[PT_TCH_X], touch->abs[PT_TCH_X],
touch->abs[PT_TCH_Y], touch->abs[PT_TCH_Y]);
}
/*******************************************************************************
* FUNCTION: pt_get_proximity_touch
*
* SUMMARY: Parse and report proximity touch event
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* *touch - pointer to pt_touch structure
******************************************************************************/
static void pt_get_proximity_touch(struct pt_proximity_data *pd,
struct pt_touch *tch, int num_cur_tch)
{
struct pt_sysinfo *si = pd->si;
int i;
for (i = 0; i < num_cur_tch; i++) {
pt_get_touch(pd, tch, si->xy_data +
(i * si->desc.tch_record_size));
/* Check for proximity event */
if (tch->abs[PT_TCH_O] == PT_OBJ_PROXIMITY) {
if (tch->abs[PT_TCH_E] == PT_EV_TOUCHDOWN)
pt_report_proximity(pd, true);
else if (tch->abs[PT_TCH_E] == PT_EV_LIFTOFF)
pt_report_proximity(pd, false);
break;
}
}
}
/*******************************************************************************
* FUNCTION: pt_xy_worker
*
* SUMMARY: Read xy_data for all current touches
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pd - pointer to proximity data structure
******************************************************************************/
static int pt_xy_worker(struct pt_proximity_data *pd)
{
struct device *dev = pd->dev;
struct pt_sysinfo *si = pd->si;
struct pt_touch tch;
u8 num_cur_tch;
pt_get_touch_hdr(pd, &tch, si->xy_mode + 3);
num_cur_tch = tch.hdr[PT_TCH_NUM];
if (num_cur_tch > si->sensing_conf_data.max_tch) {
pt_debug(dev, DL_ERROR, "%s: Num touch err detected (n=%d)\n",
__func__, num_cur_tch);
num_cur_tch = si->sensing_conf_data.max_tch;
}
if (tch.hdr[PT_TCH_LO])
pt_debug(dev, DL_WARN, "%s: Large area detected\n",
__func__);
/* extract xy_data for all currently reported touches */
pt_debug(dev, DL_INFO, "%s: extract data num_cur_rec=%d\n",
__func__, num_cur_tch);
if (num_cur_tch)
pt_get_proximity_touch(pd, &tch, num_cur_tch);
else
pt_report_proximity(pd, false);
return 0;
}
/*******************************************************************************
* FUNCTION: pt_mt_attention
*
* SUMMARY: Wrapper function for pt_xy_worker() that subscribe into the TTDL
* attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_proximity_attention(struct device *dev)
{
struct pt_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 = pt_xy_worker(pd);
mutex_unlock(&pd->prox_lock);
if (rc < 0)
pt_debug(dev, DL_ERROR, "%s: xy_worker error r=%d\n",
__func__, rc);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_startup_attention
*
* SUMMARY: Wrapper function for pt_report_proximity() that subcribe into the
* TTDL attention list.
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_startup_attention(struct device *dev)
{
struct pt_proximity_data *pd = get_prox_data(dev);
mutex_lock(&pd->prox_lock);
pt_report_proximity(pd, false);
mutex_unlock(&pd->prox_lock);
return 0;
}
/*******************************************************************************
* FUNCTION: _pt_set_proximity_via_touchmode_enabled
*
* SUMMARY: Enable/Disable proximity via touchmode parameter
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* enable - enable or disable proximity(true:enable; false:disable)
******************************************************************************/
static int _pt_set_proximity_via_touchmode_enabled(
struct pt_proximity_data *pd, bool enable)
{
struct device *dev = pd->dev;
u32 touchmode_enabled;
int rc;
rc = _pt_request_pip_get_param(dev, 0,
PT_RAM_ID_TOUCHMODE_ENABLED, &touchmode_enabled);
if (rc)
return rc;
if (enable)
touchmode_enabled |= 0x80;
else
touchmode_enabled &= 0x7F;
rc = _pt_request_pip_set_param(dev, 0,
PT_RAM_ID_TOUCHMODE_ENABLED, touchmode_enabled,
PT_RAM_ID_TOUCHMODE_ENABLED_SIZE);
return rc;
}
/*******************************************************************************
* FUNCTION: _pt_set_proximity_via_proximity_enable
*
* SUMMARY: Enable/Disable proximity via proximity parameter
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* enable - enable or disable proximity(true:enable; false:disable)
******************************************************************************/
static int _pt_set_proximity_via_proximity_enable(
struct pt_proximity_data *pd, bool enable)
{
struct device *dev = pd->dev;
u32 proximity_enable;
int rc;
rc = _pt_request_pip_get_param(dev, 0,
PT_RAM_ID_PROXIMITY_ENABLE, &proximity_enable);
if (rc)
return rc;
if (enable)
proximity_enable |= 0x01;
else
proximity_enable &= 0xFE;
rc = _pt_request_pip_set_param(dev, 0,
PT_RAM_ID_PROXIMITY_ENABLE, proximity_enable,
PT_RAM_ID_PROXIMITY_ENABLE_SIZE);
return rc;
}
/*******************************************************************************
* FUNCTION: _pt_set_proximity
*
* SUMMARY: Set proximity mode via touchmode parameter or proximity parameter.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pd - pointer to proximity data structure
* enable - enable or disable proximity(true:enable; false:disable)
******************************************************************************/
static int _pt_set_proximity(struct pt_proximity_data *pd,
bool enable)
{
if (!IS_PIP_VER_GE(pd->si, 1, 4))
return _pt_set_proximity_via_touchmode_enabled(pd,
enable);
return _pt_set_proximity_via_proximity_enable(pd, enable);
}
/*******************************************************************************
* FUNCTION: _pt_set_proximity
*
* SUMMARY: Enable proximity mode and subscribe into IRQ and STARTUP TTDL
* attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pd - pointer to proximity data structure
******************************************************************************/
static int _pt_proximity_enable(struct pt_proximity_data *pd)
{
struct device *dev = pd->dev;
int rc = 0;
pm_runtime_get_sync(dev);
rc = pt_request_exclusive(dev,
PT_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Error on request exclusive r=%d\n",
__func__, rc);
goto exit;
}
rc = _pt_set_proximity(pd, true);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Error on request enable proximity scantype r=%d\n",
__func__, rc);
goto exit_release;
}
pt_debug(dev, DL_INFO, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_pt_subscribe_attention(dev, PT_ATTEN_IRQ, PT_PROXIMITY_NAME,
pt_proximity_attention, PT_MODE_OPERATIONAL);
/* set up startup call back */
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
PT_PROXIMITY_NAME, pt_startup_attention, 0);
exit_release:
pt_release_exclusive(dev);
exit:
return rc;
}
/*******************************************************************************
* FUNCTION: _pt_proximity_disable
*
* SUMMARY: Disable proximity mode and unsubscribe from IRQ and STARTUP TTDL
* attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pd - pointer to proximity data structure
******************************************************************************/
static int _pt_proximity_disable(struct pt_proximity_data *pd,
bool force)
{
struct device *dev = pd->dev;
int rc = 0;
rc = pt_request_exclusive(dev,
PT_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Error on request exclusive r=%d\n",
__func__, rc);
goto exit;
}
rc = _pt_set_proximity(pd, false);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: Error on request disable proximity scan r=%d\n",
__func__, rc);
goto exit_release;
}
exit_release:
pt_release_exclusive(dev);
exit:
if (!rc || force) {
_pt_unsubscribe_attention(dev, PT_ATTEN_IRQ,
PT_PROXIMITY_NAME, pt_proximity_attention,
PT_MODE_OPERATIONAL);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
PT_PROXIMITY_NAME, pt_startup_attention, 0);
}
pm_runtime_put(dev);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_proximity_enable_show
*
* SUMMARY: Show method for the prox_enable sysfs node that will show the
* enable_count of proximity
*
* RETURN: Size of printed buffer
*
* PARAMETERS:
* *dev - pointer to device structure
* *attr - pointer to device attributes
* *buf - pointer to output buffer
******************************************************************************/
static ssize_t pt_proximity_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pt_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, PT_MAX_PRBUF_SIZE, "%d\n", val);
}
/*******************************************************************************
* FUNCTION: pt_proximity_enable_store
*
* SUMMARY: The store method for the prox_enable sysfs node that allows to
* enable or disable proxmity mode.
*
* RETURN: Size of passed in buffer
*
* PARAMETERS:
* *dev - pointer to device structure
* *attr - pointer to device attributes
* *buf - pointer to buffer that hold the command parameters
* size - size of buf
******************************************************************************/
static ssize_t pt_proximity_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct pt_proximity_data *pd = get_prox_data(dev);
unsigned long value;
int rc;
rc = kstrtoul(buf, 10, &value);
if (rc < 0 || (value != 0 && value != 1)) {
pt_debug(dev, DL_ERROR, "%s: Invalid value\n", __func__);
return -EINVAL;
}
mutex_lock(&pd->sysfs_lock);
if (value) {
if (pd->enable_count++) {
pt_debug(dev, DL_WARN, "%s: '%s' already enabled\n",
__func__, pd->input->name);
} else {
rc = _pt_proximity_enable(pd);
if (rc)
pd->enable_count--;
}
} else {
if (--pd->enable_count) {
if (pd->enable_count < 0) {
pt_debug(dev, DL_ERROR, "%s: '%s' unbalanced disable\n",
__func__, pd->input->name);
pd->enable_count = 0;
}
} else {
rc = _pt_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, 0600,
pt_proximity_enable_show,
pt_proximity_enable_store);
/*******************************************************************************
* FUNCTION: pt_setup_input_device_and_sysfs
*
* SUMMARY: Create sysnode, set event signal capabilities and register input
* device for proximity.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_setup_input_device_and_sysfs(struct device *dev)
{
struct pt_proximity_data *pd = get_prox_data(dev);
int signal = PT_IGNORE_VALUE;
int i;
int rc;
rc = device_create_file(dev, &dev_attr_prox_enable);
if (rc) {
pt_debug(dev, DL_ERROR, "%s: Error, could not create enable\n",
__func__);
goto exit;
}
pt_debug(dev, DL_INFO, "%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 != PT_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) {
pt_debug(dev, DL_ERROR, "%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;
}
/*******************************************************************************
* FUNCTION: pt_setup_input_attention
*
* SUMMARY: Wrapper function for pt_setup_input_device_and_sysfs() that
* subscribe into TTDL attention list.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
static int pt_setup_input_attention(struct device *dev)
{
struct pt_proximity_data *pd = get_prox_data(dev);
int rc;
pd->si = _pt_request_sysinfo(dev);
if (!pd->si)
return -EINVAL;
rc = pt_setup_input_device_and_sysfs(dev);
if (!rc)
rc = _pt_set_proximity(pd, false);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
PT_PROXIMITY_NAME, pt_setup_input_attention, 0);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_proximity_probe
*
* SUMMARY: The probe function for proximity input device
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
int pt_proximity_probe(struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
struct pt_proximity_data *pd = &cd->pd;
struct pt_platform_data *pdata = dev_get_platdata(dev);
struct pt_proximity_platform_data *prox_pdata;
int rc = 0;
if (!pdata || !pdata->prox_pdata) {
pt_debug(dev, DL_ERROR,
"%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. */
pt_debug(dev, DL_INFO,
"%s: Create the input device and register it\n", __func__);
pd->input = input_allocate_device();
if (!pd->input) {
pt_debug(dev, DL_ERROR, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
} else
pd->input_device_allocated = true;
if (pd->pdata->inp_dev_name)
pd->input->name = pd->pdata->inp_dev_name;
else
pd->input->name = PT_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 = _pt_request_sysinfo(dev);
if (pd->si) {
rc = pt_setup_input_device_and_sysfs(dev);
if (rc)
goto error_init_input;
rc = _pt_set_proximity(pd, false);
} else {
pt_debug(dev, DL_ERROR, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, pd->si);
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
PT_PROXIMITY_NAME, pt_setup_input_attention,
0);
}
return 0;
error_init_input:
input_free_device(pd->input);
pd->input_device_allocated = false;
error_alloc_failed:
error_no_pdata:
pt_debug(dev, DL_ERROR, "%s failed.\n", __func__);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_proximity_release
*
* SUMMARY: The release function for proximity input device
*
* RETURN:
* 0 = success
*
* PARAMETERS:
* *dev - pointer to device structure
******************************************************************************/
int pt_proximity_release(struct device *dev)
{
struct pt_proximity_data *pd;
/* Ensure valid pointers before de-referencing them */
if (dev)
pd = get_prox_data(dev);
else
return 0;
/*
* Second call this function may cause kernel panic if probe fail.
* Use input_device_registered & input_device_allocated variable to
* avoid unregister or free unavailable devive.
*/
if (pd && pd->input_device_registered) {
/* Disable proximity sensing */
pd->input_device_registered = false;
mutex_lock(&pd->sysfs_lock);
if (pd->enable_count)
_pt_proximity_disable(pd, true);
mutex_unlock(&pd->sysfs_lock);
device_remove_file(dev, &dev_attr_prox_enable);
input_unregister_device(pd->input);
/* Unregistering device will free the device too */
pd->input_device_allocated = false;
} else if (pd && pd->input_device_allocated) {
pd->input_device_allocated = false;
input_free_device(pd->input);
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
PT_PROXIMITY_NAME, pt_setup_input_attention,
0);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,429 @@
/*
* pt_spi.c
* Parade TrueTouch(TM) Standard Product SPI Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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 "pt_regs.h"
#include <linux/spi/spi.h>
#include <linux/version.h>
/* TC3315 - DUT Address (0x24 & 0x07) << 1 = 0x08 for write and 0x09 for read */
#define PT_SPI_WR_OP 0x08 /* r/~w */
#define PT_SPI_RD_OP 0x09
#define PT_SPI_BITS_PER_WORD 8
#define PT_SPI_SYNC_ACK 0x62
#define PT_SPI_CMD_BYTES 0
#define PT_SPI_DATA_SIZE (2 * 256)
#define PT_SPI_DATA_BUF_SIZE (PT_SPI_CMD_BYTES + PT_SPI_DATA_SIZE)
#define PT_SPI_OP_SIZE (1)
#define PT_SPI_DUMMY_READ (1)
#define PT_SPI_BUFFER_SIZE \
(PT_MAX_PIP2_MSG_SIZE + PT_SPI_OP_SIZE + PT_SPI_DUMMY_READ)
static u8 *tmp_rbuf;
static u8 *tmp_wbuf;
DEFINE_MUTEX(pt_spi_bus_lock);
/*******************************************************************************
* FUNCTION: pt_spi_xfer
*
* SUMMARY: Read or write date for SPI device.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to device structure
* op - flag to write or read data
* *buf - pointer to data buffer
* length - data length
******************************************************************************/
static int pt_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;
int rc;
memset(&xfer, 0, sizeof(xfer));
spi_message_init(&msg);
switch (op) {
case PT_SPI_RD_OP:
/* Clear tmp_wbuf with additional OP Code and dummy byte */
memset(tmp_wbuf, 0, length + 2);
tmp_wbuf[0] = op;
/* Total read/write = Read length + Op code + dummy byte */
xfer.tx_buf = tmp_wbuf;
xfer.rx_buf = tmp_rbuf;
xfer.len = length + 2;
break;
case PT_SPI_WR_OP:
memcpy(&tmp_wbuf[1], buf, length);
tmp_wbuf[0] = op;
/* Write length + size of Op code */
xfer.tx_buf = tmp_wbuf;
xfer.len = length + 1;
break;
default:
rc = -EIO;
goto exit;
}
spi_message_add_tail(&xfer, &msg);
rc = spi_sync(spi, &msg);
/* On reads copy only the data content back into the passed in buf */
if (op == PT_SPI_RD_OP)
memcpy(buf, &tmp_rbuf[2], length);
exit:
if (rc < 0)
pt_debug(dev, DL_ERROR, "%s: spi_sync() error %d\n",
__func__, rc);
#if 0 /* TODO TC3315 - need to verify the ACK byte */
if (tmp_rbuf[0] != PT_SPI_SYNC_ACK) {
pt_debug(dev, DL_ERROR, "%s: r_header = 0x%02X\n", __func__,
r_header[0]);
return -EIO;
}
#endif
return rc;
}
/*******************************************************************************
* FUNCTION: pt_spi_read_default
*
* SUMMARY: Read a certain number of bytes from the SPI bus
* NOTE: For TC3315 every response includes a "dummy" prefix byte that
* needs to be stipped off before returning buf.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to Device structure
* *buf - pointer to buffer where the data read will be stored
* size - size to be read
******************************************************************************/
static int pt_spi_read_default(struct device *dev, void *buf, int size)
{
int rc = 0;
if (!buf || !size || size > PT_MAX_PIP2_MSG_SIZE)
return -EINVAL;
mutex_lock(&pt_spi_bus_lock);
rc = pt_spi_xfer(dev, PT_SPI_RD_OP, buf, size);
mutex_unlock(&pt_spi_bus_lock);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_spi_read_default_nosize
*
* SUMMARY: Read from the SPI bus in two transactions first reading the HID
* packet size (2 bytes) followed by reading the rest of the packet based
* on the size initially read.
* NOTE: The empty buffer 'size' was redefined in PIP version 1.7.
* NOTE: For TC3315 every response includes a "dummy" prefix byte that
* needs to be stipped off before returning buf.
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to Device structure
* *buf - pointer to buffer where the data read will be stored
* max - max size that can be read
******************************************************************************/
static int pt_spi_read_default_nosize(struct device *dev, u8 *buf, u32 max)
{
u32 size;
int rc = 0;
if (!buf)
return 0;
mutex_lock(&pt_spi_bus_lock);
/* Separate transaction to retrieve only the length to read */
rc = pt_spi_xfer(dev, PT_SPI_RD_OP, buf, 2);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: SPI transfer error rc = %d\n",
__func__, rc);
goto exit;
}
size = get_unaligned_le16(&buf[0]);
if (!size || size == 2 || size >= PT_PIP_1P7_EMPTY_BUF)
goto exit;
if (size > max || size > PT_MAX_PIP2_MSG_SIZE) {
pt_debug(dev, DL_ERROR, "%s: Invalid size %d !\n", __func__,
size);
rc = -EINVAL;
goto exit;
}
rc = pt_spi_xfer(dev, PT_SPI_RD_OP, buf, size);
if (rc)
pt_debug(dev, DL_ERROR, "%s: SPI transfer error rc = %d\n",
__func__, rc);
exit:
mutex_unlock(&pt_spi_bus_lock);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_spi_write_read_specific
*
* SUMMARY: Write the contents of write_buf to the SPI device and then read
* the response using pt_spi_read_default_nosize()
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *dev - pointer to Device structure
* write_len - length of data buffer write_buf
* *write_buf - pointer to buffer to write
* *read_buf - pointer to buffer to read response into
******************************************************************************/
static int pt_spi_write_read_specific(struct device *dev, u16 write_len,
u8 *write_buf, u8 *read_buf)
{
int rc = 0;
/* Ensure no packet larger than what the PIP spec allows */
if (write_len > PT_MAX_PIP2_MSG_SIZE)
return -EINVAL;
if (!write_buf || !write_len) {
if (!write_buf)
pt_debug(dev, DL_ERROR,
"%s write_buf is NULL", __func__);
if (!write_len)
pt_debug(dev, DL_ERROR,
"%s write_len is NULL", __func__);
return -EINVAL;
}
mutex_lock(&pt_spi_bus_lock);
rc = pt_spi_xfer(dev, PT_SPI_WR_OP, write_buf, write_len);
if (rc < 0)
goto error;
mutex_unlock(&pt_spi_bus_lock);
if (read_buf)
rc = pt_spi_read_default_nosize(dev, read_buf,
PT_SPI_DATA_SIZE);
return rc;
error:
mutex_unlock(&pt_spi_bus_lock);
return rc;
}
static struct pt_bus_ops pt_spi_bus_ops = {
.bustype = BUS_SPI,
.read_default = pt_spi_read_default,
.read_default_nosize = pt_spi_read_default_nosize,
.write_read_specific = pt_spi_write_read_specific,
};
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
static const struct of_device_id pt_spi_of_match[] = {
{ .compatible = "parade,pt_spi_adapter", },
{ }
};
MODULE_DEVICE_TABLE(of, pt_spi_of_match);
#endif
/*******************************************************************************
* FUNCTION: pt_spi_probe
*
* SUMMARY: Probe functon for the SPI module
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *spi - pointer to spi device structure
******************************************************************************/
static int pt_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
int rc;
/* Set up SPI*/
spi->bits_per_word = PT_SPI_BITS_PER_WORD;
spi->mode = SPI_MODE_0;
rc = spi_setup(spi);
if (rc < 0) {
pt_debug(dev, DL_ERROR, "%s: SPI setup error %d\n",
__func__, rc);
return rc;
}
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(pt_spi_of_match), dev);
if (match) {
rc = pt_devtree_create_and_get_pdata(dev);
if (rc < 0)
return rc;
}
#endif
/* Add 2 to the length for the 'OP Code' & 'Dummy' prefix bytes */
tmp_wbuf = kzalloc(PT_SPI_BUFFER_SIZE, GFP_KERNEL);
tmp_rbuf = kzalloc(PT_SPI_BUFFER_SIZE, GFP_KERNEL);
if (!tmp_wbuf || !tmp_rbuf)
return -ENOMEM;
rc = pt_probe(&pt_spi_bus_ops, &spi->dev, spi->irq,
PT_SPI_DATA_BUF_SIZE);
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
if (rc && match)
pt_devtree_clean_pdata(dev);
#endif
return rc;
}
/*******************************************************************************
* FUNCTION: pt_spi_remove
*
* SUMMARY: Remove functon for the SPI module
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *spi - pointer to spi device structure
******************************************************************************/
static int pt_spi_remove(struct spi_device *spi)
{
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
struct device *dev = &spi->dev;
struct pt_core_data *cd = dev_get_drvdata(dev);
kfree(tmp_rbuf);
kfree(tmp_wbuf);
pt_release(cd);
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(pt_spi_of_match), dev);
if (match)
pt_devtree_clean_pdata(dev);
#endif
return 0;
}
static const struct spi_device_id pt_spi_id[] = {
{ PT_SPI_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, pt_spi_id);
static struct spi_driver pt_spi_driver = {
.driver = {
.name = PT_SPI_NAME,
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &pt_pm_ops,
#ifdef CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT
.of_match_table = pt_spi_of_match,
#endif
},
.probe = pt_spi_probe,
.remove = (pt_spi_remove),
.id_table = pt_spi_id,
};
#if (KERNEL_VERSION(3, 3, 0) <= LINUX_VERSION_CODE)
module_spi_driver(pt_spi_driver);
#else
/*******************************************************************************
* FUNCTION: pt_spi_init
*
* SUMMARY: Initialize function to register spi module to kernel.
*
* RETURN:
* 0 = success
* !0 = failure
******************************************************************************/
static int __init pt_spi_init(void)
{
int err = spi_register_driver(&pt_spi_driver);
pr_info("%s: Parade TTDL SPI Driver (Build %s) rc=%d\n",
__func__, PT_DRIVER_VERSION, err);
return err;
}
module_init(pt_spi_init);
/*******************************************************************************
* FUNCTION: pt_spi_exit
*
* SUMMARY: Exit function to unregister spi module from kernel.
*
******************************************************************************/
static void __exit pt_spi_exit(void)
{
spi_unregister_driver(&pt_spi_driver);
}
module_exit(pt_spi_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product SPI Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View File

@ -0,0 +1,219 @@
/*
* pt_core.h
* Parade TrueTouch(TM) Standard Product Core Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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.parade.com <ttdrivers@paradetech.com>
*/
#ifndef _LINUX_PT_CORE_H
#define _LINUX_PT_CORE_H
#include <linux/stringify.h>
#define PT_I2C_NAME "pt_i2c_adapter"
#define PT_SPI_NAME "pt_spi_adapter"
#define PT_CORE_NAME "pt_core"
#define PT_MT_NAME "pt_mt"
#define PT_BTN_NAME "pt_btn"
#define PT_PROXIMITY_NAME "pt_proximity"
#define PT_DRIVER_NAME TTDL
#define PT_DRIVER_MAJOR 04
#define PT_DRIVER_MINOR 11
#define PT_DRIVER_REVCTRL 977092
#define PT_DRIVER_VERSION \
__stringify(PT_DRIVER_NAME) \
"." __stringify(PT_DRIVER_MAJOR) \
"." __stringify(PT_DRIVER_MINOR) \
"." __stringify(PT_DRIVER_REVCTRL)
#define PT_DRIVER_DATE "20201210"
/* abs settings */
#define PT_IGNORE_VALUE -1
enum pt_core_platform_flags {
PT_CORE_FLAG_NONE,
PT_CORE_FLAG_POWEROFF_ON_SLEEP = 0x02,
PT_CORE_FLAG_RESTORE_PARAMETERS = 0x04,
PT_CORE_FLAG_DEEP_STANDBY = 0x08,
PT_CORE_FLAG_SKIP_SYS_SLEEP = 0x10,
PT_CORE_FLAG_SKIP_RUNTIME = 0x20,
PT_CORE_FLAG_SKIP_RESUME = 0x40,
};
enum pt_core_platform_easy_wakeup_gesture {
PT_CORE_EWG_NONE,
PT_CORE_EWG_TAP_TAP,
PT_CORE_EWG_TWO_FINGER_SLIDE,
PT_CORE_EWG_RESERVED,
PT_CORE_EWG_WAKE_ON_INT_FROM_HOST = 0xFF,
};
enum pt_loader_platform_flags {
PT_LOADER_FLAG_NONE,
PT_LOADER_FLAG_CALIBRATE_AFTER_FW_UPGRADE,
/* Use CONFIG_VER field in TT_CFG to decide TT_CFG update */
PT_LOADER_FLAG_CHECK_TTCONFIG_VERSION,
PT_LOADER_FLAG_CALIBRATE_AFTER_TTCONFIG_UPGRADE,
};
enum CONFIG_DUT_GENERATION {
CONFIG_DUT_AUTO_DETECT = 0x00,
CONFIG_DUT_PIP1_ONLY = 0x01,
CONFIG_DUT_PIP2_CAPABLE = 0x02,
};
enum pt_core_platform_panel_id_flags {
PT_PANEL_ID_DISABLE = 0x00,
PT_PANEL_ID_BY_BL = 0x01,
PT_PANEL_ID_BY_SYS_INFO = 0x02,
PT_PANEL_ID_BY_MFG_DATA = 0x04,
};
struct touch_settings {
const uint8_t *data;
uint32_t size;
uint8_t tag;
};
struct pt_touch_firmware {
const uint8_t *img;
uint32_t size;
const uint8_t *ver;
uint8_t vsize;
uint8_t panel_id;
};
struct pt_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 pt_loader_platform_data {
struct pt_touch_firmware *fw;
struct pt_touch_config *ttconfig;
struct pt_touch_firmware **fws;
struct pt_touch_config **ttconfigs;
u32 flags;
};
typedef int (*pt_platform_read) (struct device *dev, void *buf, int size);
#define PT_TOUCH_SETTINGS_MAX 32
struct pt_core_platform_data {
int irq_gpio;
int rst_gpio;
int ddi_rst_gpio;
int vddi_gpio;
int vcc_gpio;
int avdd_gpio;
int avee_gpio;
int level_irq_udelay;
u16 hid_desc_register;
u16 vendor_id;
u16 product_id;
int (*xres)(struct pt_core_platform_data *pdata,
struct device *dev);
int (*init)(struct pt_core_platform_data *pdata,
int on, struct device *dev);
int (*power)(struct pt_core_platform_data *pdata,
int on, struct device *dev, atomic_t *ignore_irq);
int (*detect)(struct pt_core_platform_data *pdata,
struct device *dev, pt_platform_read read);
int (*irq_stat)(struct pt_core_platform_data *pdata,
struct device *dev);
int (*setup_power)(struct pt_core_platform_data *pdata,
int on, struct device *dev);
int (*setup_irq)(struct pt_core_platform_data *pdata,
int on, struct device *dev);
struct touch_settings *sett[PT_TOUCH_SETTINGS_MAX];
u32 flags;
u8 easy_wakeup_gesture;
u8 config_dut_generation;
u8 watchdog_force_stop;
u8 panel_id_support;
};
struct touch_framework {
const int16_t *abs;
uint8_t size;
uint8_t enable_vkeys;
} __packed;
enum pt_mt_platform_power_state {
PT_MT_POWER_OFF = 0x00,
PT_MT_POWER_ON = 0x01
};
enum pt_mt_platform_irq_state {
PT_MT_IRQ_FREE = 0x00,
PT_MT_IRQ_REG = 0x01
};
enum pt_mt_platform_flags {
PT_MT_FLAG_NONE,
PT_MT_FLAG_HOVER = 0x04,
PT_MT_FLAG_FLIP = 0x08,
PT_MT_FLAG_INV_X = 0x10,
PT_MT_FLAG_INV_Y = 0x20,
PT_MT_FLAG_VKEYS = 0x40,
PT_MT_FLAG_NO_TOUCH_ON_LO = 0x80,
};
struct pt_mt_platform_data {
struct touch_framework *frmwrk;
unsigned short flags;
char const *inp_dev_name;
int vkeys_x;
int vkeys_y;
};
struct pt_btn_platform_data {
char const *inp_dev_name;
};
struct pt_proximity_platform_data {
struct touch_framework *frmwrk;
char const *inp_dev_name;
};
struct pt_platform_data {
struct pt_core_platform_data *core_pdata;
struct pt_mt_platform_data *mt_pdata;
struct pt_btn_platform_data *btn_pdata;
struct pt_proximity_platform_data *prox_pdata;
struct pt_loader_platform_data *loader_pdata;
};
#endif /* _LINUX_PT_CORE_H */

View File

@ -0,0 +1,68 @@
/*
* pt_platform.h
* Parade TrueTouch(TM) Standard Product Platform Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* 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.parade.com <ttdrivers@paradetech.com>
*/
#ifndef _LINUX_PT_PLATFORM_H
#define _LINUX_PT_PLATFORM_H
#include <linux/pt_core.h>
#if defined(CONFIG_TOUCHSCREEN_PARADE) \
|| defined(CONFIG_TOUCHSCREEN_PARADE_MODULE)
extern struct pt_loader_platform_data _pt_loader_platform_data;
extern irqreturn_t pt_irq(int irq, void *handle);
int pt_xres(struct pt_core_platform_data *pdata, struct device *dev);
int pt_init(struct pt_core_platform_data *pdata, int on,
struct device *dev);
int pt_power(struct pt_core_platform_data *pdata, int on,
struct device *dev, atomic_t *ignore_irq);
#ifdef PT_DETECT_HW
int pt_detect(struct pt_core_platform_data *pdata,
struct device *dev, pt_platform_read read);
#else
#define pt_detect NULL
#endif
int pt_irq_stat(struct pt_core_platform_data *pdata,
struct device *dev);
int pt_setup_power(struct pt_core_platform_data *pdata, int on,
struct device *dev);
int pt_setup_irq(struct pt_core_platform_data *pdata, int on,
struct device *dev);
#else /* !CONFIG_TOUCHSCREEN_PARADE */
static struct pt_loader_platform_data _pt_loader_platform_data;
#define pt_xres NULL
#define pt_init NULL
#define pt_power NULL
#define pt_irq_stat NULL
#define pt_detect NULL
#define pt_setup_power NULL
#define pt_setup_irq NULL
#endif /* CONFIG_TOUCHSCREEN_PARADE */
#endif /* _LINUX_PT_PLATFORM_H */