816 lines
22 KiB
C
816 lines
22 KiB
C
/*
|
|
* 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;
|
|
}
|