/* * * FocalTech TouchScreen driver. * * Copyright (c) 2010-2017, 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"); return; } /***************************************************************************** * 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 */