| /* | |
| * | |
| * 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 */ |