diff options
Diffstat (limited to 'drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c')
-rw-r--r-- | drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c b/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c new file mode 100644 index 000000000000..4a62ee65eaa6 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c @@ -0,0 +1,311 @@ +/* + * + * 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 */ |