--- a/drivers/input/misc/capella_cm3602.c
+++ b/drivers/input/misc/capella_cm3602.c
@@ -31,13 +31,9 @@
struct wake_lock proximity_wake_lock;
-static void ps_irq_do_work(struct work_struct *work);
-static DECLARE_WORK(ps_irq_work, ps_irq_do_work);
-
static struct capella_cm3602_data {
struct input_dev *input_dev;
struct capella_cm3602_platform_data *pdata;
- struct workqueue_struct *ps_wq;
int enabled;
} the_data;
@@ -73,18 +69,10 @@ static int capella_cm3602_report(struct
return val;
}
-static void ps_irq_do_work(struct work_struct *work)
-{
- capella_cm3602_report(&the_data);
- enable_irq(the_data.pdata->irq);
-}
-
static irqreturn_t capella_cm3602_irq_handler(int irq, void *data)
{
- disable_irq_nosync(irq);
-
- queue_work(the_data.ps_wq, &ps_irq_work);
-
+ struct capella_cm3602_data *ip = data;
+ capella_cm3602_report(ip);
return IRQ_HANDLED;
}
@@ -183,14 +171,7 @@ static int capella_cm3602_setup(struct c
__func__, pdata->p_out, rc);
goto fail_free_p_en;
}
-
- the_data.ps_wq = create_singlethread_workqueue("proximity_wq");
- if (!the_data.ps_wq) {
- pr_err("%s: can't create workqueue\n", __func__);
- rc = -ENOMEM;
- goto fail_free_p_en;
- }
-
+ set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
rc = request_irq(irq,
capella_cm3602_irq_handler,
IRQF_TRIGGER_LOW | IRQF_TRIGGER_HIGH,
@@ -200,13 +181,11 @@ static int capella_cm3602_setup(struct c
pr_err("%s: request_irq(%d) failed for gpio %d (%d)\n",
__func__, irq,
pdata->p_out, rc);
- goto fail_free_wq;
+ goto fail_free_p_en;
}
goto done;
-fail_free_wq:
- destroy_workqueue(the_data.ps_wq);
fail_free_p_en:
gpio_free(pdata->p_en);
fail_free_p_out:
@@ -330,8 +309,6 @@ err_unregister_input_device:
err_free_input_device:
input_free_device(input_dev);
done:
- if (ip->pdata && ip->pdata->irq)
- disable_irq(ip->pdata->irq);
return rc;
}
--- a/drivers/input/opticaljoystick/curcial.c
+++ b/drivers/input/opticaljoystick/curcial.c
@@ -238,8 +238,8 @@ static void curcial_oj_work_func(struct
bool out = false;
uint8_t pxsum;
uint16_t sht;
- int16_t x_sum;
- int16_t y_sum;
+ int16_t x_sum, x_idx;
+ int16_t y_sum, y_idx;
curcial_oj_polling_mode(OJ_POLLING_DISABLE);
@@ -317,8 +317,15 @@ static void curcial_oj_work_func(struct
}
}
- x_count = oj->Xsteps[abs(x_sum) / normal_th];
- y_count = oj->Ysteps[abs(y_sum) / normal_th];
+ x_idx = abs(x_sum) / normal_th;
+ y_idx = abs(y_sum) / normal_th;
+ if (x_idx >= ARRAY_SIZE(oj->Xsteps))
+ x_idx = ARRAY_SIZE(oj->Xsteps) - 1;
+ if (y_idx >= ARRAY_SIZE(oj->Ysteps))
+ y_idx = ARRAY_SIZE(oj->Ysteps) - 1;
+
+ x_count = oj->Xsteps[x_idx];
+ y_count = oj->Ysteps[y_idx];
if (evtKey == OJ_KEY_LEFT) {
for (j = 0; j < x_count; j++) {
input_report_rel(oj->input_dev, REL_X, -1);
@@ -362,7 +369,7 @@ static void curcial_oj_work_func(struct
mDeltaX = 0;
mDeltaY = 0;
if (polling_delay)
- msleep(polling_delay);/*hr_msleep(polling_delay);*/
+ hr_msleep(polling_delay);
} while ((data[0] & 0x80) && (!atomic_read(&suspend_flag)));
--- a/drivers/input/touchscreen/synaptics_i2c_rmi.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi.c
@@ -24,6 +24,8 @@
#include <linux/platform_device.h>
#include <linux/synaptics_i2c_rmi.h>
+#define ENABLE_IME_IMPROVEMENT
+
static struct workqueue_struct *synaptics_wq;
struct synaptics_ts_data {
@@ -45,8 +47,28 @@ struct synaptics_ts_data {
uint32_t flags;
int reported_finger_count;
int8_t sensitivity_adjust;
+ uint32_t dup_threshold;
int (*power)(int on);
struct early_suspend early_suspend;
+ int display_width; /* display width in pixel */
+ int display_height; /* display height in pixel */
+ int ts_raw_pos[4]; /* raw data pos of left, right, top, and bottom */
+ int ts_raw_width;
+ int ts_raw_height;
+#ifdef ENABLE_IME_IMPROVEMENT
+ int ime_threshold_pixel; /* threshold in pixel */
+ int ime_threshold[2]; /* threshold X & Y in raw data */
+ int ime_area_pixel[4]; /* ime area in pixel */
+ int ime_area_pos[4]; /* ime area in raw data */
+#endif
+ int margin_inactive_pixel[4]; /* margin area in pixel */
+ int margin_inactive_raw[4]; /* margin area in raw data */
+ uint8_t disable_margin_filter[2]; /* local margin filter. enable/disable time by time */
+ uint8_t last_finger2_pressed;
+ uint8_t last_finger_result;
+ uint8_t key_pressed[2];
+ uint8_t debug_log_level;
+ uint8_t grip_suppression[2];
};
#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -54,6 +76,363 @@ static void synaptics_ts_early_suspend(s
static void synaptics_ts_late_resume(struct early_suspend *h);
#endif
+static struct synaptics_ts_data *gl_ts;
+static const char SYNAPTICSNAME[] = "Synaptics_T1007";
+static uint32_t syn_panel_version;
+
+static ssize_t touch_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ sprintf(buf, "%s_%#x\n", SYNAPTICSNAME, syn_panel_version);
+ ret = strlen(buf) + 1;
+
+ return ret;
+}
+
+static DEVICE_ATTR(vendor, 0444, touch_vendor_show, NULL);
+
+static struct kobject *android_touch_kobj;
+
+static ssize_t debug_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+
+ return sprintf(buf, "%d\n", ts->debug_log_level);
+}
+
+static ssize_t debug_level_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+
+ if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
+ ts->debug_log_level = buf[0] - '0';
+
+ return count;
+}
+
+static DEVICE_ATTR(debug_level, 0644, debug_level_show, debug_level_store);
+
+#ifdef ENABLE_IME_IMPROVEMENT
+static ssize_t ime_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+
+ return sprintf(buf, "%d\n", ts->ime_threshold_pixel);
+}
+
+static ssize_t ime_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+ char *ptr_data = (char *)buf;
+ unsigned long val;
+
+ val = simple_strtoul(ptr_data, NULL, 10);
+
+ if (val >= 0 && val <= max(ts->display_width, ts->display_height))
+ ts->ime_threshold_pixel = val;
+ else
+ ts->ime_threshold_pixel = 0;
+
+ ts->ime_threshold[0] = ts->ime_threshold_pixel * ts->ts_raw_width / ts->display_width;
+ ts->ime_threshold[1] = ts->ime_threshold_pixel * ts->ts_raw_height / ts->display_height;
+
+ return count;
+}
+
+static ssize_t ime_work_area_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+
+ return sprintf(buf, "%d,%d,%d,%d\n", ts->ime_area_pixel[0],
+ ts->ime_area_pixel[1], ts->ime_area_pixel[2], ts->ime_area_pixel[3]);
+}
+
+static ssize_t ime_work_area_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+ char *ptr_data = (char *)buf;
+ char *p;
+ int pt_count = 0;
+ unsigned long val[4];
+
+ while ((p = strsep(&ptr_data, ","))) {
+ if (!*p)
+ break;
+
+ if (pt_count >= 4)
+ break;
+
+ val[pt_count] = simple_strtoul(p, NULL, 10);
+
+ pt_count++;
+ }
+
+ if (pt_count >= 4 && ts->display_width && ts->display_height) {
+ ts->ime_area_pixel[0] = val[0]; /* Left */
+ ts->ime_area_pixel[1] = val[1]; /* Right */
+ ts->ime_area_pixel[2] = val[2]; /* Top */
+ ts->ime_area_pixel[3] = val[3]; /* Bottom */
+
+ if (val[0] < 0 || val[0] > ts->display_width)
+ ts->ime_area_pos[0] = 0;
+ else
+ ts->ime_area_pos[0] = val[0] * ts->max[0] / ts->display_width;
+
+ if (val[1] < 0 || val[1] > ts->display_width)
+ ts->ime_area_pos[1] = ts->max[0];
+ else
+ ts->ime_area_pos[1] = val[1] * ts->max[0] / ts->display_width;
+
+ if (val[2] < 0 || val[2] > ts->display_height)
+ ts->ime_area_pos[2] = 0;
+ else
+ ts->ime_area_pos[2] = val[2] * ts->max[1] / ts->display_height;
+
+ if (val[3] < 0 || val[3] > ts->display_height)
+ ts->ime_area_pos[3] = ts->max[1];
+ else
+ ts->ime_area_pos[3] = val[3] * ts->max[1] / ts->display_height;
+ }
+
+ return count;
+}
+
+static int ime_report_filter(struct synaptics_ts_data *ts, int pos[2][2], const int finger2_pressed, const int z)
+{
+ int dx = 0;
+ int dy = 0;
+ static int report_x;
+ static int report_y;
+
+ if (finger2_pressed)
+ return 1;
+
+ if ((pos[0][0] >= ts->ime_area_pos[0] && pos[0][0] <= ts->ime_area_pos[1]) &&
+ (pos[0][1] >= ts->ime_area_pos[2] && pos[0][1] <= ts->ime_area_pos[3])) {
+ dx = abs(pos[0][0] - report_x);
+ dy = abs(pos[0][1] - report_y);
+
+ if (dx < ts->ime_threshold[0] && dy < ts->ime_threshold[1] && z != 0) {
+ return 1;
+ }
+
+ report_x = pos[0][0];
+ report_y = pos[0][1];
+
+ if (z == 0) {
+ report_x = report_y = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* sys/class/input/inputX/ime_threshold */
+static DEVICE_ATTR(ime_threshold, 0666, ime_threshold_show,
+ ime_threshold_store);
+static DEVICE_ATTR(ime_work_area, 0666, ime_work_area_show,
+ ime_work_area_store);
+#endif
+
+static ssize_t margin_area_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+
+ return sprintf(buf, "#left,right,top,bottom\n"
+ "%d,%d,%d,%d\n", ts->margin_inactive_pixel[0],
+ ts->margin_inactive_pixel[1],
+ ts->margin_inactive_pixel[2],
+ ts->margin_inactive_pixel[3]);
+}
+
+static ssize_t margin_area_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct synaptics_ts_data *ts = gl_ts;
+ char *ptr_data = (char *)buf;
+ char *p;
+ uint8_t skip_data = 0;
+ unsigned long val[5];
+ int pt_count = 0;
+
+ while (ptr_data) {
+ if ((*ptr_data == '#') || skip_data) {
+ /* skip any string begin at '#' */
+ skip_data = 1;
+ if (*ptr_data == '\n')
+ skip_data = 0;
+ } else {
+ break;
+ }
+ ptr_data++;
+ }
+
+ while ((p = strsep(&ptr_data, ","))) {
+ if (!*p)
+ break;
+
+ if (pt_count >= 4)
+ break;
+
+ val[pt_count] = simple_strtoul(p, NULL, 10);
+
+ pt_count++;
+ }
+
+ if (pt_count >= 4) {
+ if (val[0] < 0 || val[0] > ts->display_width) { /* Left */
+ ts->margin_inactive_raw[0] = ts->margin_inactive_pixel[0] = 0;
+ } else {
+ ts->margin_inactive_pixel[0] = val[0];
+ ts->margin_inactive_raw[0] = ts->ts_raw_pos[0] + val[0] *
+ ts->ts_raw_width / ts->display_width;
+ }
+
+ if (val[1] < 0 || val[1] > ts->display_width) { /* Right */
+ ts->margin_inactive_pixel[1] = 0;
+ ts->margin_inactive_raw[1] = ts->max[0];
+ } else {
+ ts->margin_inactive_pixel[1] = val[1];
+ ts->margin_inactive_raw[1] = ts->ts_raw_pos[0] + val[1] *
+ ts->ts_raw_width / ts->display_width;
+ }
+
+ if (val[2] < 0 || val[2] > ts->display_width) { /* top */
+ ts->margin_inactive_raw[2] = ts->margin_inactive_pixel[2] = 0;
+ } else {
+ ts->margin_inactive_pixel[2] = val[2];
+ ts->margin_inactive_raw[2] = ts->ts_raw_pos[1] - val[2] *
+ ts->ts_raw_width / ts->display_width;
+ }
+
+ if (val[3] < 0 || val[3] > ts->display_width) { /* Bottom */
+ ts->margin_inactive_pixel[3] = 0;
+ ts->margin_inactive_raw[3] = ts->max[1];
+ } else {
+ ts->margin_inactive_pixel[3] = val[3];
+ ts->margin_inactive_raw[3] = ts->ts_raw_pos[1] - val[3] *
+ ts->ts_raw_width / ts->display_width;
+ }
+ }
+
+ return count;
+}
+
+/* sys/class/input/inputX/margin_area */
+static DEVICE_ATTR(margin_area, 0600, margin_area_show, margin_area_store);
+
+static void margin_filter(struct synaptics_ts_data *ts, int pos[2][2],
+ const int finger2_pressed, const int z)
+{
+ if (ts->grip_suppression[0] != 2) {
+ if (pos[0][0] < ts->margin_inactive_raw[0] ||
+ pos[0][0] > ts->margin_inactive_raw[3])
+ ts->grip_suppression[0] = 1;
+ else if ((pos[0][0] < ts->margin_inactive_raw[1] ||
+ pos[0][0] > ts->margin_inactive_raw[2]) && ts->grip_suppression[0])
+ ts->grip_suppression[0] = 1;
+ else
+ ts->grip_suppression[0] = 2;
+ }
+ if (finger2_pressed && ts->grip_suppression[1] != 2) {
+ if (pos[1][0] < ts->margin_inactive_raw[0] ||
+ pos[1][0] > ts->margin_inactive_raw[3])
+ ts->grip_suppression[1] = 1;
+ else if ((pos[1][0] < ts->margin_inactive_raw[1] ||
+ pos[1][0] > ts->margin_inactive_raw[2]) &&
+ ts->grip_suppression[1])
+ ts->grip_suppression[1] = 1;
+ else
+ ts->grip_suppression[1] = 2;
+ }
+
+ if (z == 0) {
+ /* Finger left, re-enable margin filter for next touch event */
+ ts->grip_suppression[0] = ts->grip_suppression[1] = 0;
+ }
+}
+
+#ifdef CONFIG_TOUCHSCREEN_DUPLICATED_FILTER
+static int duplicated_filter(struct synaptics_ts_data *ts, int pos[2][2],
+ const int finger2_pressed, const int z)
+{
+ int drift_x[2];
+ int drift_y[2];
+ static int ref_x[2], ref_y[2];
+ uint8_t discard[2] = {0, 0};
+
+ drift_x[0] = abs(ref_x[0] - pos[0][0]);
+ drift_y[0] = abs(ref_y[0] - pos[0][1]);
+ if (finger2_pressed) {
+ drift_x[1] = abs(ref_x[1] - pos[1][0]);
+ drift_y[1] = abs(ref_y[1] - pos[1][1]);
+ }
+ /* printk("ref_x :%d, ref_y: %d, x: %d, y: %d\n", ref_x, ref_y, pos[0][0], pos[0][1]); */
+ if (drift_x[0] < ts->dup_threshold && drift_y[0] < ts->dup_threshold && z != 0) {
+ /* printk("ref_x :%d, ref_y: %d, x: %d, y: %d\n", ref_x[0], ref_y[0], pos[0][0], pos[0][1]); */
+ discard[0] = 1;
+ }
+ if (!finger2_pressed || (drift_x[1] < ts->dup_threshold && drift_y[1] < ts->dup_threshold)) {
+ discard[1] = 1;
+ }
+ if (discard[0] && discard[1]) {
+ /* if finger 0 and finger 1's movement < threshold , discard it. */
+ return 1;
+ }
+ ref_x[0] = pos[0][0];
+ ref_y[0] = pos[0][1];
+ if (finger2_pressed) {
+ ref_x[1] = pos[1][0];
+ ref_y[1] = pos[1][1];
+ }
+ if (z == 0) {
+ ref_x[0] = ref_y[0] = 0;
+ ref_x[1] = ref_y[1] = 0;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_TOUCHSCREEN_DUPLICATED_FILTER */
+
+static int synaptics_touch_sysfs_init(void)
+{
+ int ret;
+ android_touch_kobj = kobject_create_and_add("android_touch", NULL);
+ if (android_touch_kobj == NULL) {
+ printk(KERN_ERR "%s: subsystem_register failed\n", __func__);
+ ret = -ENOMEM;
+ return ret;
+ }
+ ret = sysfs_create_file(android_touch_kobj, &dev_attr_vendor.attr);
+ if (ret) {
+ printk(KERN_ERR "touch_sysfs_init: sysfs_create_group failed\n");
+ return ret;
+ }
+ ret = sysfs_create_file(android_touch_kobj, &dev_attr_debug_level.attr);
+ if (ret) {
+ printk(KERN_ERR "%s: sysfs_create_file failed\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+static void synaptics_touch_sysfs_remove(void)
+{
+ sysfs_remove_file(android_touch_kobj, &dev_attr_debug_level.attr);
+ kobject_del(android_touch_kobj);
+}
+
static int synaptics_init_panel(struct synaptics_ts_data *ts)
{
int ret;
@@ -151,13 +530,21 @@ static void synaptics_ts_work_func(struc
/* int dx = (int8_t)buf[12]; */
/* int dy = (int8_t)buf[13]; */
- int finger2_pressed;
+ int finger2_pressed = finger > 1 && finger != 7;
/* printk("x %4d, y %4d, z %3d, w %2d, F %d, 2nd: x %4d, y %4d, z %3d, w %2d, F %d, dx %4d, dy %4d\n", */
/* x, y, z, w, finger, */
/* x2, y2, z2, w2, finger2, */
/* dx, dy); */
+ /* debug log level 1 */
+ if (ts->debug_log_level & 0x1) {
+ printk("%s: raw data:", __func__);
+ for (i = 0; i < buf_len; i++)
+ printk(" %2x", buf[i]);
+ printk("\n");
+ }
+
base = 2;
for (f = 0; f < 2; f++) {
uint32_t flip_flag = SYNAPTICS_FLIP_X;
@@ -192,6 +579,8 @@ static void synaptics_ts_work_func(struc
if (ts->flags & SYNAPTICS_SWAP_XY)
swap(pos[f][0], pos[f][1]);
}
+
+#ifdef CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT
if (z) {
input_report_abs(ts->input_dev, ABS_X, pos[0][0]);
input_report_abs(ts->input_dev, ABS_Y, pos[0][1]);
@@ -199,26 +588,76 @@ static void synaptics_ts_work_func(struc
input_report_abs(ts->input_dev, ABS_PRESSURE, z);
input_report_abs(ts->input_dev, ABS_TOOL_WIDTH, w);
input_report_key(ts->input_dev, BTN_TOUCH, finger);
- finger2_pressed = finger > 1 && finger != 7;
input_report_key(ts->input_dev, BTN_2, finger2_pressed);
if (finger2_pressed) {
input_report_abs(ts->input_dev, ABS_HAT0X, pos[1][0]);
input_report_abs(ts->input_dev, ABS_HAT0Y, pos[1][1]);
}
+#endif
if (!finger)
z = 0;
- input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z);
- input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[0][0]);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[0][1]);
- input_mt_sync(ts->input_dev);
+
+#ifdef ENABLE_IME_IMPROVEMENT
+ if (ts->ime_threshold_pixel > 0) {
+ ret = ime_report_filter(ts, pos, finger2_pressed, z);
+ if (ret == 1) {
+ /* printk("%s: ime_report_filter\n", __func__); */
+ break;
+ }
+ }
+#endif
+
+ /**
+ * Margin filter
+ */
+ if (ts->margin_inactive_pixel[0] || ts->margin_inactive_pixel[1] ||
+ ts->margin_inactive_pixel[2] || ts->margin_inactive_pixel[3]) {
+ margin_filter(ts, pos, finger2_pressed, z);
+ } else {
+ ts->grip_suppression[0] = 2;
+ ts->grip_suppression[1] = 2;
+ }
+
+#ifdef CONFIG_TOUCHSCREEN_DUPLICATED_FILTER
+ /**
+ * Small movement report would seem as duplicated report, discard it
+ */
+ ret = duplicated_filter(ts, pos, finger2_pressed, z);
+ if (ret == 1) {
+ /* printk("%s: duplicated_filter\n", __func__); */
+ break;
+ }
+#endif
+#ifdef CONFIG_TOUCHSCREEN_CONCATENATE_REPORT
+ /**
+ * We concatenate z, w, x, y info to reduce the number of reports in event hub
+ */
+ if (ts->grip_suppression[0] == 2 || z == 0) {
+ input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, z << 16 | w);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION,
+ (!(finger2_pressed && ts->grip_suppression[1] == 2)) << 31 | pos[0][0] << 16 | pos[0][1]);
+ }
+ if (finger2_pressed && ts->grip_suppression[1] == 2) {
+ input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, z << 16 | w);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31 | pos[1][0] << 16 | pos[1][1]);
+ }
+#else
+ if (ts->grip_suppression[0] == 2 || z == 0) {
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[0][0]);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[0][1]);
+ input_mt_sync(ts->input_dev);
+ }
if (finger2_pressed) {
+ if (ts->grip_suppression[1] == 2) {
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[1][0]);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[1][1]);
input_mt_sync(ts->input_dev);
+ }
} else if (ts->reported_finger_count > 1) {
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
@@ -226,6 +665,27 @@ static void synaptics_ts_work_func(struc
}
ts->reported_finger_count = finger;
input_sync(ts->input_dev);
+#endif /* CONFIG_TOUCHSCREEN_CONCATENATE_REPORT */
+ if (!ts->key_pressed[0] && finger) {
+ ts->key_pressed[0] = 1;
+ printk(KERN_INFO "S1@%d, %d\n", pos[0][0], pos[0][1]);
+ } else if (ts->key_pressed[0] == 1 && !finger) {
+ ts->key_pressed[0] = 2;
+ printk(KERN_INFO "E1@%d, %d\n", pos[0][0], pos[0][1]);
+ }
+ if (ts->key_pressed[0] == 1 && !ts->key_pressed[1] && finger2_pressed) {
+ ts->key_pressed[1] = 1;
+ printk(KERN_INFO "S2@%d, %d\n", pos[1][0], pos[1][1]);
+ } else if (ts->key_pressed[1] && !finger2_pressed) {
+ ts->key_pressed[1] = 0;
+ printk(KERN_INFO "E2@%d, %d\n", pos[1][0], pos[1][1]);
+ }
+ /* debug log level 2 */
+ if (ts->debug_log_level & 0x2) {
+ printk("X1 %4d, Y1 %4d, Z %3d, W %2d, F1 %d, X2 %4d, Y2 %4d, F2 %d\n",
+ pos[0][0], pos[0][1], z, w, finger,
+ pos[1][0], pos[1][1], finger2_pressed);
+ }
}
}
}
@@ -279,6 +739,7 @@ static int synaptics_ts_probe(
int snap_bottom_on;
int snap_bottom_off;
uint32_t panel_version;
+ int i;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
printk(KERN_ERR "synaptics_ts_probe: need I2C_FUNC_I2C\n");
@@ -291,7 +752,6 @@ static int synaptics_ts_probe(
ret = -ENOMEM;
goto err_alloc_data_failed;
}
- INIT_WORK(&ts->work, synaptics_ts_work_func);
ts->client = client;
i2c_set_clientdata(client, ts);
pdata = client->dev.platform_data;
@@ -325,6 +785,7 @@ static int synaptics_ts_probe(
}
printk(KERN_INFO "synaptics_ts_probe: Product Major Version %x\n", ret);
panel_version = ret << 8;
+ syn_panel_version = panel_version;
ret = i2c_smbus_read_byte_data(ts->client, 0xe5);
if (ret < 0) {
printk(KERN_ERR "i2c_smbus_read_byte_data failed\n");
@@ -362,6 +823,11 @@ static int synaptics_ts_probe(
fuzz_y = pdata->fuzz_y;
fuzz_p = pdata->fuzz_p;
fuzz_w = pdata->fuzz_w;
+ ts->dup_threshold = pdata->dup_threshold;
+ ts->display_width = pdata->display_width;
+ ts->display_height = pdata->display_height;
+ if (!ts->display_width || !ts->display_height)
+ ts->display_width = ts->display_height = 1;
} else {
irqflags = 0;
inactive_area_left = 0;
@@ -380,6 +846,12 @@ static int synaptics_ts_probe(
fuzz_y = 0;
fuzz_p = 0;
fuzz_w = 0;
+ ts->display_width = 1;
+ ts->display_height = 1;
+ }
+
+ for (i = 0; i < 4 ; i++) {
+ ts->margin_inactive_pixel[i] = pdata->margin_inactive_pixel[i];
}
ret = i2c_smbus_read_byte_data(ts->client, 0xf0);
@@ -453,6 +925,11 @@ static int synaptics_ts_probe(
goto err_detect_failed;
}
+ synaptics_wq = create_singlethread_workqueue("synaptics_wq");
+ if (!synaptics_wq)
+ goto err_create_wq_failed;
+ INIT_WORK(&ts->work, synaptics_ts_work_func);
+
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
@@ -491,6 +968,20 @@ static int synaptics_ts_probe(
ts->snap_down_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_off;
ts->snap_up_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_on;
ts->snap_up_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_off;
+ ts->ts_raw_pos[0] = -inactive_area_left;
+ ts->ts_raw_pos[1] = max_x + inactive_area_right;
+ ts->ts_raw_pos[2] = -inactive_area_top;
+ ts->ts_raw_pos[3] = max_y + inactive_area_bottom;
+ ts->ts_raw_width = ts->ts_raw_pos[1] - ts->ts_raw_pos[0]; /* ts raw width */
+ ts->ts_raw_height = ts->ts_raw_pos[3] - ts->ts_raw_pos[2]; /* ts raw height */
+ ts->margin_inactive_raw[0] = ts->ts_raw_pos[0] + ts->margin_inactive_pixel[0] *
+ ts->ts_raw_width / ts->display_width;
+ ts->margin_inactive_raw[1] = ts->ts_raw_pos[0] + ts->margin_inactive_pixel[1] *
+ ts->ts_raw_width / ts->display_width;
+ ts->margin_inactive_raw[2] = ts->ts_raw_pos[1] - ts->margin_inactive_pixel[2] *
+ ts->ts_raw_width / ts->display_width;
+ ts->margin_inactive_raw[3] = ts->ts_raw_pos[1] - ts->margin_inactive_pixel[3] *
+ ts->ts_raw_width / ts->display_width;
printk(KERN_INFO "synaptics_ts_probe: max_x %d, max_y %d\n", max_x, max_y);
printk(KERN_INFO "synaptics_ts_probe: inactive_x %d %d, inactive_y %d %d\n",
inactive_area_left, inactive_area_right,
@@ -498,22 +989,65 @@ static int synaptics_ts_probe(
printk(KERN_INFO "synaptics_ts_probe: snap_x %d-%d %d-%d, snap_y %d-%d %d-%d\n",
snap_left_on, snap_left_off, snap_right_on, snap_right_off,
snap_top_on, snap_top_off, snap_bottom_on, snap_bottom_off);
+ printk(KERN_INFO "synaptics_ts_probe: margin_pixel_left: %d, margin_pixel_right: %d, "
+ "margin_pixel_top: %d, margin_pixel_bottom: %d\n",
+ ts->margin_inactive_pixel[0], ts->margin_inactive_pixel[1],
+ ts->margin_inactive_pixel[2], ts->margin_inactive_pixel[3]);
+ printk(KERN_INFO "synaptics_ts_probe: ts_raw_width: %d, ts_raw_height: %d\n",
+ ts->ts_raw_width, ts->ts_raw_height);
+#ifdef CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT
input_set_abs_params(ts->input_dev, ABS_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0);
input_set_abs_params(ts->input_dev, ABS_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0);
input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, fuzz_p, 0);
input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH, 0, 15, fuzz_w, 0);
input_set_abs_params(ts->input_dev, ABS_HAT0X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0);
input_set_abs_params(ts->input_dev, ABS_HAT0Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0);
+#endif
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, fuzz_p, 0);
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 15, fuzz_w, 0);
+#ifdef CONFIG_TOUCHSCREEN_CONCATENATE_REPORT
+ input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((255 << 16) | 255), 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, ((1 << 31) | (max_x << 16) | max_y), 0, 0);
+#endif
/* ts->input_dev->name = ts->keypad_info->name; */
ret = input_register_device(ts->input_dev);
if (ret) {
printk(KERN_ERR "synaptics_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
goto err_input_register_device_failed;
}
+
+ gl_ts = ts;
+
+#ifdef ENABLE_IME_IMPROVEMENT
+ ts->ime_threshold_pixel = 0;
+
+ ret = device_create_file(&ts->input_dev->dev, &dev_attr_ime_threshold);
+ if (ret) {
+ printk(KERN_ERR "ENABLE_IME_IMPROVEMENT: "
+ "Error to create ime_threshold\n");
+ goto err_input_register_device_failed;
+ }
+ ret = device_create_file(&ts->input_dev->dev, &dev_attr_ime_work_area);
+ if (ret) {
+ printk(KERN_ERR "ENABLE_IME_IMPROVEMENT: "
+ "Error to create ime_work_area\n");
+ device_remove_file(&ts->input_dev->dev,
+ &dev_attr_ime_threshold);
+ goto err_input_register_device_failed;
+ }
+
+#endif
+
+ /* For margin filter*/
+ ret = device_create_file(&ts->input_dev->dev, &dev_attr_margin_area);
+ if (ret) {
+ printk(KERN_ERR "MARGIN_FILTER: "
+ "Error to create margin_area\n");
+ goto err_input_register_device_failed;
+ }
+
if (client->irq) {
ret = request_irq(client->irq, synaptics_ts_irq_handler, irqflags, client->name, ts);
if (ret == 0) {
@@ -532,12 +1066,14 @@ static int synaptics_ts_probe(
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
#ifdef CONFIG_HAS_EARLYSUSPEND
- ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1;
ts->early_suspend.suspend = synaptics_ts_early_suspend;
ts->early_suspend.resume = synaptics_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
+ synaptics_touch_sysfs_init();
+
printk(KERN_INFO "synaptics_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
return 0;
@@ -546,9 +1082,13 @@ err_input_register_device_failed:
input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
+ destroy_workqueue(synaptics_wq);
+
+err_create_wq_failed:
err_detect_failed:
err_power_failed:
kfree(ts);
+
err_alloc_data_failed:
err_check_functionality_failed:
return ret;
@@ -563,6 +1103,16 @@ static int synaptics_ts_remove(struct i2
else
hrtimer_cancel(&ts->timer);
input_unregister_device(ts->input_dev);
+
+#ifdef ENABLE_IME_IMPROVEMENT
+ device_remove_file(&ts->input_dev->dev, &dev_attr_ime_threshold);
+ device_remove_file(&ts->input_dev->dev, &dev_attr_ime_work_area);
+#endif
+ /* For margin filter */
+ device_remove_file(&ts->input_dev->dev, &dev_attr_margin_area);
+
+ synaptics_touch_sysfs_remove();
+
kfree(ts);
return 0;
}
@@ -583,6 +1133,8 @@ static int synaptics_ts_suspend(struct i
if (ret < 0)
printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n");
+ ts->key_pressed[0] = 0;
+
ret = i2c_smbus_write_byte_data(client, 0xf0, 0x86); /* deep sleep */
if (ret < 0)
printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n");
@@ -654,9 +1206,6 @@ static struct i2c_driver synaptics_ts_dr
static int __devinit synaptics_ts_init(void)
{
- synaptics_wq = create_singlethread_workqueue("synaptics_wq");
- if (!synaptics_wq)
- return -ENOMEM;
return i2c_add_driver(&synaptics_ts_driver);
}
--- a/include/linux/curcial_oj.h
+++ b/include/linux/curcial_oj.h
@@ -36,6 +36,8 @@ struct curcial_oj_platform_data {
#endif
unsigned irq_gpio;
+ unsigned rst_gpio;
+ uint8_t ledval;
};
void curcial_oj_send_key(unsigned int code, int value);
--- a/include/linux/synaptics_i2c_rmi.h
+++ b/include/linux/synaptics_i2c_rmi.h
@@ -20,6 +20,7 @@
#define SYNAPTICS_I2C_RMI_NAME "synaptics-rmi-ts"
#define SYNAPTICS_T1007_NAME "synaptics-t1007"
#define SYNAPTICS_T1021_NAME "synaptics-t1021"
+#define SYNAPTICS_3K_NAME "synaptics-3k"
enum {
SYNAPTICS_FLIP_X = 1UL << 0,
@@ -47,6 +48,7 @@ struct synaptics_i2c_rmi_platform_data {
struct synaptics_virtual_key *virtual_key;
uint8_t virtual_key_num;
uint8_t sensitivity;
+ uint8_t finger_support;
uint32_t gap_area;
uint32_t key_area;
uint32_t flags;
@@ -65,6 +67,10 @@ struct synaptics_i2c_rmi_platform_data {
uint32_t snap_bottom_off; /* 0x10000 = screen height */
uint32_t fuzz_x; /* 0x10000 = screen width */
uint32_t fuzz_y; /* 0x10000 = screen height */
+ uint16_t abs_x_min;
+ uint16_t abs_x_max;
+ uint16_t abs_y_min;
+ uint16_t abs_y_max;
int fuzz_p;
int fuzz_w;
uint32_t display_width;
@@ -79,4 +85,11 @@ struct page_description {
uint8_t value;
};
+struct syn_finger_data {
+ int x;
+ int y;
+ int w;
+ int z;
+};
+
#endif /* _LINUX_SYNAPTICS_I2C_RMI_H */