312 lines
8.9 KiB
C
312 lines
8.9 KiB
C
/*
|
|
*
|
|
* FocalTech TouchScreen driver.
|
|
*
|
|
* Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* File Name: focaltech_esdcheck.c
|
|
*
|
|
* Author: Focaltech Driver Team
|
|
*
|
|
* Created: 2016-08-03
|
|
*
|
|
* Abstract: Sensor
|
|
*
|
|
* Version: v1.0
|
|
*
|
|
* Revision History:
|
|
* v1.0:
|
|
* First release. By luougojin 2016-08-03
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Included header files
|
|
*****************************************************************************/
|
|
#include "focaltech_core.h"
|
|
|
|
#if FTS_PSENSOR_EN
|
|
/*****************************************************************************
|
|
* Private constant and macro definitions using #define
|
|
*****************************************************************************/
|
|
/* psensor register address*/
|
|
#define FTS_REG_PSENSOR_ENABLE 0xB0
|
|
#define FTS_REG_PSENSOR_STATUS 0x01
|
|
|
|
/* psensor register bits*/
|
|
#define FTS_PSENSOR_ENABLE_MASK 0x01
|
|
#define FTS_PSENSOR_STATUS_NEAR 0xC0
|
|
#define FTS_PSENSOR_STATUS_FAR 0xE0
|
|
#define FTS_PSENSOR_FAR_TO_NEAR 0
|
|
#define FTS_PSENSOR_NEAR_TO_FAR 1
|
|
#define FTS_PSENSOR_ORIGINAL_STATE_FAR 1
|
|
#define FTS_PSENSOR_WAKEUP_TIMEOUT 500
|
|
|
|
/*****************************************************************************
|
|
* Static variables
|
|
*****************************************************************************/
|
|
static struct sensors_classdev __maybe_unused sensors_proximity_cdev = {
|
|
.name = "fts-proximity",
|
|
.vendor = "FocalTech",
|
|
.version = 1,
|
|
.handle = SENSORS_PROXIMITY_HANDLE,
|
|
.type = SENSOR_TYPE_PROXIMITY,
|
|
.max_range = "5.0",
|
|
.resolution = "5.0",
|
|
.sensor_power = "0.1",
|
|
.min_delay = 0,
|
|
.fifo_reserved_event_count = 0,
|
|
.fifo_max_event_count = 0,
|
|
.enabled = 0,
|
|
.delay_msec = 200,
|
|
.sensors_enable = NULL,
|
|
.sensors_poll_delay = NULL,
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* functions body
|
|
*****************************************************************************/
|
|
/*****************************************************************************
|
|
* Name: fts_psensor_support_enabled
|
|
* Brief:
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
*****************************************************************************/
|
|
static inline bool fts_psensor_support_enabled(void)
|
|
{
|
|
/*return config_enabled(CONFIG_TOUCHSCREEN_FTS_PSENSOR); */
|
|
return FTS_PSENSOR_EN;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_psensor_enable
|
|
* Brief:
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
*****************************************************************************/
|
|
static void fts_psensor_enable(struct fts_ts_data *data, int enable)
|
|
{
|
|
u8 state;
|
|
int ret = -1;
|
|
|
|
if (data->client == NULL)
|
|
return;
|
|
|
|
fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_ENABLE, &state);
|
|
if (enable)
|
|
state |= FTS_PSENSOR_ENABLE_MASK;
|
|
else
|
|
state &= ~FTS_PSENSOR_ENABLE_MASK;
|
|
|
|
ret = fts_i2c_write_reg(data->client, FTS_REG_PSENSOR_ENABLE, state);
|
|
if (ret < 0)
|
|
FTS_ERROR("write psensor switch command failed");
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_psensor_enable_set
|
|
* Brief:
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
*****************************************************************************/
|
|
static int fts_psensor_enable_set(struct sensors_classdev *sensors_cdev,
|
|
unsigned int enable)
|
|
{
|
|
struct fts_psensor_platform_data *psensor_pdata =
|
|
container_of(sensors_cdev,
|
|
struct fts_psensor_platform_data, ps_cdev);
|
|
struct fts_ts_data *data = psensor_pdata->data;
|
|
struct input_dev *input_dev = data->psensor_pdata->input_psensor_dev;
|
|
|
|
mutex_lock(&input_dev->mutex);
|
|
fts_psensor_enable(data, enable);
|
|
psensor_pdata->tp_psensor_data = FTS_PSENSOR_ORIGINAL_STATE_FAR;
|
|
if (enable)
|
|
psensor_pdata->tp_psensor_opened = 1;
|
|
else
|
|
psensor_pdata->tp_psensor_opened = 0;
|
|
mutex_unlock(&input_dev->mutex);
|
|
return enable;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_read_tp_psensor_data
|
|
* Brief:
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
*****************************************************************************/
|
|
static int fts_read_tp_psensor_data(struct fts_ts_data *data)
|
|
{
|
|
u8 psensor_status;
|
|
char tmp;
|
|
int ret = 1;
|
|
|
|
fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_STATUS, &psensor_status);
|
|
|
|
tmp = data->psensor_pdata->tp_psensor_data;
|
|
if (psensor_status == FTS_PSENSOR_STATUS_NEAR)
|
|
data->psensor_pdata->tp_psensor_data = FTS_PSENSOR_FAR_TO_NEAR;
|
|
else if (psensor_status == FTS_PSENSOR_STATUS_FAR)
|
|
data->psensor_pdata->tp_psensor_data = FTS_PSENSOR_NEAR_TO_FAR;
|
|
|
|
if (tmp != data->psensor_pdata->tp_psensor_data) {
|
|
FTS_ERROR("%s sensor data changed", __func__);
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int fts_sensor_read_data(struct fts_ts_data *data)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (fts_psensor_support_enabled()
|
|
&& data->psensor_pdata->tp_psensor_opened) {
|
|
ret = fts_read_tp_psensor_data(data);
|
|
if (!ret) {
|
|
if (data->suspended) {
|
|
pm_wakeup_event(&data->client->dev,
|
|
FTS_PSENSOR_WAKEUP_TIMEOUT);
|
|
}
|
|
input_report_abs(data->psensor_pdata->input_psensor_dev,
|
|
ABS_DISTANCE,
|
|
data->psensor_pdata->tp_psensor_data);
|
|
input_sync(data->psensor_pdata->input_psensor_dev);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int fts_sensor_suspend(struct fts_ts_data *data)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (fts_psensor_support_enabled()
|
|
&& device_may_wakeup(&data->client->dev)
|
|
&& data->psensor_pdata->tp_psensor_opened) {
|
|
ret = enable_irq_wake(data->client->irq);
|
|
if (ret != 0)
|
|
FTS_ERROR("%s: set_irq_wake failed", __func__);
|
|
data->suspended = true;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fts_sensor_resume(struct fts_ts_data *data)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (fts_psensor_support_enabled()
|
|
&& device_may_wakeup(&data->client->dev)
|
|
&& data->psensor_pdata->tp_psensor_opened) {
|
|
ret = disable_irq_wake(data->client->irq);
|
|
if (ret)
|
|
FTS_ERROR("%s: disable_irq_wake failed", __func__);
|
|
data->suspended = false;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fts_sensor_init(struct fts_ts_data *data)
|
|
{
|
|
struct fts_psensor_platform_data *psensor_pdata;
|
|
struct input_dev *psensor_input_dev;
|
|
int err;
|
|
|
|
if (fts_psensor_support_enabled()) {
|
|
device_init_wakeup(&data->client->dev, 1);
|
|
psensor_pdata =
|
|
devm_kzalloc(&data->client->dev,
|
|
sizeof(struct fts_psensor_platform_data),
|
|
GFP_KERNEL);
|
|
if (!psensor_pdata) {
|
|
FTS_ERROR("Failed to allocate memory");
|
|
goto irq_free;
|
|
}
|
|
data->psensor_pdata = psensor_pdata;
|
|
|
|
psensor_input_dev = input_allocate_device();
|
|
if (!psensor_input_dev) {
|
|
FTS_ERROR("Failed to allocate device");
|
|
goto free_psensor_pdata;
|
|
}
|
|
|
|
__set_bit(EV_ABS, psensor_input_dev->evbit);
|
|
input_set_abs_params(psensor_input_dev, ABS_DISTANCE, 0, 1, 0,
|
|
0);
|
|
psensor_input_dev->name = "proximity";
|
|
psensor_input_dev->id.bustype = BUS_I2C;
|
|
psensor_input_dev->dev.parent = &data->client->dev;
|
|
data->psensor_pdata->input_psensor_dev = psensor_input_dev;
|
|
|
|
err = input_register_device(psensor_input_dev);
|
|
if (err) {
|
|
FTS_ERROR("Unable to register device, err=%d", err);
|
|
goto free_psensor_input_dev;
|
|
}
|
|
|
|
psensor_pdata->ps_cdev = sensors_proximity_cdev;
|
|
psensor_pdata->ps_cdev.sensors_enable = fts_psensor_enable_set;
|
|
psensor_pdata->data = data;
|
|
|
|
err =
|
|
sensors_classdev_register(&data->client->dev,
|
|
&psensor_pdata->ps_cdev);
|
|
if (err)
|
|
goto unregister_psensor_input_device;
|
|
}
|
|
|
|
return 0;
|
|
unregister_psensor_input_device:
|
|
if (fts_psensor_support_enabled())
|
|
input_unregister_device(data->psensor_pdata->input_psensor_dev);
|
|
free_psensor_input_dev:
|
|
if (fts_psensor_support_enabled())
|
|
input_free_device(data->psensor_pdata->input_psensor_dev);
|
|
free_psensor_pdata:
|
|
if (fts_psensor_support_enabled()) {
|
|
devm_kfree(&data->client->dev, psensor_pdata);
|
|
data->psensor_pdata = NULL;
|
|
}
|
|
irq_free:
|
|
if (fts_psensor_support_enabled())
|
|
device_init_wakeup(&data->client->dev, 0);
|
|
free_irq(data->client->irq, data);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int fts_sensor_remove(struct fts_ts_data *data)
|
|
{
|
|
if (fts_psensor_support_enabled()) {
|
|
device_init_wakeup(&data->client->dev, 0);
|
|
sensors_classdev_unregister(&data->psensor_pdata->ps_cdev);
|
|
input_unregister_device(data->psensor_pdata->input_psensor_dev);
|
|
devm_kfree(&data->client->dev, data->psensor_pdata);
|
|
data->psensor_pdata = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* FTS_PSENSOR_EN */
|