summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorBeomho Seo <beomho.seo@samsung.com>2014-11-25 19:24:16 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:40:39 +0900
commit8ccc361df036379769a6ff5d62c9155fff59066f (patch)
treee240dcdd5f7f5dad07617706e63bef49b33a0694 /drivers/input
parent52f4d3ccfdb7a240d6e25894f1275f1736d2c9f1 (diff)
LOCAL / input: touchscreen: Add STM FTS touchscreen
This patch add STMicroelectronics FTS touchscreen controller. Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/Kconfig8
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/fts_ts.c682
-rw-r--r--drivers/input/touchscreen/fts_ts.h231
4 files changed, 922 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 80f6386709bf..621b3687b705 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1027,4 +1027,12 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
+config TOUCHSCREEN_FTS
+ tristate "STMicroelectronics i2c multitouch touchscreen with FingerTipS"
+ depends on I2C
+ help
+ Say Y here to enable STMicroelectronics touchscreen support.
+ If unsure, say N.
+ To compile this driver as a module, choose M here: the
+ module will be called STM_ts.
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 44deea743d02..562e05fdf4e8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -84,3 +84,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += fts_ts.o
diff --git a/drivers/input/touchscreen/fts_ts.c b/drivers/input/touchscreen/fts_ts.c
new file mode 100644
index 000000000000..3737768b11ab
--- /dev/null
+++ b/drivers/input/touchscreen/fts_ts.c
@@ -0,0 +1,682 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+
+#include "fts_ts.h"
+
+int fts_write_reg(struct fts_ts_info *info,
+ unsigned char *reg, unsigned short num_com)
+{
+ struct i2c_client *client = info->client;
+ struct i2c_msg xfer_msg[2];
+ int ret;
+
+ if (info->touch_stopped) {
+ dev_err(&client->dev, "Sensor stopped\n");
+ return 0;
+ }
+
+ xfer_msg[0].addr = client->addr;
+ xfer_msg[0].len = num_com;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = reg;
+
+ ret = i2c_transfer(client->adapter, xfer_msg, 1);
+
+ return ret;
+}
+
+int fts_read_reg(struct fts_ts_info *info, unsigned char *reg, int cnum,
+ unsigned char *buf, int num)
+{
+ struct i2c_client *client = info->client;
+ struct i2c_msg xfer_msg[2];
+ int ret;
+
+ if (info->touch_stopped) {
+ dev_err(&client->dev, "Sensor stopped\n");
+ return 0;
+ }
+
+ xfer_msg[0].addr = info->client->addr;
+ xfer_msg[0].len = cnum;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = reg;
+
+ xfer_msg[1].addr = info->client->addr;
+ xfer_msg[1].len = num;
+ xfer_msg[1].flags = I2C_M_RD;
+ xfer_msg[1].buf = buf;
+
+ ret = i2c_transfer(client->adapter, xfer_msg, 2);
+
+ return ret;
+}
+
+void fts_command(struct fts_ts_info *info, unsigned char cmd)
+{
+ struct i2c_client *client = info->client;
+ unsigned char reg_addr = 0;
+ int ret = 0;
+
+ reg_addr = cmd;
+ ret = fts_write_reg(info, &reg_addr, 1);
+
+ dev_dbg(&client->dev, "FTS Command (%02X) , ret = %d\n", cmd, ret);
+}
+
+void fts_systemreset(struct fts_ts_info *info)
+{
+ struct i2c_client *client = info->client;
+ unsigned char reg_addr[4] = { 0xB6, 0x00, 0x23, 0x01 };
+
+ dev_dbg(&client->dev, "FTS SystemReset\n");
+
+ fts_write_reg(info, &reg_addr[0], 4);
+ msleep(20);
+}
+
+static void fts_interrupt_set(struct fts_ts_info *info, int enable)
+{
+ struct i2c_client *client = info->client;
+ unsigned char reg_addr[4] = { 0xB6, 0x00, 0x1C, enable };
+
+ if (enable)
+ dev_dbg(&client->dev, "FTS INT Enable\n");
+ else
+ dev_dbg(&client->dev, "FTS INT Disable\n");
+
+ fts_write_reg(info, &reg_addr[0], 4);
+}
+
+static void fts_get_version_info(struct fts_ts_info *info)
+{
+ struct i2c_client *client = info->client;
+ unsigned char reg_addr[3];
+ unsigned char data[FTS_EVENT_SIZE];
+ int retry = 0;
+
+ fts_command(info, FTS_CMD_RELEASEINFO);
+
+ memset(data, 0x00, FTS_EVENT_SIZE);
+
+ reg_addr[0] = READ_ONE_EVENT;
+
+ while (fts_read_reg(info, &reg_addr[0], 1, (unsigned char *)data,
+ FTS_EVENT_SIZE)) {
+ if (data[0] == EVENTID_INTERNAL_RELEASE_INFO) {
+ info->fw_ver_ic = (data[3] << 8) + data[4];
+ info->config_ver_ic = (data[6] << 8) + data[5];
+ } else if (data[0] == EVENTID_EXTERNAL_RELEASE_INFO) {
+ info->fw_main_ver_ic = (data[1] << 8) + data[2];
+ break;
+ }
+
+ if (retry++ > FTS_RETRY_COUNT) {
+ dev_err(&client->dev,
+ "Time out to get ic information\n");
+ break;
+ }
+ }
+
+ dev_info(&client->dev,
+ "FW ver: 0x%04x, Config ver: 0x%04x, FW main ver 0x%04x\n",
+ info->fw_ver_ic, info->config_ver_ic, info->fw_main_ver_ic);
+}
+
+static int fts_wait_for_ready(struct fts_ts_info *info)
+{
+ int rc;
+ unsigned char reg_addr;
+ unsigned char data[FTS_EVENT_SIZE];
+ int retry = 0;
+ int err_cnt = 0;
+
+ memset(data, 0x0, FTS_EVENT_SIZE);
+
+ reg_addr = READ_ONE_EVENT;
+ rc = -1;
+ while (fts_read_reg(info, &reg_addr, 1,
+ (unsigned char *)data, FTS_EVENT_SIZE)) {
+
+ if (data[0] == EVENTID_CONTROLLER_READY) {
+ rc = 0;
+ break;
+ }
+
+ if (data[0] == EVENTID_ERROR) {
+ if (err_cnt++ > 32) {
+ rc = -FTS_ERROR_EVENT_ID;
+ break;
+ }
+ continue;
+ }
+
+ if (retry++ > FTS_RETRY_COUNT) {
+ rc = -FTS_ERROR_TIMEOUT;
+ dev_err(&info->client->dev, "Time Over\n");
+ break;
+ }
+ msleep(20);
+ }
+
+ return rc;
+}
+
+static int fts_init(struct fts_ts_info *info)
+{
+ struct i2c_client *client = info->client;
+ unsigned char val[16];
+ unsigned char reg_addr[8];
+ int rc;
+
+ fts_systemreset(info);
+
+ rc = fts_wait_for_ready(info);
+ if (rc == -FTS_ERROR_EVENT_ID)
+ dev_err(&client->dev, "Failed to wait for ready\n");
+
+ fts_get_version_info(info);
+
+ fts_command(info, SLEEPOUT);
+ fts_command(info, SENSEON);
+ fts_command(info, FORCECALIBRATION);
+ fts_command(info, FLUSHBUFFER);
+
+ fts_interrupt_set(info, INT_ENABLE);
+
+ memset(val, 0x0, 4);
+ reg_addr[0] = READ_STATUS;
+ fts_read_reg(info, reg_addr, 1, (unsigned char *)val, 4);
+
+ dev_dbg(&client->dev, "FTS Initialized\n");
+
+ return 0;
+}
+
+void fts_release_all_finger(struct fts_ts_info *info)
+{
+ struct i2c_client *client = info->client;
+ int i;
+
+ for (i = 0; i < FINGER_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);
+
+ if ((info->finger[i].state == EVENTID_ENTER_POINTER) ||
+ (info->finger[i].state == EVENTID_MOTION_POINTER)) {
+
+ dev_dbg(&client->dev,
+ "[RA] tID:%d mc: %d\n",
+ i, info->finger[i].mcount);
+ }
+
+ info->finger[i].state = EVENTID_LEAVE_POINTER;
+ info->finger[i].mcount = 0;
+ }
+
+ input_report_key(info->input_dev, BTN_TOUCH, 0);
+ input_report_key(info->input_dev, BTN_TOOL_FINGER, 0);
+
+ input_sync(info->input_dev);
+}
+
+static unsigned char fts_event_handler_type_b(struct fts_ts_info *info,
+ unsigned char data[], unsigned char left_event)
+{
+ struct i2c_client *client = info->client;
+ unsigned char id = 0, event_id = 0;
+ unsigned char last_left_event = 0;
+ int x = 0, y = 0;
+ int bw = 0, bh = 0, palm = 0, sumsize = 0;
+
+ event_id = data[0] & 0x0F;
+
+ switch (event_id) {
+ case EVENTID_MOTION_POINTER:
+ x = data[1] + ((data[2] & 0x0f) << 8);
+ y = ((data[2] & 0xf0) >> 4) + (data[3] << 4);
+ bw = data[4];
+ bh = data[5];
+ palm = (data[6] >> 7) & 0x01;
+ sumsize = (data[6] & 0x7f) << 1;
+
+ input_mt_slot(info->input_dev, id);
+ input_mt_report_slot_state(info->input_dev,
+ MT_TOOL_FINGER, 1 + (palm << 1));
+ input_report_key(info->input_dev, BTN_TOUCH, 1);
+ input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
+
+ input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR,
+ max(bw, bh));
+ input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR,
+ min(bw, bh));
+
+ dev_dbg(&client->dev, "Pressed x: %d, y: %d\n", x, y);
+ break;
+ case EVENTID_LEAVE_POINTER:
+ input_mt_slot(info->input_dev, id);
+ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);
+ input_report_key(info->input_dev, BTN_TOUCH, 0);
+
+ dev_dbg(&client->dev, "Released\n");
+ break;
+ default:
+ break;
+ }
+
+ if (event_id == EVENTID_ENTER_POINTER)
+ dev_dbg(&client->dev, "[P] id: %d\n", id);
+ else if (event_id == EVENTID_LEAVE_POINTER) {
+ dev_dbg(&client->dev, "[R] id: %d mc: %d\n",
+ id, info->finger[id].mcount);
+ info->finger[id].mcount = 0;
+ } else if (event_id == EVENTID_MOTION_POINTER)
+ info->finger[id].mcount++;
+
+ info->finger[id].state = event_id;
+ input_sync(info->input_dev);
+
+ return last_left_event;
+}
+
+static irqreturn_t fts_interrupt_handler(int irq, void *handle)
+{
+ struct fts_ts_info *info = handle;
+ unsigned char reg_addr[4] = {0xb6, 0x00, 0x45, READ_ALL_EVENT};
+ unsigned short evtcount = 0;
+
+ evtcount = 0;
+ fts_read_reg(info, &reg_addr[0], 3, (unsigned char *)&evtcount, 2);
+ evtcount = evtcount >> 10;
+
+ if (evtcount > FTS_FIFO_MAX)
+ evtcount = FTS_FIFO_MAX;
+
+ if (evtcount > 0) {
+ memset(info->data, 0x0, FTS_EVENT_SIZE * evtcount);
+ fts_read_reg(info, &reg_addr[3], 1, (unsigned char *)info->data,
+ FTS_EVENT_SIZE * evtcount);
+ fts_event_handler_type_b(info, info->data, evtcount);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int fts_power_ctrl(void *data, bool on)
+{
+ struct fts_ts_info *info = (struct fts_ts_info *)data;
+ const struct fts_i2c_platform_data *pdata = info->board;
+ struct device *dev = &info->client->dev;
+ int retval = 0;
+
+ if (info->enabled == on)
+ return retval;
+
+ dev_dbg(dev, "Touchscreen power ctrl: %s\n", on ? "on" : "off");
+
+ if (on) {
+ retval = regulator_enable(pdata->vdd);
+ if (retval) {
+ dev_err(dev, "Failed to enable vdd: %d\n", retval);
+ return retval;
+ }
+ retval = regulator_enable(pdata->avdd);
+ if (retval) {
+ dev_err(dev, "Failed to enable avdd: %d\n", retval);
+ return retval;
+ }
+ msleep(20);
+ } else {
+ if (regulator_is_enabled(pdata->vdd))
+ regulator_disable(pdata->vdd);
+ if (regulator_is_enabled(pdata->avdd))
+ regulator_disable(pdata->avdd);
+ }
+
+ info->enabled = on;
+
+ return retval;
+}
+
+static void fts_reinit(struct fts_ts_info *info)
+{
+ fts_wait_for_ready(info);
+
+ fts_systemreset(info);
+
+ fts_wait_for_ready(info);
+
+ fts_command(info, SLEEPOUT);
+ msleep(50);
+
+ fts_command(info, SENSEON);
+ msleep(50);
+
+ fts_command(info, FLUSHBUFFER);
+ fts_interrupt_set(info, INT_ENABLE);
+}
+
+static int fts_start_device(struct fts_ts_info *info)
+{
+ struct i2c_client *client = info->client;
+
+ if (!info->touch_stopped) {
+ dev_err(&client->dev, "already power on\n");
+ return 0;
+ }
+
+ fts_release_all_finger(info);
+
+ if (info->board->power)
+ info->board->power(info, true);
+
+ info->touch_stopped = false;
+ info->reinit_done = false;
+ fts_reinit(info);
+ info->reinit_done = true;
+ enable_irq(client->irq);
+
+ return 0;
+}
+
+static int fts_stop_device(struct fts_ts_info *info)
+{
+ struct i2c_client *client = info->client;
+
+ if (info->touch_stopped) {
+ dev_err(&client->dev, "already power off\n");
+ return 0;
+ }
+
+ fts_interrupt_set(info, INT_DISABLE);
+ disable_irq(client->irq);
+
+ fts_command(info, FLUSHBUFFER);
+ fts_command(info, SLEEPIN);
+ fts_release_all_finger(info);
+ info->touch_stopped = true;
+
+ if (info->board->power)
+ info->board->power(info, false);
+
+ return 0;
+}
+
+#ifdef USE_OPEN_CLOSE
+static int fts_input_open(struct input_dev *dev)
+{
+ struct fts_ts_info *info = input_get_drvdata(dev);
+ struct i2c_client *client = info->client;
+ int retval;
+
+ retval = fts_start_device(info);
+ if (retval < 0)
+ dev_err(&client->dev, "Failed to start device\n");
+
+ return 0;
+}
+
+static void fts_input_close(struct input_dev *dev)
+{
+ struct fts_ts_info *info = input_get_drvdata(dev);
+
+ fts_stop_device(info);
+
+}
+#endif
+
+static struct fts_i2c_platform_data *fts_parse_dt(struct device *dev)
+{
+ struct fts_i2c_platform_data *pdata;
+ struct device_node *np = dev->of_node;
+
+ pdata = devm_kzalloc(dev, sizeof(struct fts_i2c_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ if (of_property_read_u32(np, "x-size", &pdata->max_x)) {
+ dev_err(dev, "failed to get x-size property\n");
+ return NULL;
+ };
+
+ if (of_property_read_u32(np, "y-size", &pdata->max_y)) {
+ dev_err(dev, "failed to get y-size property\n");
+ return NULL;
+ };
+
+ return pdata;
+}
+
+static int fts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct fts_i2c_platform_data *pdata;
+ struct fts_ts_info *info;
+ static char fts_ts_phys[64] = { 0 };
+ int retval;
+ int i = 0;
+
+ pdata = dev_get_platdata(&client->dev);
+ if (!pdata)
+ pdata = fts_parse_dt(&client->dev);
+
+ if (!pdata) {
+ dev_err(&client->dev, "Need platform data\n");
+ return -EINVAL;
+ }
+
+ info = devm_kzalloc(&client->dev,
+ sizeof(struct fts_ts_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "Failed to check i2c functionality.\n");
+ return -ENODEV;
+ }
+
+ pdata->power = fts_power_ctrl;
+ info->client = client;
+ info->board = pdata;
+ info->irq_enabled = false;
+ info->touch_stopped = false;
+
+ i2c_set_clientdata(client, info);
+
+ pdata->vdd = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(pdata->vdd)) {
+ retval = PTR_ERR(pdata->vdd);
+ dev_err(&client->dev,
+ "Unable to get the IO regulator (%d)\n", retval);
+ return retval;
+ }
+
+ pdata->avdd = devm_regulator_get(&client->dev, "avdd");
+ if (IS_ERR(pdata->avdd)) {
+ retval = PTR_ERR(pdata->avdd);
+ dev_err(&client->dev,
+ "Unable to get the Core regulator (%d)\n", retval);
+ return retval;
+ }
+
+ info->dev = &info->client->dev;
+ info->input_dev = devm_input_allocate_device(&client->dev);
+ if (!info->input_dev)
+ return -ENOMEM;
+
+ info->input_dev->dev.parent = &client->dev;
+ info->input_dev->name = "sec_touchscreen";
+ snprintf(fts_ts_phys, sizeof(fts_ts_phys), "%s/input0",
+ info->input_dev->name);
+ info->input_dev->phys = fts_ts_phys;
+ info->input_dev->id.bustype = BUS_I2C;
+#ifdef USE_OPEN_CLOSE
+ info->input_dev->open = fts_input_open;
+ info->input_dev->close = fts_input_close;
+#endif
+ __set_bit(EV_ABS, info->input_dev->evbit);
+ __set_bit(EV_KEY, info->input_dev->evbit);
+ set_bit(BTN_TOUCH, info->input_dev->keybit);
+
+ input_mt_init_slots(info->input_dev, FINGER_MAX, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_POSITION_X,
+ 0, info->board->max_x, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y,
+ 0, info->board->max_y, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_X,
+ 0, info->board->max_x, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_Y,
+ 0, info->board->max_y, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, 255, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR,
+ 0, 255, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_DISTANCE,
+ 0, 255, 0, 0);
+
+ input_set_drvdata(info->input_dev, info);
+ i2c_set_clientdata(client, info);
+
+ if (info->board->power)
+ info->board->power(info, true);
+
+ retval = fts_init(info);
+ info->reinit_done = true;
+
+ if (retval) {
+ dev_err(&client->dev, "FTS fts_init fail!\n");
+ goto err_fts_init;
+ }
+
+ retval = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, fts_interrupt_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ FTS_TS_DRV_NAME, info);
+
+ if (retval) {
+ dev_err(&client->dev, "Failed to enable attention interrupt\n");
+ goto err_fts_init;
+ }
+
+ retval = input_register_device(info->input_dev);
+ if (retval) {
+ dev_err(&client->dev, "FTS input_register_device fail!\n");
+ goto err_fts_init;
+ }
+
+ for (i = 0; i < FINGER_MAX; i++) {
+ info->finger[i].state = EVENTID_LEAVE_POINTER;
+ info->finger[i].mcount = 0;
+ }
+
+ return 0;
+
+err_fts_init:
+ info->board->power(info, false);
+ return retval;
+}
+
+static int fts_remove(struct i2c_client *client)
+{
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ fts_interrupt_set(info, INT_DISABLE);
+ fts_command(info, FLUSHBUFFER);
+
+ if (info->irq_enabled) {
+ disable_irq(client->irq);
+ free_irq(client->irq, info);
+ info->irq_enabled = false;
+ }
+
+ input_mt_destroy_slots(info->input_dev);
+
+ input_unregister_device(info->input_dev);
+ info->input_dev = NULL;
+
+ info->board->power(info, false);
+
+ kfree(info);
+
+ return 0;
+}
+
+static void fts_shutdown(struct i2c_client *client)
+{
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ fts_stop_device(info);
+}
+
+static int fts_pm_suspend(struct device *dev)
+{
+ struct fts_ts_info *info = dev_get_drvdata(dev);
+
+ mutex_lock(&info->input_dev->mutex);
+
+ if (info->input_dev->users)
+ fts_stop_device(info);
+
+ mutex_unlock(&info->input_dev->mutex);
+
+ return 0;
+}
+
+static int fts_pm_resume(struct device *dev)
+{
+ struct fts_ts_info *info = dev_get_drvdata(dev);
+
+ mutex_lock(&info->input_dev->mutex);
+
+ if (info->input_dev->users)
+ fts_start_device(info);
+
+ mutex_unlock(&info->input_dev->mutex);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(fts_dev_pm_ops, fts_pm_suspend, fts_pm_resume);
+
+static const struct i2c_device_id fts_device_id[] = {
+ { "fts_touch", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, fts_device_id);
+
+static const struct of_device_id fts_match_table[] = {
+ { .compatible = "stm,fts_touch",},
+ { },
+};
+
+static struct i2c_driver fts_i2c_driver = {
+ .driver = {
+ .name = FTS_TS_DRV_NAME,
+ .of_match_table = of_match_ptr(fts_match_table),
+ .pm = &fts_dev_pm_ops,
+
+ },
+ .probe = fts_probe,
+ .remove = fts_remove,
+ .shutdown = fts_shutdown,
+ .id_table = fts_device_id,
+};
+
+module_i2c_driver(fts_i2c_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver");
+MODULE_AUTHOR("STMicroelectronics, Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/fts_ts.h b/drivers/input/touchscreen/fts_ts.h
new file mode 100644
index 000000000000..f83f2d71cd38
--- /dev/null
+++ b/drivers/input/touchscreen/fts_ts.h
@@ -0,0 +1,231 @@
+#ifndef _LINUX_FTS_TS_H_
+#define _LINUX_FTS_TS_H_
+
+#include <linux/device.h>
+#include <linux/i2c/fts.h>
+
+#define FIRMWARE_IC "fts_ic"
+
+#define FTS_MAX_FW_PATH 64
+
+#define FTS_TS_DRV_NAME "fts_touch"
+#define FTS_TS_DRV_VERSION "0132"
+
+#define STM_DEVICE_NAME "STM"
+
+#define FTS_ID0 0x39
+#define FTS_ID1 0x80
+#define FTS_ID2 0x6C
+
+#define FTS_DIGITAL_REV_1 0x01
+#define FTS_DIGITAL_REV_2 0x02
+#define FTS_FIFO_MAX 32
+#define FTS_EVENT_SIZE 8
+
+#define PRESSURE_MIN 0
+#define PRESSURE_MAX 127
+#define P70_PATCH_ADDR_START 0x00420000
+#define FINGER_MAX 10
+#define AREA_MIN PRESSURE_MIN
+#define AREA_MAX PRESSURE_MAX
+
+#define EVENTID_NO_EVENT 0x00
+#define EVENTID_ENTER_POINTER 0x03
+#define EVENTID_LEAVE_POINTER 0x04
+#define EVENTID_MOTION_POINTER 0x05
+#define EVENTID_HOVER_ENTER_POINTER 0x07
+#define EVENTID_HOVER_LEAVE_POINTER 0x08
+#define EVENTID_HOVER_MOTION_POINTER 0x09
+#define EVENTID_PROXIMITY_IN 0x0B
+#define EVENTID_PROXIMITY_OUT 0x0C
+#define EVENTID_MSKEY 0x0E
+#define EVENTID_ERROR 0x0F
+#define EVENTID_CONTROLLER_READY 0x10
+#define EVENTID_SLEEPOUT_CONTROLLER_READY 0x11
+#define EVENTID_RESULT_READ_REGISTER 0x12
+#define EVENTID_STATUS_EVENT 0x16
+#define EVENTID_INTERNAL_RELEASE_INFO 0x19
+#define EVENTID_EXTERNAL_RELEASE_INFO 0x1A
+
+#define EVENTID_FROM_STRING 0x80
+#define EVENTID_GESTURE 0x20
+
+#define EVENTID_SIDE_SCROLL 0x40
+#define EVENTID_SIDE_TOUCH_DEBUG 0xDB
+/* side touch event-id for debug, remove after f/w fixed */
+#define EVENTID_SIDE_TOUCH 0x0B
+
+#define STATUS_EVENT_MUTUAL_AUTOTUNE_DONE 0x01
+#define STATUS_EVENT_SELF_AUTOTUNE_DONE 0x42
+
+#define INT_ENABLE 0x41
+#define INT_DISABLE 0x00
+
+#define READ_STATUS 0x84
+#define READ_ONE_EVENT 0x85
+#define READ_ALL_EVENT 0x86
+
+#define SLEEPIN 0x90
+#define SLEEPOUT 0x91
+#define SENSEOFF 0x92
+#define SENSEON 0x93
+#define FTS_CMD_HOVER_OFF 0x94
+#define FTS_CMD_HOVER_ON 0x95
+
+#define FTS_CMD_MSKEY_AUTOTUNE 0x96
+
+#define FTS_CMD_KEY_SENSE_OFF 0x9A
+#define FTS_CMD_KEY_SENSE_ON 0x9B
+#define FTS_CMD_SET_FAST_GLOVE_MODE 0x9D
+
+#define FTS_CMD_MSHOVER_OFF 0x9E
+#define FTS_CMD_MSHOVER_ON 0x9F
+#define FTS_CMD_SET_NOR_GLOVE_MODE 0x9F
+
+#define FLUSHBUFFER 0xA1
+#define FORCECALIBRATION 0xA2
+#define CX_TUNNING 0xA3
+#define SELF_AUTO_TUNE 0xA4
+
+#define FTS_CMD_CHARGER_PLUGGED 0xA8
+#define FTS_CMD_CHARGER_UNPLUGGED 0xAB
+
+#define FTS_CMD_RELEASEINFO 0xAA
+#define FTS_CMD_STYLUS_OFF 0xAB
+#define FTS_CMD_STYLUS_ON 0xAC
+#define FTS_CMD_LOWPOWER_MODE 0xAD
+
+#define FTS_CMS_ENABLE_FEATURE 0xC1
+#define FTS_CMS_DISABLE_FEATURE 0xC2
+
+#define FTS_CMD_WRITE_PRAM 0xF0
+#define FTS_CMD_BURN_PROG_FLASH 0xF2
+#define FTS_CMD_ERASE_PROG_FLASH 0xF3
+#define FTS_CMD_READ_FLASH_STAT 0xF4
+#define FTS_CMD_UNLOCK_FLASH 0xF7
+#define FTS_CMD_SAVE_FWCONFIG 0xFB
+#define FTS_CMD_SAVE_CX_TUNING 0xFC
+
+#define FTS_CMD_FAST_SCAN 0x01
+#define FTS_CMD_SLOW_SCAN 0x02
+#define FTS_CMD_USLOW_SCAN 0x03
+
+#define REPORT_RATE_90HZ 0
+#define REPORT_RATE_60HZ 1
+#define REPORT_RATE_30HZ 2
+
+#define FTS_CMD_STRING_ACCESS 0xF000
+#define FTS_CMD_NOTIFY 0xC0
+
+#define FTS_RETRY_COUNT 10
+
+/* QUICK SHOT : Quick Camera Launching */
+#define FTS_STRING_EVENT_REAR_CAM (1 << 0)
+#define FTS_STRING_EVENT_FRONT_CAM (1 << 1)
+
+/* SCRUB : Display Watch, Event Status / Fast Access Event */
+#define FTS_STRING_EVENT_WATCH_STATUS (1 << 2)
+#define FTS_STRING_EVENT_FAST_ACCESS (1 << 3)
+#define FTS_STRING_EVENT_DIRECT_INDICATOR (1 << 3) | (1 << 2)
+
+#define FTS_SIDEGESTURE_EVENT_SINGLE_STROKE 0xE0
+#define FTS_SIDEGESTURE_EVENT_DOUBLE_STROKE 0xE1
+
+#define FTS_SIDETOUCH_EVENT_LONG_PRESS 0xBB
+#define FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD 0xED
+
+#define FTS_ENABLE 1
+#define FTS_DISABLE 0
+
+#define FTS_MODE_QUICK_SHOT (1 << 0)
+#define FTS_MODE_SCRUB (1 << 1)
+#define FTS_MODE_QUICK_APP_ACCESS (1 << 2)
+#define FTS_MODE_DIRECT_INDICATOR (1 << 3)
+
+#define TSP_BUF_SIZE 1024
+#define CMD_STR_LEN 32
+#define CMD_RESULT_STR_LEN 512
+#define CMD_PARAM_NUM 8
+
+#define FTS_LOWP_FLAG_QUICK_CAM (1 << 0)
+#define FTS_LOWP_FLAG_2ND_SCREEN (1 << 1)
+#define FTS_LOWP_FLAG_BLACK_UI (1 << 2)
+#define FTS_LOWP_FLAG_QUICK_APP_ACCESS (1 << 3)
+#define FTS_LOWP_FLAG_DIRECT_INDICATOR (1 << 4)
+#define FTS_LOWP_FLAG_TEMP_CMD (1 << 5)
+
+enum fts_error_return {
+ FTS_NOT_ERROR = 0,
+ FTS_ERROR_INVALID_CHIP_ID,
+ FTS_ERROR_INVALID_CHIP_VERSION_ID,
+ FTS_ERROR_INVALID_SW_VERSION,
+ FTS_ERROR_EVENT_ID,
+ FTS_ERROR_TIMEOUT,
+ FTS_ERROR_FW_UPDATE_FAIL,
+};
+
+#define RAW_MAX 3750
+
+/*
+ * struct fts_finger - Represents fingers.
+ * @ state: finger status (Event ID).
+ * @ mcount: moving counter for debug.
+ */
+struct fts_finger {
+ unsigned char state;
+ unsigned short mcount;
+ int lx;
+ int ly;
+};
+
+enum tsp_power_mode {
+ FTS_POWER_STATE_ACTIVE = 0,
+ FTS_POWER_STATE_LOWPOWER,
+ FTS_POWER_STATE_POWERDOWN,
+ FTS_POWER_STATE_DEEPSLEEP,
+};
+
+enum fts_cover_id {
+ FTS_FLIP_WALLET = 0,
+ FTS_VIEW_COVER,
+ FTS_COVER_NOTHING1,
+ FTS_VIEW_WIRELESS,
+ FTS_COVER_NOTHING2,
+ FTS_CHARGER_COVER,
+ FTS_VIEW_WALLET,
+ FTS_LED_COVER,
+ FTS_MONTBLANC_COVER = 100,
+};
+
+enum fts_customer_feature {
+ FTS_FEATURE_ORIENTATION_GESTURE = 1,
+ FTS_FEATURE_STYLUS,
+ FTS_FEATURE_QUICK_SHORT_CAMERA_ACCESS,
+ FTS_FEATURE_SIDE_GUSTURE,
+ FTS_FEATURE_COVER_GLASS,
+ FTS_FEATURE_COVER_WALLET,
+ FTS_FEATURE_COVER_LED,
+};
+
+struct fts_ts_info {
+ struct device *dev;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+
+ bool irq_enabled;
+ struct fts_i2c_platform_data *board;
+ bool enabled;
+
+ struct fts_finger finger[FINGER_MAX];
+
+ int touch_mode;
+ int fw_ver_ic;
+ int config_ver_ic;
+ int fw_main_ver_ic;
+
+ bool touch_stopped;
+ bool reinit_done;
+
+ unsigned char data[FTS_EVENT_SIZE * FTS_FIFO_MAX];
+};
+#endif /* LINUX_FTS_TS_H_ */