summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c')
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c311
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 */