diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/input/touchscreen/melfas_ts.c | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 |
samsung update 1
Diffstat (limited to 'drivers/input/touchscreen/melfas_ts.c')
-rw-r--r-- | drivers/input/touchscreen/melfas_ts.c | 1782 |
1 files changed, 1782 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/melfas_ts.c b/drivers/input/touchscreen/melfas_ts.c new file mode 100644 index 0000000..4d09be4 --- /dev/null +++ b/drivers/input/touchscreen/melfas_ts.c @@ -0,0 +1,1782 @@ +/* drivers/input/touchscreen/melfas_ts.c + * + * Copyright (C) 2010 Melfas, Inc. + * + * 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. + * + */ + +#define SEC_TSP +#ifdef SEC_TSP +#define ENABLE_NOISE_TEST_MODE +#define TSP_FACTORY_TEST + +#endif + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/earlysuspend.h> +#include <linux/hrtimer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/melfas_ts.h> +#include <mach/cpufreq.h> +#include <mach/dev.h> + +#ifdef CONFIG_INPUT_FBSUSPEND +#include <linux/fb.h> +#endif + +#ifdef SEC_TSP +#include <linux/gpio.h> +#endif + +#define TS_MAX_Z_TOUCH 255 +#define TS_MAX_W_TOUCH 30 +#define TS_MAX_ANGLE 90 +#define TS_MIN_ANGLE -90 + +#define TS_MAX_X_COORD 720 +#define TS_MAX_Y_COORD 1280 + +#define FW_VERSION_4_8 0x74 +#define FW_VERSION_4_65 0x61 + +#define TS_READ_START_ADDR 0x0F +#define TS_READ_START_ADDR2 0x10 +#define TS_READ_VERSION_ADDR 0xF0 +#define TS_READ_CONF_VERSION 0xF5 +#define TSP_STATUS_ESD 0x0f + +#ifdef SEC_TSP +#define TS_THRESHOLD 0x05 +/* #define TS_READ_REGS_LEN 5 */ +#define TS_WRITE_REGS_LEN 16 +#endif + +#define TS_READ_REGS_LEN 88 +#define MELFAS_MAX_TOUCH 11 + +#define DEBUG_PRINT 0 +#define X_LINE 14 +#define Y_LINE 26 + +#define SET_DOWNLOAD_BY_GPIO 1 + +#define TSP_STATE_INACTIVE -1 +#define TSP_STATE_RELEASE 0 +#define TSP_STATE_PRESS 1 +#define TSP_STATE_MOVE 2 + +#if defined(CONFIG_SLP) || !(defined(CONFIG_EXYNOS4_CPUFREQ)\ + && defined(CONFIG_BUSFREQ_OPP)) +#define TOUCH_BOOSTER 0 +#else +#define TOUCH_BOOSTER 1 +#define TOUCH_BOOSTER_TIME 100 +#endif + +#undef CPURATE_DEBUG_FOR_TSP + +#ifdef CPURATE_DEBUG_FOR_TSP +#define DbgOut(_x_) printk _x_ +#else +#define DbgOut(_x_) +#endif + +#if SET_DOWNLOAD_BY_GPIO +#include "mms100_ISP_download.h" +#endif + +unsigned long saved_rate; +static bool lock_status; + +static int tsp_enabled; +int touch_is_pressed; + +struct device *sec_touchscreen; +static struct device *bus_dev; + +struct muti_touch_info { + int status; + int strength; + int width; + int posX; + int posY; + int angle; + int minor; + int major; + int palm; +}; + +struct melfas_ts_data { + uint16_t addr; + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct work; + struct melfas_tsi_platform_data *pdata; +#if TOUCH_BOOSTER + struct delayed_work dvfs_work; +#endif + uint32_t flags; + int (*power) (int on); + void (*input_event)(void *data); + void (*set_touch_i2c) (void); + void (*set_touch_i2c_to_gpio) (void); + struct early_suspend early_suspend; + bool mt_protocol_b; + bool enable_btn_touch; +#ifdef CONFIG_INPUT_FBSUSPEND + struct notifier_block fb_notif; + bool was_enabled_at_suspend; +#endif +#if defined(CONFIG_MACH_C1CTC) || defined(CONFIG_MACH_M0_CHNOPEN) ||\ + defined(CONFIG_MACH_M0_CMCC) || defined(CONFIG_MACH_M0_CTC) + int (*lcd_type)(void); +#endif +}; + +struct melfas_ts_data *ts_data; + +#ifdef SEC_TSP +extern struct class *sec_class; +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void melfas_ts_early_suspend(struct early_suspend *h); +static void melfas_ts_late_resume(struct early_suspend *h); +#endif + +#ifdef SEC_TSP +static int melfas_ts_suspend(struct i2c_client *client, pm_message_t mesg); +static int melfas_ts_resume(struct i2c_client *client); +#endif + +#if TOUCH_BOOSTER +static bool dvfs_lock_status = false; +static bool press_status = false; +#endif + +static struct muti_touch_info g_Mtouch_info[MELFAS_MAX_TOUCH]; +static int firm_status_data; + +static int melfas_init_panel(struct melfas_ts_data *ts) +{ + const char buf = 0x00; + int ret; + ret = i2c_master_send(ts->client, &buf, 1); + + ret = i2c_master_send(ts->client, &buf, 1); + + if (ret < 0) { + pr_err("%s : i2c_master_send() failed\n [%d]", + __func__, ret); + return 0; + } + + return true; +} + +#if TOUCH_BOOSTER +static void set_dvfs_off(struct work_struct *work) +{ + int ret; + if (dvfs_lock_status && !press_status) { + ret = dev_unlock(bus_dev, sec_touchscreen); + if (ret < 0) { + pr_err("%s: bus unlock failed(%d)\n", + __func__, __LINE__); + return; + } + exynos_cpufreq_lock_free(DVFS_LOCK_ID_TSP); + dvfs_lock_status = false; +#if DEBUG_PRINT + pr_info("[TSP] TSP DVFS mode exit "); +#endif + } +} +#endif + +#ifdef SEC_TSP +static int +melfas_i2c_read(struct i2c_client *client, u16 addr, u8 length, u8 * value) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg[2]; + + msg[0].addr = client->addr; + msg[0].flags = 0x00; + msg[0].len = 2; + msg[0].buf = (u8 *) & addr; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = (u8 *) value; + + if (i2c_transfer(adapter, msg, 2) == 2) + return 0; + else + return -EIO; + +} + +static int melfas_i2c_write(struct i2c_client *client, char *buf, int length) +{ + int i; + char data[TS_WRITE_REGS_LEN]; + + if (length > TS_WRITE_REGS_LEN) { + pr_err("[TSP] size error - %s\n", __func__); + return -EINVAL; + } + + for (i = 0; i < length; i++) + data[i] = *buf++; + + i = i2c_master_send(client, (char *)data, length); + + if (i == length) + return length; + else + return -EIO; +} + +static void release_all_fingers(struct melfas_ts_data *ts) +{ + int i, ret; + + printk(KERN_DEBUG "[TSP] %s\n", __func__); + for (i = 0; i < MELFAS_MAX_TOUCH; i++) { + g_Mtouch_info[i].status = TSP_STATE_INACTIVE; + g_Mtouch_info[i].strength = 0; + g_Mtouch_info[i].posX = 0; + g_Mtouch_info[i].posY = 0; + g_Mtouch_info[i].angle = 0; + g_Mtouch_info[i].major = 0; + g_Mtouch_info[i].minor = 0; + g_Mtouch_info[i].palm = 0; + + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 0); + } + input_sync(ts->input_dev); +#if TOUCH_BOOSTER + if (dvfs_lock_status) { + exynos_cpufreq_lock_free(DVFS_LOCK_ID_TSP); + ret = dev_unlock(bus_dev, sec_touchscreen); + if (ret < 0) { + pr_err("%s: bus unlock failed(%d)\n", + __func__, __LINE__); + return; + } + dvfs_lock_status = false; + press_status = false; +#if DEBUG_PRINT + pr_info("[TSP] %s : DVFS mode exit\n", __func__); +#endif + } +#endif +} + +static void firmware_update(struct melfas_ts_data *ts) +{ + char buf[4] = { 0, }; + int ret = 0; + u8 FW_VERSION; + +#if SET_DOWNLOAD_BY_GPIO + buf[0] = TS_READ_VERSION_ADDR; + ret = i2c_master_send(ts->client, buf, 1); + if (ret < 0) { + pr_err("[TSP]%s: i2c_master_send [%d]\n", __func__, + ret); + } + + ret = i2c_master_recv(ts->client, buf, 4); + if (ret < 0) { + pr_err("[TSP]%s: i2c_master_recv [%d]\n", __func__, + ret); + } + pr_info("[TSP] firmware_update"); + +#if defined(CONFIG_MACH_C1CTC) || defined(CONFIG_MACH_M0_CHNOPEN) ||\ + defined(CONFIG_MACH_M0_CTC) + if (ts->lcd_type() == 0x20) { + FW_VERSION = FW_VERSION_4_65; + pr_info("[TSP] lcd type is 4.8, FW_VER: 0x%x\n", buf[3]); + } else { + FW_VERSION = FW_VERSION_4_8; + pr_info("[TSP] lcd type is 4.65, FW_VER: 0x%x\n", buf[3]); + } +#elif defined(CONFIG_MACH_M0_CMCC) + if (ts->lcd_type() == 0x20) { + FW_VERSION = FW_VERSION_4_8; + pr_info("[TSP] lcd type is 4.8, FW_VER: 0x%x\n", buf[3]); + } else { + FW_VERSION = FW_VERSION_4_65; + pr_info("[TSP] lcd type is 4.65, FW_VER: 0x%x\n", buf[3]); + } +#else + +#if defined(CONFIG_MACH_M0) + if (system_rev == 2 || system_rev >= 5) +#else + if (system_rev == 2 || system_rev >= 4) +#endif + FW_VERSION = FW_VERSION_4_8; + else + FW_VERSION = FW_VERSION_4_65; +#endif + +#if defined(CONFIG_MACH_C1CTC) || defined(CONFIG_MACH_M0_CHNOPEN) ||\ + defined(CONFIG_MACH_M0_CMCC) || defined(CONFIG_MACH_M0_CTC) + if (buf[3] != FW_VERSION || buf[3] == 0xFF) { +#else + if (buf[3] < FW_VERSION || buf[3] == 0xFF) { +#endif + ts->set_touch_i2c_to_gpio(); + pr_err("[TSP]FW Upgrading... FW_VERSION: 0x%02x\n", + buf[3]); + + ret = mms100_download(ts->pdata); + + if (ret != 0) { + pr_err( + "[TSP]SET Download Fail - error code [%d]\n", + ret); + } + ts->set_touch_i2c(); + msleep(100); + ts->power(0); + msleep(200); + ts->power(1); + msleep(100); + } +#endif /* SET_DOWNLOAD_BY_GPIO */ +} + +static ssize_t +show_firm_version_phone(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 FW_VERSION; + + struct melfas_ts_data *ts = dev_get_drvdata(dev); + + if (!tsp_enabled) + return 0; + +#if defined(CONFIG_MACH_C1CTC) || defined(CONFIG_MACH_M0_CHNOPEN) ||\ + defined(CONFIG_MACH_M0_CMCC) || defined(CONFIG_MACH_M0_CTC) + if (ts->lcd_type() == 0x20) + FW_VERSION = FW_VERSION_4_65; + else + FW_VERSION = FW_VERSION_4_8; +#else + +#if defined(CONFIG_MACH_M0) + if (system_rev == 2 || system_rev >= 5) +#else + if (system_rev == 2 || system_rev >= 4) +#endif + FW_VERSION = FW_VERSION_4_8; + else + FW_VERSION = FW_VERSION_4_65; +#endif + + return sprintf(buf, "%#02x\n", FW_VERSION); +} + +static ssize_t +show_firm_version_panel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct melfas_ts_data *ts = dev_get_drvdata(dev); + u8 tsp_version_disp; + int ret; + char buff[4] = { TS_READ_VERSION_ADDR, 0, }; + + if (!tsp_enabled) + return 0; + ret = i2c_master_send(ts->client, (const char *)buff, 1); + if (ret < 0) { + pr_err("%s : i2c_master_send [%d]\n", __func__, ret); + } + + ret = i2c_master_recv(ts->client, buff, 4); + if (ret < 0) { + pr_err("%s : i2c_master_recv [%d]\n", __func__, ret); + } + tsp_version_disp = buff[3]; + + return sprintf(buf, "%#02x\n", tsp_version_disp); +} + +static ssize_t +show_firm_conf_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct melfas_ts_data *ts = dev_get_drvdata(dev); + u8 tsp_version_disp; + int ret; + char buff[4] = { TS_READ_CONF_VERSION, 0, }; + + if (!tsp_enabled) + return 0; + ret = i2c_master_send(ts->client, (const char *)buff, 1); + if (ret < 0) + pr_err("%s : i2c_master_send [%d]\n", __func__, ret); + + ret = i2c_master_recv(ts->client, buff, 4); + if (ret < 0) + pr_err("%s : i2c_master_recv [%d]\n", __func__, ret); + tsp_version_disp = buff[3]; + + return sprintf(buf, "%#02x\n", tsp_version_disp); +} + +static ssize_t +tsp_firm_update_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct melfas_ts_data *ts = dev_get_drvdata(dev); + int ret = 0; + + if (!tsp_enabled) + return 0; + + disable_irq(ts->client->irq); + + firm_status_data = 1; + + ts->set_touch_i2c_to_gpio(); + + pr_info("[TSP] ADB F/W UPDATE MODE ENTER!"); + if (*buf == 'S') + ret = mms100_download(ts->pdata); + else if (*buf == 'F') + ret = mms100_download_file(ts->pdata); + pr_info("[TSP] ADB F/W UPDATE MODE FROM %s END! %s", + (*buf == 'S' ? "BINARY" : "FILE"), (ret ? "fail" : "success")); + + firm_status_data = (ret ? 3 : 2); + + ts->set_touch_i2c(); + release_all_fingers(ts); + + ts->power(0); + msleep(200); + ts->power(1); + msleep(100); + + enable_irq(ts->client->irq); + + return count; +} + +static ssize_t +show_threshold(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct melfas_ts_data *ts = dev_get_drvdata(dev); + u8 threshold; + + if (!tsp_enabled) + return 0; + + melfas_i2c_read(ts->client, TS_THRESHOLD, 1, &threshold); + + return sprintf(buf, "%d\n", threshold); +} + +static ssize_t +show_firm_update_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + pr_info("[TSP] Enter firmware_status_show by Factory command\n"); + + if (!tsp_enabled) + return 0; + + if (firm_status_data == 1) { + count = sprintf(buf, "DOWNLOADING\n"); + } else if (firm_status_data == 2) { + count = sprintf(buf, "PASS\n"); + } else if (firm_status_data == 3) { + count = sprintf(buf, "FAIL\n"); + } else + count = sprintf(buf, "PASS\n"); + + return count; +} + +static DEVICE_ATTR(tsp_firm_version_phone, S_IRUGO, + show_firm_version_phone, NULL); +/* PHONE *//* firmware version resturn in phone driver version */ +static DEVICE_ATTR(tsp_firm_version_panel, S_IRUGO, + show_firm_version_panel, NULL); +/*PART*//* firmware version resturn in TSP panel version */ +static DEVICE_ATTR(tsp_firm_version_config, S_IRUGO, + show_firm_conf_version, NULL); +static DEVICE_ATTR(tsp_firm_update_status, S_IRUGO, + show_firm_update_status, NULL); +static DEVICE_ATTR(tsp_threshold, S_IRUGO, show_threshold, NULL); +static DEVICE_ATTR(tsp_firm_update, S_IWUSR | S_IWGRP, NULL, + tsp_firm_update_mode); + +static struct attribute *sec_touch_attributes[] = { + &dev_attr_tsp_firm_version_phone.attr, + &dev_attr_tsp_firm_version_panel.attr, + &dev_attr_tsp_firm_version_config.attr, + &dev_attr_tsp_firm_update_status.attr, + &dev_attr_tsp_threshold.attr, + &dev_attr_tsp_firm_update.attr, + NULL, +}; + +static struct attribute_group sec_touch_attr_group = { + .attrs = sec_touch_attributes, +}; +#endif + +#ifdef TSP_FACTORY_TEST +static bool debug_print = true; +static u16 index_reference; +static u16 inspection_data[X_LINE * Y_LINE] = { 0, }; +static u16 intensity_data[X_LINE * Y_LINE] = { 0, }; +static u16 reference_data[X_LINE * Y_LINE] = { 0, }; + +static ssize_t set_tsp_module_control(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct melfas_ts_data *ts = dev_get_drvdata(dev); + char write_buffer[2]; + + if (*buf == '0' && tsp_enabled == true) { + tsp_enabled = false; + release_all_fingers(ts); + ts->power(false); + msleep(200); + } else if (*buf == '1' && tsp_enabled == false) { + ts->power(true); + msleep(200); + melfas_i2c_write(ts->client, (char *)write_buffer, 2); + msleep(150); + tsp_enabled = true; + } else + pr_info("[TSP]tsp_power_control bad command!"); + return count; +} + +static int check_debug_data(struct melfas_ts_data *ts) +{ + u8 write_buffer[6]; + u8 read_buffer[2]; + int sensing_line, exciting_line; + int gpio = ts->pdata->gpio_int; + int count = 0; + + disable_irq(ts->client->irq); + /* enter the debug mode */ + write_buffer[0] = 0xB0; + write_buffer[1] = 0x1A; + write_buffer[2] = 0x0; + write_buffer[3] = 0x0; + write_buffer[4] = 0x0; + write_buffer[5] = 0x01; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + + /* wating for the interrupt */ + while (gpio_get_value(gpio)) { + pr_info("."); + udelay(100); + count++; + if (count == 100000) { + enable_irq(ts->client->irq); + return -1; + } + } + + if (debug_print) + pr_info("[TSP] read dummy\n"); + + /* read the dummy data */ + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + + if (debug_print) + pr_info("[TSP] read inspenction data\n"); + write_buffer[5] = 0x02; + for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) { + for (exciting_line = 0; exciting_line < Y_LINE;\ + exciting_line++) { + write_buffer[2] = exciting_line; + write_buffer[3] = sensing_line; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + reference_data[exciting_line + sensing_line * Y_LINE] = + (read_buffer[1] & 0xf) << 8 | read_buffer[0]; + } + } + pr_info("[TSP] Reading data end.\n"); + + msleep(200); + melfas_ts_suspend(ts->client, PMSG_SUSPEND); + + msleep(200); + melfas_ts_resume(ts->client); + + enable_irq(ts->client->irq); + return 0; +} + +static ssize_t +set_all_refer_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int status = 0; + int i; + struct melfas_ts_data *ts = dev_get_drvdata(dev); + + if (!tsp_enabled) + return 0; + + for (i = 0; i < 3; i++) { + if (!check_debug_data(ts)) { + status = 0; + break; + } else { + pr_info("[TSP] check_debug_data Error try=%d", i); + msleep(200); + melfas_ts_suspend(ts->client, PMSG_SUSPEND); + + msleep(200); + melfas_ts_resume(ts->client); + msleep(300); + status = 1; + } + } + if (!status) { + for (i = 0; i < X_LINE * Y_LINE; i++) { + /* out of range */ + if (reference_data[i] < 30) { + status = 1; + break; + } + + if (debug_print) { + if (0 == i % X_LINE) + pr_info("[TSP]\n"); + pr_info("[TSP] %5u ", reference_data[i]); + } + } + } else { + pr_info + ("[TSP] all_refer_show func & check_debug_data error[%d]", + status); + return sprintf(buf, "%u\n", status); + } + + pr_info("[TSP] all_refer_show func [%d]", status); + return sprintf(buf, "%u\n", status); +} + +static int index; + +static void check_intensity_data(struct melfas_ts_data *ts, int num) +{ + u8 write_buffer[6]; + u8 read_buffer[2]; + int sensing_line, exciting_line; + int gpio = ts->pdata->gpio_int; + int i = 0, ret; + + if (0 == reference_data[0]) { + disable_irq(ts->client->irq); + + /* enter the debug mode */ + write_buffer[0] = 0xB0; + write_buffer[1] = 0x1A; + write_buffer[2] = 0x0; + write_buffer[3] = 0x0; + write_buffer[4] = 0x0; + write_buffer[5] = 0x01; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + + /* wating for the interrupt*/ + while (gpio_get_value(gpio)) { + pr_info("."); + udelay(100); + } + + /* read the dummy data */ + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + + if (debug_print) + pr_info("[TSP] read the dummy data\n"); + + write_buffer[5] = 0x07; + for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) { + for (exciting_line = 0; exciting_line < Y_LINE; + exciting_line++) { + write_buffer[2] = exciting_line; + write_buffer[3] = sensing_line; + melfas_i2c_write(ts->client, + (char *)write_buffer, 6); + melfas_i2c_read(ts->client, 0xBF, 2, + read_buffer); + reference_data[exciting_line + + sensing_line * Y_LINE] = + (read_buffer[1] & 0xf) << 8 + | read_buffer[0]; + } + } + msleep(200); + melfas_ts_suspend(ts->client, PMSG_SUSPEND); + + msleep(200); + melfas_ts_resume(ts->client); + + msleep(100); + enable_irq(ts->client->irq); + msleep(100); + } + + disable_irq(ts->client->irq); + release_all_fingers(ts); + + write_buffer[0] = 0xB0; + write_buffer[1] = 0x1A; + write_buffer[2] = 0x0; + write_buffer[3] = 0x0; + write_buffer[4] = 0x0; + write_buffer[5] = 0x04; + for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) { + for (exciting_line = 0; exciting_line < Y_LINE;\ + exciting_line++) { + write_buffer[2] = exciting_line; + write_buffer[3] = sensing_line; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + intensity_data[exciting_line + sensing_line * Y_LINE] = + (read_buffer[1] & 0xf) << 8 | read_buffer[0]; + } + } + enable_irq(ts->client->irq); +} + +#define SET_SHOW_FN(name, fn, format, ...) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct melfas_ts_data *ts = dev_get_drvdata(dev); \ + if ((NULL == ts) || !tsp_enabled) { \ + printk(KERN_DEBUG "[TSP] drvdata is not set\n");\ + return sprintf(buf, "\n"); \ + } \ + fn; \ + return sprintf(buf, format "\n", ## __VA_ARGS__); \ +} + +#define ATTR_SHOW_REF(num, node) \ +SET_SHOW_FN(set_refer##num, \ + check_intensity_data(ts, num), \ + "%u", node) + +#define ATTR_SHOW_INTENSITY(num, node) \ +SET_SHOW_FN(set_intensity##num, , \ + "%u", node) + +ATTR_SHOW_REF(0, reference_data[28]); +ATTR_SHOW_REF(1, reference_data[288]); +ATTR_SHOW_REF(2, reference_data[194]); +ATTR_SHOW_REF(3, reference_data[49]); +ATTR_SHOW_REF(4, reference_data[309]); + +ATTR_SHOW_INTENSITY(0, intensity_data[28]); +ATTR_SHOW_INTENSITY(1, intensity_data[288]); +ATTR_SHOW_INTENSITY(2, intensity_data[194]); +ATTR_SHOW_INTENSITY(3, intensity_data[49]); +ATTR_SHOW_INTENSITY(4, intensity_data[309]); + + +static ssize_t show_tsp_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", MELFAS_TS_NAME); +} +static ssize_t show_tsp_x_line_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", X_LINE); +} + +static ssize_t show_tsp_y_line_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", Y_LINE); +} +static int atoi(const char *str) +{ + int result = 0; + int count = 0; + if (str == NULL) + return -1; + while (str[count] && str[count] >= '0' && str[count] <= '9') { + result = result * 10 + str[count] - '0'; + ++count; + } + return result; +} +static ssize_t set_debug_data1(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + + struct melfas_ts_data *ts = dev_get_drvdata(dev); + + u8 write_buffer[6]; + u8 read_buffer[2]; + int sensing_line, exciting_line; + int gpio = ts->pdata->gpio_int; + +/* if (!ts->tsp_status) { + pr_info("[TSP] call set_debug_data1 but TSP status OFF!"); + return count; + } +*/ + disable_irq(ts->client->irq); + + /* enter the debug mode */ + write_buffer[0] = 0xB0; + write_buffer[1] = 0x1A; + write_buffer[2] = 0x0; + write_buffer[3] = 0x0; + write_buffer[4] = 0x0; + write_buffer[5] = 0x01; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + + /* wating for the interrupt*/ + while (gpio_get_value(gpio)) { + pr_info("."); + udelay(100); + } + + /* read the dummy data */ + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + + pr_info("[TSP] read Reference data\n"); + write_buffer[5] = 0x03; + for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) { + for (exciting_line = 0; exciting_line < Y_LINE; + exciting_line++) { + write_buffer[2] = exciting_line; + write_buffer[3] = sensing_line; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + melfas_i2c_read(ts->client, 0xA8, 2, read_buffer); + reference_data[exciting_line + sensing_line * Y_LINE] = + (read_buffer[1] & 0xf) << 8 | read_buffer[0]; + } + } + + ts->power(0); + mdelay(200); + ts->power(1); + + msleep(200); + enable_irq(ts->client->irq); + return count; +} + +static ssize_t set_debug_data2(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + + struct melfas_ts_data *ts = dev_get_drvdata(dev); + + u8 write_buffer[6]; + u8 read_buffer[2]; + int sensing_line, exciting_line; + int gpio = ts->pdata->gpio_int; + +/* if (!ts->tsp_status) { + pr_info("[TSP] call set_debug_data2 but TSP status OFF!"); + return count; + } +*/ + disable_irq(ts->client->irq); + + /* enter the debug mode */ + write_buffer[0] = 0xB0; + write_buffer[1] = 0x1A; + write_buffer[2] = 0x0; + write_buffer[3] = 0x0; + write_buffer[4] = 0x0; + write_buffer[5] = 0x01; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + + /* wating for the interrupt*/ + while (gpio_get_value(gpio)) { + pr_info("."); + udelay(100); + } + + /* read the dummy data */ + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + + pr_info("[TSP] read Inspection data\n"); + write_buffer[5] = 0x02; + for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) { + for (exciting_line = 0; exciting_line < Y_LINE; + exciting_line++) { + write_buffer[2] = exciting_line; + write_buffer[3] = sensing_line; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + inspection_data[exciting_line + + sensing_line * Y_LINE] = + (read_buffer[1] & 0xf) << 8 | read_buffer[0]; + } + } + ts->power(0); + mdelay(200); + ts->power(1); + + msleep(200); + enable_irq(ts->client->irq); + return count; +} + +static ssize_t set_debug_data3(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + + struct melfas_ts_data *ts = dev_get_drvdata(dev); + + u8 write_buffer[6]; + u8 read_buffer[2]; + int sensing_line, exciting_line; + int gpio = ts->pdata->gpio_int; + +/* if (!ts->tsp_status) { + pr_info("[TSP] call set_debug_data3 but TSP status OFF!"); + return count; + } +*/ + pr_info("[TSP] read lntensity data\n"); + + disable_irq(ts->client->irq); + + /* enter the debug mode */ + write_buffer[0] = 0xB0; + write_buffer[1] = 0x1A; + write_buffer[2] = 0x0; + write_buffer[3] = 0x0; + write_buffer[4] = 0x0; + write_buffer[5] = 0x01; + + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + + /* wating for the interrupt*/ + while (gpio_get_value(gpio)) { + pr_info("."); + udelay(100); + } + + /* read the dummy data */ + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + + pr_info("[TSP] read Inspection data\n"); + write_buffer[5] = 0x04; + + for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) { + for (exciting_line = 0; exciting_line < Y_LINE; + exciting_line++) { + write_buffer[2] = exciting_line; + write_buffer[3] = sensing_line; + melfas_i2c_write(ts->client, (char *)write_buffer, 6); + melfas_i2c_read(ts->client, 0xBF, 2, read_buffer); + intensity_data[exciting_line + sensing_line * Y_LINE] = + (read_buffer[1] & 0xf) << 8 | read_buffer[0]; + } + } + ts->power(0); + mdelay(200); + ts->power(1); + + msleep(200); + enable_irq(ts->client->irq); + return count; +} +static ssize_t set_index_reference(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + index_reference = atoi(buf); + if (index_reference < 0 || index_reference >= X_LINE*Y_LINE){ + pr_info("[TSP] input bad index_reference value"); + return -1; + }else{ + pr_info("[TSP]index_reference =%d ",index_reference); + return count; + } +} +static ssize_t show_reference_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i = 0; + if (debug_print) { + for (i = 0; i < X_LINE*Y_LINE; i++) { + if (0 == i % Y_LINE) + pr_info("\n"); + pr_info("%4u", reference_data[i]); + } + } + return sprintf(buf, "%d\n", reference_data[index_reference]); +} +static ssize_t show_inspection_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i = 0; + if (debug_print) { + for (i = 0; i < X_LINE*Y_LINE; i++) { + if (0 == i % Y_LINE) + pr_info("\n"); + pr_info("%5u", inspection_data[i]); + } + } + return sprintf(buf, "%d\n", inspection_data[index_reference]); +} +static ssize_t show_intensity_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i = 0; + if (debug_print) { + for (i = 0; i < X_LINE*Y_LINE; i++) { + if (0 == i % Y_LINE) + pr_info("\n"); + pr_info("%4u", intensity_data[i]); + } + } + return sprintf(buf, "%d\n", intensity_data[index_reference]); +} + +static DEVICE_ATTR(set_all_refer, S_IRUGO, set_all_refer_mode_show, NULL); +static DEVICE_ATTR(set_refer0, S_IRUGO, show_set_refer0, NULL); +static DEVICE_ATTR(set_delta0, S_IRUGO, show_set_intensity0, NULL); +static DEVICE_ATTR(set_refer1, S_IRUGO, show_set_refer1, NULL); +static DEVICE_ATTR(set_delta1, S_IRUGO, show_set_intensity1, NULL); +static DEVICE_ATTR(set_refer2, S_IRUGO, show_set_refer2, NULL); +static DEVICE_ATTR(set_delta2, S_IRUGO, show_set_intensity2, NULL); +static DEVICE_ATTR(set_refer3, S_IRUGO, show_set_refer3, NULL); +static DEVICE_ATTR(set_delta3, S_IRUGO, show_set_intensity3, NULL); +static DEVICE_ATTR(set_refer4, S_IRUGO, show_set_refer4, NULL); +static DEVICE_ATTR(set_delta4, S_IRUGO, show_set_intensity4, NULL); +static DEVICE_ATTR(set_threshold, S_IRUGO, show_threshold, NULL); +/* touch threshold return */ +static DEVICE_ATTR(tsp_info, S_IRUGO, show_tsp_info, NULL); +static DEVICE_ATTR(tsp_x_line, S_IRUGO, show_tsp_x_line_info, NULL); +static DEVICE_ATTR(tsp_y_line, S_IRUGO, show_tsp_y_line_info, NULL); +static DEVICE_ATTR(tsp_module, S_IWUSR | S_IWGRP, NULL, set_tsp_module_control); +static DEVICE_ATTR(set_debug_data1, + S_IWUSR | S_IWGRP | S_IRUGO, NULL, set_debug_data1); +static DEVICE_ATTR(set_debug_data2, + S_IWUSR | S_IWGRP | S_IRUGO, NULL, set_debug_data2); +static DEVICE_ATTR(set_debug_data3, + S_IWUSR | S_IWGRP | S_IRUGO, NULL, set_debug_data3); +static DEVICE_ATTR(set_index_ref, S_IWUSR + | S_IWGRP, NULL, set_index_reference); +static DEVICE_ATTR(show_reference_info, S_IRUGO, show_reference_info, NULL); +static DEVICE_ATTR(show_inspection_info, S_IRUGO, show_inspection_info, NULL); +static DEVICE_ATTR(show_intensity_info, S_IRUGO, show_intensity_info, NULL); + + + +static struct attribute *sec_touch_facotry_attributes[] = { + &dev_attr_set_all_refer.attr, + &dev_attr_set_refer0.attr, + &dev_attr_set_delta0.attr, + &dev_attr_set_refer1.attr, + &dev_attr_set_delta1.attr, + &dev_attr_set_refer2.attr, + &dev_attr_set_delta2.attr, + &dev_attr_set_refer3.attr, + &dev_attr_set_delta3.attr, + &dev_attr_set_refer4.attr, + &dev_attr_set_delta4.attr, + &dev_attr_set_threshold.attr, + &dev_attr_tsp_info.attr, + &dev_attr_tsp_x_line.attr, + &dev_attr_tsp_y_line.attr, + &dev_attr_tsp_module.attr, + &dev_attr_set_debug_data1.attr, + &dev_attr_set_debug_data2.attr, + &dev_attr_set_debug_data3.attr, + &dev_attr_set_index_ref.attr, + &dev_attr_show_reference_info.attr, + &dev_attr_show_inspection_info.attr, + &dev_attr_show_intensity_info.attr, + + NULL, +}; + +static struct attribute_group sec_touch_factory_attr_group = { + .attrs = sec_touch_facotry_attributes, +}; +#endif + +void TSP_force_released(void) +{ + pr_err("%s satrt!\n", __func__); + + if (tsp_enabled == false) { + pr_err("[TSP] Disabled\n"); + return; + } + release_all_fingers(ts_data); + + touch_is_pressed = 0; +} +EXPORT_SYMBOL(TSP_force_released); + +#ifdef CONFIG_INPUT_FBSUSPEND +static int +melfas_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *fb_evdata) +{ + struct melfas_ts_data *data; + struct fb_event *evdata = fb_evdata; + int blank; + + /* If we aren't interested in this event, skip it immediately ... */ + if (event != FB_EVENT_BLANK) + return 0; + + data = container_of(self, struct melfas_ts_data, fb_notif); + blank = *(int *)evdata->data; + + switch (blank) { + case FB_BLANK_UNBLANK: + if (tsp_enabled == 0) { + data->power(true); + enable_irq(data->client->irq); + tsp_enabled = 1; + } else { + pr_err("[TSP] touchscreen already on\n"); + } + break; + case FB_BLANK_POWERDOWN: + TSP_force_released(); + if (tsp_enabled == 1) { + disable_irq(data->client->irq); + data->power(false); + tsp_enabled = 0; + } else { + pr_err("[TSP] touchscreen already off\n"); + } + break; + default: + break; + } + return 0; +} + +static int tsp_register_fb(struct melfas_ts_data *ts) +{ + memset(&ts->fb_notif, 0, sizeof(ts->fb_notif)); + ts->fb_notif.notifier_call = melfas_fb_notifier_callback; + return fb_register_client(&ts->fb_notif); +} + +static void tsp_unregister_fb(struct melfas_ts_data *ts) +{ + fb_unregister_client(&ts->fb_notif); +} +#endif + +static void melfas_ts_get_data(struct work_struct *work) +{ + struct melfas_ts_data *ts = + container_of(work, struct melfas_ts_data, work); + int ret = 0, i; + int _touch_is_pressed; + u8 read_num = 0, FingerID = 0; + u8 buf[TS_READ_REGS_LEN]; + int pre_status = 0; + + ret = melfas_i2c_read(ts->client, + TS_READ_START_ADDR, 1, &read_num); + if (ret < 0) { + pr_err("%s: i2c failed(%d)\n", __func__, __LINE__); + return ; + } + + if (read_num > 0) { + ret = melfas_i2c_read(ts->client, + TS_READ_START_ADDR2, read_num, buf); + if (ret < 0) { + pr_err("%s: i2c failed(%d)\n", \ + __func__, __LINE__); + return ; + } + + switch (buf[0]) { + case TSP_STATUS_ESD: + printk(KERN_DEBUG "[TSP] ESD protection.\n"); + disable_irq_nosync(ts->client->irq); + ts->power(0); + TSP_force_released(); + mdelay(200); + ts->power(1); + mdelay(200); + enable_irq(ts->client->irq); + return ; + + default: + break; + } + + if (read_num % 8 != 0) { + pr_err("[TSP] incorrect read_num %d\n", read_num); + read_num = (read_num / 8) * 8; + } + + for (i = 0; i < read_num; i = i + 8) { + FingerID = (buf[i] & 0x0F) - 1; + g_Mtouch_info[FingerID].posX = + (uint16_t) (buf[i + 1] & 0x0F) << 8 | buf[i + 2]; + g_Mtouch_info[FingerID].posY = + (uint16_t) (buf[i + 1] & 0xF0) << 4 | buf[i + 3]; +#if !defined(CONFIG_MACH_C1) && !defined(CONFIG_MACH_C1VZW) && \ + !defined(CONFIG_MACH_M0) && \ + !defined(CONFIG_MACH_SLP_PQ) && \ + !defined(CONFIG_MACH_SLP_PQ_LTE) && \ + !defined(CONFIG_MACH_M3) + g_Mtouch_info[FingerID].posX = + 720 - g_Mtouch_info[FingerID].posX; + g_Mtouch_info[FingerID].posY = + 1280 - g_Mtouch_info[FingerID].posY; +#endif + g_Mtouch_info[FingerID].width = buf[i + 4]; + g_Mtouch_info[FingerID].angle = + (buf[i + 5] >= + 127) ? (-(256 - buf[i + 5])) : buf[i + 5]; + g_Mtouch_info[FingerID].major = buf[i + 6]; + g_Mtouch_info[FingerID].minor = buf[i + 7]; + g_Mtouch_info[FingerID].palm = (buf[i] & 0x10) >> 4; + pre_status = g_Mtouch_info[FingerID].status; + if ((buf[i] & 0x80) == 0) { + g_Mtouch_info[FingerID].strength = 0; + g_Mtouch_info[FingerID].status = + TSP_STATE_RELEASE; + } else { + g_Mtouch_info[FingerID].strength = buf[i + 4]; + + if (TSP_STATE_PRESS == \ + g_Mtouch_info[FingerID].status) + g_Mtouch_info[FingerID].status = + TSP_STATE_MOVE; + else + g_Mtouch_info[FingerID].status = + TSP_STATE_PRESS; + } + /*g_Mtouch_info[FingerID].width = buf[i + 5];*/ + } + + } + + _touch_is_pressed = 0; + if (ret < 0) { + pr_err("%s: i2c failed(%d)\n", __func__, __LINE__); + return; + } + + for (i = 0; i < MELFAS_MAX_TOUCH; i++) { + if (TSP_STATE_INACTIVE == g_Mtouch_info[i].status) + continue; + + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, + !!g_Mtouch_info[i].strength); + + if (TSP_STATE_RELEASE == g_Mtouch_info[i].status) { + g_Mtouch_info[i].status = TSP_STATE_INACTIVE; + printk(KERN_DEBUG "[TSP] %d released\n", i); + continue; + } + + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + g_Mtouch_info[i].posX); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + g_Mtouch_info[i].posY); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + g_Mtouch_info[i].major); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, + g_Mtouch_info[i].minor); + + if (ts->mt_protocol_b) + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + g_Mtouch_info[i].width); + else { + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + g_Mtouch_info[i].width); + input_report_key(ts->input_dev, BTN_TOUCH, + !!g_Mtouch_info[i].strength); + if (pre_status == -1) + printk(KERN_DEBUG "[TSP] %d (%d, %d) %d\n", + i, g_Mtouch_info[i].posX, + g_Mtouch_info[i].posY, + g_Mtouch_info[i].major); + +/* if ((TSP_STATE_PRESS == g_Mtouch_info[i].status)) + printk(KERN_DEBUG "[TSP] %d (%d, %d) %d\n", + i, g_Mtouch_info[i].posX, + g_Mtouch_info[i].posY, + g_Mtouch_info[i].major); + else if (TSP_STATE_RELEASE == g_Mtouch_info[i].status) + printk(KERN_DEBUG "[TSP] %d released\n", i); */ + } + + input_report_abs(ts->input_dev, ABS_MT_ANGLE, + g_Mtouch_info[i].angle); + input_report_abs(ts->input_dev, ABS_MT_PALM, + g_Mtouch_info[i].palm); +#if 0 + printk(KERN_DEBUG + "[TSP]melfas_ts_get_data: Touch ID: %d, " + "State : %d, x: %d, y: %d, major: %d " + "minor: %d w: %d a: %d p: %d\n", + i, (g_Mtouch_info[i].strength > 0), + g_Mtouch_info[i].posX, g_Mtouch_info[i].posY, + g_Mtouch_info[i].major, g_Mtouch_info[i].minor, + g_Mtouch_info[i].width, g_Mtouch_info[i].angle, + g_Mtouch_info[i].palm); +#endif + if (g_Mtouch_info[i].strength > 0) + _touch_is_pressed = 1; + + } + + input_sync(ts->input_dev); + touch_is_pressed = _touch_is_pressed; + +/* if (touch_is_pressed > 0) { *//* when touch is pressed. */ +/* if (lock_status == 0) { + lock_status = 1; + } + } else { *//* when touch is released. */ +/* if (read_num > 0) { + lock_status = 0; + } + }*/ + +#if TOUCH_BOOSTER + if (touch_is_pressed) + press_status = true; + else + press_status = false; + + cancel_delayed_work(&ts->dvfs_work); + schedule_delayed_work(&ts->dvfs_work,\ + msecs_to_jiffies(TOUCH_BOOSTER_TIME)); + + if (!dvfs_lock_status && press_status) { + ret = exynos_cpufreq_lock(DVFS_LOCK_ID_TSP, L7); + if (ret < 0) { + pr_err("%s: cpufreq lock failed(%d)\n", + __func__, __LINE__); + return; + } + + ret = dev_lock(bus_dev, sec_touchscreen, 267160); + if (ret < 0) { + pr_err("%s: bus lock failed(%d)\n", + __func__, __LINE__); + return; + } + dvfs_lock_status = true; +#if DEBUG_PRINT + printk(KERN_DEBUG"[TSP] TSP DVFS mode enter"); +#endif + } +#endif + +#if DEBUG_PRINT + if (ts->mt_protocol_b) + pr_err("melfas_ts_get_data: touch_is_pressed=%d\n", + touch_is_pressed); +#endif +} + +static irqreturn_t melfas_ts_irq_handler(int irq, void *handle) +{ + struct melfas_ts_data *ts = (struct melfas_ts_data *)handle; +#if DEBUG_PRINT + pr_err("melfas_ts_irq_handler\n"); +#endif + + if (ts->input_event) + ts->input_event(ts); + + melfas_ts_get_data(&ts->work); + + return IRQ_HANDLED; +} + +static int +melfas_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct melfas_ts_data *ts; + struct melfas_tsi_platform_data *data = client->dev.platform_data; +#ifdef SEC_TSP +/* struct device *sec_touchscreen; */ + struct device *tsp_noise_test; +#endif + int ret = 0, i; + char buf[4] = { 0, }; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s: need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kmalloc(sizeof(struct melfas_ts_data), GFP_KERNEL); + if (ts == NULL) { + pr_err("%s: failed to create a state of melfas-ts\n", + __func__); + ret = -ENOMEM; + goto err_alloc_data_failed; + } + ts_data = ts; + ts->pdata = client->dev.platform_data; + data = client->dev.platform_data; + ts->power = data->power; + ts->mt_protocol_b = data->mt_protocol_b; + ts->enable_btn_touch = data->enable_btn_touch; + ts->set_touch_i2c = data->set_touch_i2c; + ts->set_touch_i2c_to_gpio = data->set_touch_i2c_to_gpio; + ts->input_event = data->input_event; + +#if defined(CONFIG_MACH_C1CTC) || defined(CONFIG_MACH_M0_CHNOPEN) ||\ + defined(CONFIG_MACH_M0_CMCC) || defined(CONFIG_MACH_M0_CTC) + ts->lcd_type = data->lcd_type; +#endif + + ts->power(0); + ts->power(true); + msleep(100); + ts->client = client; + i2c_set_clientdata(client, ts); + ret = i2c_master_send(ts->client, buf, 1); + if (ret < 0) { +#if DEBUG_PRINT + pr_err("%s: i2c_master_send() [%d], Add[%d]\n", + __func__, ret, ts->client->addr); +#endif + } + + firmware_update(ts); + + ts->input_dev = input_allocate_device(); + if (!ts->input_dev) { + pr_err("%s: Not enough memory\n", __func__); + ret = -ENOMEM; + goto err_input_dev_alloc_failed; + } + + ts->input_dev->name = "sec_touchscreen"; + __set_bit(EV_ABS, ts->input_dev->evbit); + __set_bit(EV_KEY, ts->input_dev->evbit); + __set_bit(BTN_TOUCH, ts->input_dev->keybit); + + if (ts->enable_btn_touch) { + input_set_abs_params(ts->input_dev, ABS_X, 0, + TS_MAX_X_COORD, 0, 0); + input_set_abs_params(ts->input_dev, ABS_Y, 0, + TS_MAX_Y_COORD, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, + TS_MAX_X_COORD, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, + TS_MAX_Y_COORD, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, + TS_MAX_Z_TOUCH, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, + TS_MAX_W_TOUCH, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_ANGLE, + TS_MIN_ANGLE, TS_MAX_ANGLE, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PALM, + 0, 1, 0, 0); + input_mt_init_slots(ts->input_dev, MELFAS_MAX_TOUCH); + } else { + input_mt_init_slots(ts->input_dev, + MELFAS_MAX_TOUCH - 1); + input_set_abs_params(ts->input_dev, + ABS_MT_POSITION_X, 0, TS_MAX_X_COORD - 1, 0, 0); + input_set_abs_params(ts->input_dev, + ABS_MT_POSITION_Y, 0, TS_MAX_Y_COORD - 1, 0, 0); + input_set_abs_params(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 0, TS_MAX_Z_TOUCH, 0, 0); + input_set_abs_params(ts->input_dev, + ABS_MT_TOUCH_MINOR, 0, TS_MAX_Z_TOUCH, 0, 0); + input_set_abs_params(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 0, TS_MAX_W_TOUCH, 0, 0); + input_set_abs_params(ts->input_dev, + ABS_MT_ANGLE, TS_MIN_ANGLE, TS_MAX_ANGLE, 0, 0); + input_set_abs_params(ts->input_dev, + ABS_MT_PALM, 0, 1, 0, 0); + + __set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); + __set_bit(EV_SYN, ts->input_dev->evbit); + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + } + + ret = input_register_device(ts->input_dev); + if (ret) { + pr_err("%s: Failed to register device\n", __func__); + ret = -ENOMEM; + goto err_input_register_device_failed; + } + +#if TOUCH_BOOSTER + INIT_DELAYED_WORK(&ts->dvfs_work, set_dvfs_off); + bus_dev = dev_get("exynos-busfreq"); +#endif + + if (ts->client->irq) { +#if DEBUG_PRINT + pr_err("%s: trying to request irq: %s-%d\n", __func__, + ts->client->name, ts->client->irq); +#endif + ret = + request_threaded_irq(client->irq, NULL, + melfas_ts_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + ts->client->name, ts); + if (ret > 0) { + pr_err("%s: Can't allocate irq %d, ret %d\n", + __func__, ts->client->irq, ret); + ret = -EBUSY; + goto err_request_irq; + } + } + + for (i = 0; i < MELFAS_MAX_TOUCH; i++) /* _SUPPORT_MULTITOUCH_ */ + g_Mtouch_info[i].status = TSP_STATE_INACTIVE; + + tsp_enabled = true; + +#if DEBUG_PRINT + pr_err("%s: succeed to register input device\n", __func__); +#endif + +#if 1 /* 0//SEC_TSP */ + sec_touchscreen = + device_create(sec_class, NULL, 0, ts, "sec_touchscreen"); + if (IS_ERR(sec_touchscreen)) + pr_err("[TSP] Failed to create device for the sysfs\n"); + + ret = sysfs_create_group(&sec_touchscreen->kobj, \ + &sec_touch_attr_group); + if (ret) + pr_err("[TSP] Failed to create sysfs group\n"); +#endif + +#if 1 /* 0//TSP_FACTORY_TEST */ + tsp_noise_test = + device_create(sec_class, NULL, 0, ts, "tsp_noise_test"); + if (IS_ERR(tsp_noise_test)) + pr_err("[TSP] Failed to create device for the sysfs\n"); + + ret = + sysfs_create_group(&tsp_noise_test->kobj, + &sec_touch_factory_attr_group); + if (ret) + pr_err("[TSP] Failed to create sysfs group\n"); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = melfas_ts_early_suspend; + ts->early_suspend.resume = melfas_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + +#ifdef CONFIG_INPUT_FBSUSPEND + ret = tsp_register_fb(ts); + if (ret) + pr_err("[TSP] Failed to register fb\n"); +#endif + +#if DEBUG_PRINT + pr_info("%s: Start touchscreen. name: %s, irq: %d\n", __func__, + ts->client->name, ts->client->irq); +#endif + return 0; + + err_request_irq: + pr_err("melfas-ts: err_request_irq failed\n"); + err_input_register_device_failed: + pr_err("melfas-ts: err_input_register_device failed\n"); + input_free_device(ts->input_dev); + err_input_dev_alloc_failed: + pr_err("melfas-ts: err_input_dev_alloc failed\n"); + kfree(ts); + err_alloc_data_failed: + pr_err("melfas-ts: err_alloc_data failed_\n"); + err_check_functionality_failed: + pr_err("melfas-ts: err_check_functionality failed_\n"); + + return ret; +} + +static int melfas_ts_remove(struct i2c_client *client) +{ + struct melfas_ts_data *ts = i2c_get_clientdata(client); + + unregister_early_suspend(&ts->early_suspend); +#ifdef CONFIG_INPUT_FBSUSPEND + tsp_unregister_fb(ts); +#endif + free_irq(client->irq, ts); + ts->power(false); + input_unregister_device(ts->input_dev); + kfree(ts); + return 0; +} + +static int melfas_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct melfas_ts_data *ts = i2c_get_clientdata(client); + if (!tsp_enabled) { +#ifdef CONFIG_INPUT_FBSUSPEND + ts->was_enabled_at_suspend = false; +#endif + return 0; + } + +#ifdef CONFIG_INPUT_FBSUSPEND + ts->was_enabled_at_suspend = true; +#endif + + disable_irq(client->irq); + tsp_enabled = false; + release_all_fingers(ts); + ts->power(false); + return 0; +} + +static int melfas_ts_resume(struct i2c_client *client) +{ + struct melfas_ts_data *ts = i2c_get_clientdata(client); + if (tsp_enabled) + return 0; +#ifdef CONFIG_INPUT_FBSUSPEND + if (!ts->was_enabled_at_suspend) + return 0; +#endif + + ts->power(true); + msleep(100); + + /* Because irq_type by EXT_INTxCON register is changed to low_level + * after wakeup, irq_type set to falling edge interrupt again. + */ + irq_set_irq_type(client->irq, IRQ_TYPE_EDGE_FALLING); + enable_irq(client->irq); /* scl wave */ + tsp_enabled = true; + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void melfas_ts_early_suspend(struct early_suspend *h) +{ + struct melfas_ts_data *ts; + + ts = container_of(h, struct melfas_ts_data, early_suspend); + melfas_ts_suspend(ts->client, PMSG_SUSPEND); +} + +static void melfas_ts_late_resume(struct early_suspend *h) +{ + struct melfas_ts_data *ts; + ts = container_of(h, struct melfas_ts_data, early_suspend); + melfas_ts_resume(ts->client); +} +#endif + +static const struct i2c_device_id melfas_ts_id[] = { + {MELFAS_TS_NAME, 0}, + {} +}; + +static struct i2c_driver melfas_ts_driver = { + .driver = { + .name = MELFAS_TS_NAME, + }, + .id_table = melfas_ts_id, + .probe = melfas_ts_probe, + .remove = __devexit_p(melfas_ts_remove), +#if !defined(CONFIG_HAS_EARLYSUSPEND) + .suspend = melfas_ts_suspend, + .resume = melfas_ts_resume, +#endif +}; + +#ifdef CONFIG_BATTERY_SEC +extern unsigned int is_lpcharging_state(void); +#endif + +static int __devinit melfas_ts_init(void) +{ +#ifdef CONFIG_BATTERY_SEC + if (is_lpcharging_state()) { + pr_info("%s : LPM Charging Mode! return 0\n", __func__); + return 0; + } +#endif + + return i2c_add_driver(&melfas_ts_driver); +} + +static void __exit melfas_ts_exit(void) +{ + i2c_del_driver(&melfas_ts_driver); +} + +MODULE_DESCRIPTION("Driver for Melfas MTSI Touchscreen Controller"); +MODULE_AUTHOR("MinSang, Kim <kimms@melfas.com>"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); + +module_init(melfas_ts_init); +module_exit(melfas_ts_exit); |