blob: 4a62ee65eaa6b327e39460a26fcc50219fa48d3a [file] [log] [blame]
/*
*
* 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 */