
Removed example files and move source to /pt/ Git-commit: e2e4bb9eacc2406cb0351d15e478e68249d5f625 Git-repo: https://github.com/Parade-Github/TTDL/tree/main Change-Id: I07f3464718058d5bba76b7d5be486a79934db354 Signed-off-by: Surya Teja Kudiri <quic_skudiri@quicinc.com>
573 wiersze
15 KiB
C
573 wiersze
15 KiB
C
#ifndef TTDL_KERNEL_SUBMISSION
|
|
/*
|
|
* pt_pen.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-2021 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_pen_lift_all
|
|
*
|
|
* SUMMARY: Reports pen liftoff action
|
|
*
|
|
* PARAMETERS:
|
|
* *pend - pointer to pen data structure
|
|
******************************************************************************/
|
|
static void pt_pen_lift_all(struct pt_pen_data *pend)
|
|
{
|
|
input_report_key(pend->input, BTN_STYLUS, 0);
|
|
input_report_key(pend->input, BTN_STYLUS2, 0);
|
|
input_report_key(pend->input, BTN_TOUCH, 0);
|
|
input_report_key(pend->input, BTN_TOOL_PEN, 0);
|
|
input_sync(pend->input);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_get_pen_data
|
|
*
|
|
* SUMMARY: Gets axis of pen report
|
|
*
|
|
* PARAMETERS:
|
|
* *pend - pointer to pen data structure
|
|
* *xy_data - pointer to touch data
|
|
******************************************************************************/
|
|
static void pt_get_pen(struct pt_pen_data *pend,
|
|
struct pt_pen *pen, u8 *xy_data)
|
|
{
|
|
struct device *dev = pend->dev;
|
|
struct pt_sysinfo *si = pend->si;
|
|
enum pt_pen_abs abs;
|
|
|
|
for (abs = PT_PEN_X; abs < PT_PEN_NUM_ABS; abs++) {
|
|
if (!si->pen_abs[abs].report)
|
|
continue;
|
|
pt_get_touch_field(dev, &pen->abs[abs],
|
|
si->pen_abs[abs].size,
|
|
si->pen_abs[abs].max,
|
|
xy_data + si->tch_abs[abs].ofs,
|
|
si->pen_abs[abs].bofs);
|
|
pt_debug(dev, DL_DEBUG, "%s: get %s=%04X(%d)\n",
|
|
__func__, pt_pen_abs_string[abs],
|
|
pen->abs[abs], pen->abs[abs]);
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_xy_worker
|
|
*
|
|
* SUMMARY: Read xy_data for current pen touch
|
|
*
|
|
* RETURN:
|
|
* 0 = success
|
|
*
|
|
* PARAMETERS:
|
|
* *pend - pointer to pen data structure
|
|
******************************************************************************/
|
|
static int pt_xy_worker(struct pt_pen_data *pend)
|
|
{
|
|
struct pt_sysinfo *si = pend->si;
|
|
struct pt_pen pen;
|
|
bool tool;
|
|
|
|
pt_get_pen(pend, &pen, si->xy_data + 3);
|
|
|
|
tool = pen.abs[PT_PEN_IV] ?
|
|
BTN_TOOL_RUBBER : BTN_TOOL_PEN;
|
|
|
|
input_report_abs(pend->input, ABS_X, pen.abs[PT_PEN_X]);
|
|
input_report_abs(pend->input, ABS_Y, pen.abs[PT_PEN_Y]);
|
|
input_report_abs(pend->input, ABS_PRESSURE, pen.abs[PT_PEN_P]);
|
|
input_report_key(pend->input, BTN_STYLUS, pen.abs[PT_PEN_BS]);
|
|
|
|
if (si->pen_abs[PT_PEN_2ND_BS].report)
|
|
input_report_key(pend->input, BTN_STYLUS2,
|
|
pen.abs[PT_PEN_2ND_BS]);
|
|
|
|
input_report_key(pend->input, BTN_TOUCH, pen.abs[PT_PEN_TS]);
|
|
input_report_key(pend->input, tool, pen.abs[PT_PEN_IR]);
|
|
|
|
if (si->pen_abs[PT_PEN_X_TILT].report)
|
|
input_report_abs(pend->input, ABS_TILT_X,
|
|
pen.abs[PT_PEN_X_TILT]);
|
|
|
|
if (si->pen_abs[PT_PEN_Y_TILT].report)
|
|
input_report_abs(pend->input, ABS_TILT_Y,
|
|
pen.abs[PT_PEN_Y_TILT]);
|
|
|
|
input_sync(pend->input);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_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_pen_attention(struct device *dev)
|
|
{
|
|
struct pt_core_data *cd = dev_get_drvdata(dev);
|
|
struct pt_pen_data *pend = &cd->pend;
|
|
int rc;
|
|
|
|
if (pend->si->xy_mode[2] != pend->si->desc.pen_report_id)
|
|
return 0;
|
|
|
|
/* core handles handshake */
|
|
mutex_lock(&pend->pen_lock);
|
|
rc = pt_xy_worker(pend);
|
|
mutex_unlock(&pend->pen_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_pen_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_pen_data *pend = &cd->pend;
|
|
|
|
mutex_lock(&pend->pen_lock);
|
|
pt_pen_lift_all(pend);
|
|
mutex_unlock(&pend->pen_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_suspend_attention
|
|
*
|
|
* SUMMARY: Function for pen to enter suspend state that as following steps:
|
|
* 1) Lift pen touch
|
|
* 2) Set flag with suspend state
|
|
* 3) Decrese pm system count
|
|
*
|
|
* RETURN:
|
|
* 0 = success
|
|
*
|
|
* PARAMETERS:
|
|
* *dev - pointer to device structure
|
|
******************************************************************************/
|
|
static int pt_pen_suspend_attention(struct device *dev)
|
|
{
|
|
struct pt_core_data *cd = dev_get_drvdata(dev);
|
|
struct pt_pen_data *pend = &cd->pend;
|
|
|
|
mutex_lock(&pend->pen_lock);
|
|
pt_pen_lift_all(pend);
|
|
pend->is_suspended = true;
|
|
mutex_unlock(&pend->pen_lock);
|
|
|
|
pm_runtime_put(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_resume_attention
|
|
*
|
|
* SUMMARY: Function for pen 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_pen_resume_attention(struct device *dev)
|
|
{
|
|
struct pt_core_data *cd = dev_get_drvdata(dev);
|
|
struct pt_pen_data *pend = &cd->pend;
|
|
|
|
pm_runtime_get(dev);
|
|
|
|
mutex_lock(&pend->pen_lock);
|
|
pend->is_suspended = false;
|
|
mutex_unlock(&pend->pen_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_open
|
|
*
|
|
* SUMMARY: Open method for input device(pen) that sets up call back
|
|
* functions to TTDL attention list
|
|
*
|
|
* RETURN:
|
|
* 0 = success
|
|
*
|
|
* PARAMETERS:
|
|
* *input - pointer to input_dev structure
|
|
******************************************************************************/
|
|
static int pt_pen_open(struct input_dev *input)
|
|
{
|
|
struct device *dev = input->dev.parent;
|
|
struct pt_core_data *cd = dev_get_drvdata(dev);
|
|
struct pt_pen_data *pend = &cd->pend;
|
|
|
|
pm_runtime_get_sync(dev);
|
|
|
|
mutex_lock(&pend->pen_lock);
|
|
pend->is_suspended = false;
|
|
mutex_unlock(&pend->pen_lock);
|
|
|
|
pt_debug(dev, DL_INFO, "%s: setup subscriptions\n", __func__);
|
|
|
|
/* set up touch call back */
|
|
_pt_subscribe_attention(dev, PT_ATTEN_IRQ, PT_PEN_NAME,
|
|
pt_pen_attention, PT_MODE_OPERATIONAL);
|
|
|
|
/* set up startup call back */
|
|
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP, PT_PEN_NAME,
|
|
pt_startup_attention, 0);
|
|
|
|
/* set up suspend call back */
|
|
_pt_subscribe_attention(dev, PT_ATTEN_SUSPEND, PT_PEN_NAME,
|
|
pt_pen_suspend_attention, 0);
|
|
|
|
/* set up resume call back */
|
|
_pt_subscribe_attention(dev, PT_ATTEN_RESUME, PT_PEN_NAME,
|
|
pt_pen_resume_attention, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_close
|
|
*
|
|
* SUMMARY: Close method for input device(pen) that clears call back
|
|
* functions from TTDL attention list.
|
|
*
|
|
* PARAMETERS:
|
|
* *input - pointer to input_dev structure
|
|
******************************************************************************/
|
|
static void pt_pen_close(struct input_dev *input)
|
|
{
|
|
struct device *dev = input->dev.parent;
|
|
struct pt_core_data *cd = dev_get_drvdata(dev);
|
|
struct pt_pen_data *pend = &cd->pend;
|
|
|
|
_pt_unsubscribe_attention(dev, PT_ATTEN_IRQ, PT_PEN_NAME,
|
|
pt_pen_attention, PT_MODE_OPERATIONAL);
|
|
|
|
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP, PT_PEN_NAME,
|
|
pt_startup_attention, 0);
|
|
|
|
_pt_unsubscribe_attention(dev, PT_ATTEN_SUSPEND, PT_PEN_NAME,
|
|
pt_pen_suspend_attention, 0);
|
|
|
|
_pt_unsubscribe_attention(dev, PT_ATTEN_RESUME, PT_PEN_NAME,
|
|
pt_pen_resume_attention, 0);
|
|
|
|
mutex_lock(&pend->pen_lock);
|
|
if (!pend->is_suspended) {
|
|
pm_runtime_put(dev);
|
|
pend->is_suspended = true;
|
|
}
|
|
mutex_unlock(&pend->pen_lock);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_setup_input_device
|
|
*
|
|
* SUMMARY: Set up resolution, event signal capabilities and register input
|
|
* device for pen.
|
|
*
|
|
* 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_pen_data *pend = &cd->pend;
|
|
int i;
|
|
int rc;
|
|
u32 usage;
|
|
int max_x, max_y, max_p;
|
|
|
|
pt_debug(dev, DL_INFO, "%s: Initialize event signals\n",
|
|
__func__);
|
|
__set_bit(EV_ABS, pend->input->evbit);
|
|
__set_bit(EV_KEY, pend->input->evbit);
|
|
|
|
for (i = PT_PEN_X; i < PT_PEN_NUM_ABS; i++) {
|
|
usage = pt_pen_abs_field_map[i];
|
|
|
|
switch (usage) {
|
|
case HID_GD_X:
|
|
max_x = pend->si->sensing_conf_data.res_x;
|
|
input_set_abs_params(pend->input,
|
|
ABS_X, 0, max_x, 0, 0);
|
|
break;
|
|
case HID_GD_Y:
|
|
max_y = pend->si->sensing_conf_data.res_y;
|
|
input_set_abs_params(pend->input,
|
|
ABS_Y, 0, max_y, 0, 0);
|
|
break;
|
|
case HID_DG_TIPPRESSURE:
|
|
max_p = pend->si->sensing_conf_data.max_z;
|
|
input_set_abs_params(pend->input,
|
|
ABS_PRESSURE, 0, max_p, 0, 0);
|
|
break;
|
|
case HID_DG_INRANGE:
|
|
input_set_capability(pend->input,
|
|
EV_KEY, BTN_TOOL_PEN);
|
|
break;
|
|
case HID_DG_INVERT:
|
|
input_set_capability(pend->input,
|
|
EV_KEY, BTN_TOOL_RUBBER);
|
|
break;
|
|
case HID_DG_TILT_X:
|
|
max_x = pend->si->pen_abs[i].max;
|
|
input_set_abs_params(pend->input,
|
|
ABS_TILT_X, 0, max_x, 0, 0);
|
|
break;
|
|
case HID_DG_TILT_Y:
|
|
max_x = pend->si->pen_abs[i].max;
|
|
input_set_abs_params(pend->input,
|
|
ABS_TILT_Y, 0, max_x, 0, 0);
|
|
break;
|
|
case HID_DG_ERASER:
|
|
case HID_DG_TIPSWITCH:
|
|
input_set_capability(pend->input,
|
|
EV_KEY, BTN_TOUCH);
|
|
break;
|
|
case HID_DG_BARRELSWITCH:
|
|
input_set_capability(pend->input,
|
|
EV_KEY, BTN_STYLUS);
|
|
break;
|
|
case HID_DG_BARRELSWITCH2:
|
|
input_set_capability(pend->input,
|
|
EV_KEY, BTN_STYLUS2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rc = input_register_device(pend->input);
|
|
if (rc < 0)
|
|
pt_debug(dev, DL_ERROR,
|
|
"%s: Error, failed register input device r=%d\n",
|
|
__func__, rc);
|
|
else
|
|
pend->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_pen_data *pend = &cd->pend;
|
|
int rc;
|
|
|
|
pend->si = _pt_request_sysinfo(dev);
|
|
if (!pend->si)
|
|
return -1;
|
|
|
|
rc = pt_setup_input_device(dev);
|
|
|
|
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP, PT_PEN_NAME,
|
|
pt_setup_input_attention, 0);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_probe
|
|
*
|
|
* SUMMARY: The probe function for pen input device
|
|
*
|
|
* RETURN:
|
|
* 0 = success
|
|
* !0 = failure
|
|
*
|
|
* PARAMETERS:
|
|
* *dev - pointer to device structure
|
|
******************************************************************************/
|
|
int pt_pen_probe(struct device *dev)
|
|
{
|
|
struct pt_core_data *cd = dev_get_drvdata(dev);
|
|
struct pt_pen_data *pend = &cd->pend;
|
|
struct pt_platform_data *pdata = dev_get_platdata(dev);
|
|
struct pt_pen_platform_data *pen_pdata;
|
|
int rc = 0;
|
|
|
|
if (!pdata || !pdata->pen_pdata) {
|
|
pt_debug(dev, DL_ERROR,
|
|
"%s: Missing platform data\n", __func__);
|
|
rc = -ENODEV;
|
|
goto error_no_pdata;
|
|
}
|
|
pen_pdata = pdata->pen_pdata;
|
|
|
|
mutex_init(&pend->pen_lock);
|
|
pend->dev = dev;
|
|
pend->pdata = pen_pdata;
|
|
|
|
/* Create the input device and register it. */
|
|
pt_debug(dev, DL_INFO,
|
|
"%s: Create the input device and register it\n", __func__);
|
|
pend->input = input_allocate_device();
|
|
if (!pend->input) {
|
|
pt_debug(dev, DL_ERROR,
|
|
"%s: Error, failed to allocate input device\n",
|
|
__func__);
|
|
rc = -ENODEV;
|
|
goto error_alloc_failed;
|
|
} else
|
|
pend->input_device_allocated = true;
|
|
|
|
if (pend->pdata->inp_dev_name)
|
|
pend->input->name = pend->pdata->inp_dev_name;
|
|
else
|
|
pend->input->name = PT_PEN_NAME;
|
|
scnprintf(pend->phys, sizeof(pend->phys), "%s/input%d", dev_name(dev),
|
|
cd->phys_num++);
|
|
pend->input->phys = pend->phys;
|
|
pend->input->dev.parent = pend->dev;
|
|
pend->input->open = pt_pen_open;
|
|
pend->input->close = pt_pen_close;
|
|
input_set_drvdata(pend->input, pend);
|
|
|
|
/* get sysinfo */
|
|
pend->si = _pt_request_sysinfo(dev);
|
|
|
|
if (pend->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__, pend->si);
|
|
_pt_subscribe_attention(dev, PT_ATTEN_STARTUP,
|
|
PT_PEN_NAME, pt_setup_input_attention, 0);
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_init_input:
|
|
input_free_device(pend->input);
|
|
pend->input_device_allocated = false;
|
|
error_alloc_failed:
|
|
error_no_pdata:
|
|
pt_debug(dev, DL_ERROR, "%s failed.\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FUNCTION: pt_pen_release
|
|
*
|
|
* SUMMARY: The release function for pen input device
|
|
*
|
|
* RETURN:
|
|
* 0 = success
|
|
*
|
|
* PARAMETERS:
|
|
* *dev - pointer to device structure
|
|
******************************************************************************/
|
|
int pt_pen_release(struct device *dev)
|
|
{
|
|
struct pt_core_data *cd;
|
|
struct pt_pen_data *pend;
|
|
|
|
/* Ensure valid pointers before de-referencing them */
|
|
if (dev) {
|
|
cd = dev_get_drvdata(dev);
|
|
if (cd)
|
|
pend = &cd->pend;
|
|
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 (pend && pend->input_device_registered) {
|
|
pend->input_device_registered = false;
|
|
input_unregister_device(pend->input);
|
|
/* Unregistering device will free the device too */
|
|
pend->input_device_allocated = false;
|
|
} else if (pend && pend->input_device_allocated) {
|
|
pend->input_device_allocated = false;
|
|
input_free_device(pend->input);
|
|
_pt_unsubscribe_attention(dev, PT_ATTEN_STARTUP,
|
|
PT_PEN_NAME, pt_setup_input_attention, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /*!TTDL_KERNEL_SUBMISSION */
|