aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/mxt1664s.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/mxt1664s.c')
-rw-r--r--drivers/input/touchscreen/mxt1664s.c712
1 files changed, 605 insertions, 107 deletions
diff --git a/drivers/input/touchscreen/mxt1664s.c b/drivers/input/touchscreen/mxt1664s.c
index 54e55b8..cce3717 100644
--- a/drivers/input/touchscreen/mxt1664s.c
+++ b/drivers/input/touchscreen/mxt1664s.c
@@ -34,7 +34,7 @@
int mxt_read_mem(struct mxt_data *data, u16 reg, u8 len, u8 *buf)
{
- int ret;
+ int ret = 0, i = 0;
u16 le_reg = cpu_to_le16(reg);
struct i2c_msg msg[2] = {
{
@@ -51,32 +51,48 @@ int mxt_read_mem(struct mxt_data *data, u16 reg, u8 len, u8 *buf)
},
};
- ret = i2c_transfer(data->client->adapter, msg, 2);
+ if (!data->mxt_enabled) {
+ dev_err(&data->client->dev,
+ "%s tsp ic is not ready\n", __func__);
+ return -EBUSY;
+ }
- if (ret < 0) {
- dev_err(&data->client->dev, "%s fail[%d] address[0x%x]\n",
- __func__, ret, le_reg);
- return ret;
+ for (i = 0; i < 3 ; i++) {
+ ret = i2c_transfer(data->client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "%s fail[%d] address[0x%x]\n",
+ __func__, ret, le_reg);
+ data->pdata->power_reset();
+ } else
+ break;
}
+
return ret == 2 ? 0 : -EIO;
}
int mxt_write_mem(struct mxt_data *data,
u16 reg, u8 len, const u8 *buf)
{
- int ret, i;
+ int ret = 0, i = 0;
u8 tmp[len + 2];
+ if (!data->mxt_enabled) {
+ dev_err(&data->client->dev,
+ "%s tsp ic is not ready\n", __func__);
+ return -EBUSY;
+ }
+
put_unaligned_le16(cpu_to_le16(reg), tmp);
memcpy(tmp + 2, buf, len);
- for (i = 0; i < 5 ; i++) {
+ for (i = 0; i < 3 ; i++) {
ret = i2c_master_send(data->client, tmp, sizeof(tmp));
- if (ret < 0)
+ if (ret < 0) {
dev_err(&data->client->dev,
"%s %d times write error on address[0x%x,0x%x]\n",
__func__, i, tmp[1], tmp[0]);
- else
+ data->pdata->power_reset();
+ } else
break;
}
@@ -147,6 +163,21 @@ static int mxt_backup(struct mxt_data *data)
return mxt_write_mem(data, data->cmd_proc + CMD_BACKUP_OFFSET, 1, &buf);
}
+static void mxt_start(struct mxt_data *data)
+{
+ /* Touch report enable */
+ mxt_write_object(data,
+ TOUCH_MULTITOUCHSCREEN_T9, 0,
+ data->tsp_ctl);
+}
+
+static void mxt_stop(struct mxt_data *data)
+{
+ /* Touch report disable */
+ mxt_write_object(data,
+ TOUCH_MULTITOUCHSCREEN_T9, 0, 0);
+}
+
static int mxt_check_instance(struct mxt_data *data, u8 object_type)
{
int i;
@@ -288,25 +319,21 @@ static int mxt_get_object_table(struct mxt_data *data)
(data->objects[i].instances);
switch (data->objects[i].object_type) {
- case TOUCH_MULTITOUCHSCREEN_T9:
- data->finger_report_id = type_count + 1;
-#if TSP_DEBUG_INFO
- dev_info(&data->client->dev, "Finger report id: %d\n",
- data->finger_report_id);
-#endif
- break;
case GEN_MESSAGEPROCESSOR_T5:
data->msg_object_size = data->objects[i].size;
data->msg_proc = data->objects[i].start_address;
-#if TSP_DEBUG_INFO
- dev_info(&data->client->dev, "mesage object size: %d"
+ dev_dbg(&data->client->dev, "mesage object size: %d"
" message address: 0x%x\n",
data->msg_object_size, data->msg_proc);
-#endif
break;
case GEN_COMMANDPROCESSOR_T6:
data->cmd_proc = data->objects[i].start_address;
break;
+ case TOUCH_MULTITOUCHSCREEN_T9:
+ data->finger_report_id = type_count + 1;
+ dev_dbg(&data->client->dev, "Finger report id: %d\n",
+ data->finger_report_id);
+ break;
}
if (data->objects[i].num_report_ids) {
@@ -333,7 +360,6 @@ out:
return ret;
}
-
static void __devinit mxt_make_reportid_table(struct mxt_data *data)
{
struct mxt_object *objects = data->objects;
@@ -372,7 +398,7 @@ static void __devinit mxt_make_reportid_table(struct mxt_data *data)
static int mxt_write_configuration(struct mxt_data *data)
{
- int i, ret;
+ int i = 0, ret = 0;
u8 ** tsp_config = (u8 **)data->pdata->config;
@@ -383,6 +409,9 @@ static int mxt_write_configuration(struct mxt_data *data)
goto out;
if (tsp_config[i][0] == TOUCH_MULTITOUCHSCREEN_T9) {
+ data->tsp_ctl = tsp_config[i][1];
+ data->x_num = tsp_config[i][4];
+ data->y_num = tsp_config[i][5];
/* Are x and y inverted? */
if (tsp_config[i][10] & 0x1) {
data->x_dropbits =
@@ -425,6 +454,194 @@ static int mxt_calibrate_chip(struct mxt_data *data)
return ret;
}
+#if TSP_INFORM_CHARGER
+static bool check_acq_int(struct mxt_data *data, u8 *buf)
+{
+ bool int_conf = false;
+
+ if ((!data->charging_mode) &&
+ (GEN_POWERCONFIG_T7 == buf[0])) {
+ switch (buf[1]) {
+ case MXT_T7_IDLE_ACQ_INT:
+ case MXT_T7_ACT_ACQ_INT:
+ int_conf = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return int_conf;
+}
+
+static void set_charger_config(struct mxt_data *data,
+ int mode)
+{
+ u8 *buf = data->charger_inform_buf;
+ int i = 1;
+
+ while (data->charger_inform_buf_size > i + 3) {
+ u8 *tmp = &buf[i];
+ int ret = 0;
+ if (mode == check_acq_int(data, tmp)) {
+ u8 type = buf[i];
+ u8 offset = buf[i + 1];
+ u8 val = buf[i + 2 + data->charging_mode];
+
+ ret = mxt_write_object(data, type, offset, val);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "%s : failed to write i2c %d %d %d\n",
+ __func__, type, offset, val);
+ return ;
+ }
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "%s : %d %d %d\n",
+ __func__, type, offset, val);
+ }
+ i += 4;
+ }
+
+}
+
+static void inform_charger(struct mxt_callbacks *cb,
+ bool en)
+{
+ struct mxt_data *data = container_of(cb,
+ struct mxt_data, callbacks);
+
+ cancel_delayed_work_sync(&data->noti_dwork);
+ cancel_delayed_work_sync(&data->acq_int_dwork);
+ data->charging_mode = en;
+ schedule_delayed_work(&data->noti_dwork, HZ / 5);
+}
+
+static void charger_noti_dwork(struct work_struct *work)
+{
+ struct mxt_data *data =
+ container_of(work, struct mxt_data,
+ noti_dwork.work);
+
+ if (!data->mxt_enabled) {
+ schedule_delayed_work(&data->noti_dwork, HZ / 5);
+ return ;
+ }
+
+ dev_info(&data->client->dev,
+ "%s mode\n",
+ data->charging_mode ? "charging" : "battery");
+
+ set_charger_config(data, 0);
+
+ if (!data->charging_mode)
+ schedule_delayed_work(&data->acq_int_dwork, HZ * 3);
+}
+
+static void switch_acq_int_dwork(struct work_struct *work)
+{
+ struct mxt_data *data =
+ container_of(work, struct mxt_data,
+ acq_int_dwork.work);
+
+ set_charger_config(data, 1);
+}
+
+static void inform_charger_init(struct mxt_data *data, u8 *buf)
+{
+ data->charger_inform_buf_size = buf[0];
+ data->charger_inform_buf = kzalloc(buf[0], GFP_KERNEL);
+ memcpy(data->charger_inform_buf, buf, buf[0]);
+ INIT_DELAYED_WORK(&data->noti_dwork, charger_noti_dwork);
+ INIT_DELAYED_WORK(&data->acq_int_dwork, switch_acq_int_dwork);
+}
+#endif
+
+
+#if CHECK_ANTITOUCH
+void mxt_t61_timer_set(struct mxt_data *data, u8 mode, u8 cmd, u16 ms_period)
+{
+ struct mxt_object *object;
+ int ret = 0;
+ u8 buf[5] = {3, 0, 0, 0, 0};
+
+ object = mxt_get_object_info(data, SPT_TIMER_T61);
+
+ buf[1] = cmd;
+ buf[2] = mode;
+ buf[3] = ms_period & 0xFF;
+ buf[4] = (ms_period >> 8) & 0xFF;
+
+ ret = mxt_write_mem(data, object->start_address, 5, buf);
+ if (ret)
+ dev_err(&data->client->dev,
+ "%s write error T%d address[0x%x]\n",
+ __func__, SPT_TIMER_T61, object->start_address);
+
+ if (ms_period)
+ dev_info(&data->client->dev,
+ "T61 Timer Enabled %d\n", ms_period);
+}
+
+void mxt_t8_autocal_set(struct mxt_data *data, u8 mstime)
+{
+ struct mxt_object *object;
+ int ret = 0;
+
+ if (mstime) {
+ data->check_autocal = 1;
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "T8 Autocal Enabled %d\n", mstime);
+ } else {
+ data->check_autocal = 0;
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "T8 Autocal Disabled %d\n", mstime);
+ }
+
+ object = mxt_get_object_info(data,
+ GEN_ACQUISITIONCONFIG_T8);
+
+ ret = mxt_write_mem(data,
+ object->start_address + 4,
+ 1, &mstime);
+ if (ret)
+ dev_err(&data->client->dev,
+ "%s write error T%d address[0x%x]\n",
+ __func__, SPT_TIMER_T61, object->start_address);
+}
+
+static void mxt_check_coordinate(struct mxt_data *data,
+ bool detect, u8 id, u16 *px, u16 *py)
+{
+ static int tcount[] = {0, };
+ static u16 pre_x[][4] = {{0}, };
+ static u16 pre_y[][4] = {{0}, };
+ int distance = 0;
+
+ if (detect)
+ tcount[id] = 0;
+
+ if (tcount[id] > 1) {
+ distance = abs(pre_x[id][0] - *px) + abs(pre_y[id][0] - *py);
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "Check Distance ID:%d, %d\n",
+ id, distance);
+
+ /* AutoCal Disable */
+ if (distance > 3)
+ mxt_t8_autocal_set(data, 0);
+ }
+
+ pre_x[id][0] = *px;
+ pre_y[id][0] = *py;
+
+ tcount[id]++;
+}
+#endif /* CHECK_ANTITOUCH */
+
static void mxt_report_input_data(struct mxt_data *data)
{
int i;
@@ -451,13 +668,22 @@ static void mxt_report_input_data(struct mxt_data *data)
data->fingers[i].w);
input_report_abs(data->input_dev, ABS_MT_PRESSURE,
data->fingers[i].z);
+#if TSP_USE_SHAPETOUCH
+ input_report_abs(data->input_dev, ABS_MT_COMPONENT,
+ data->fingers[i].component);
+ input_report_abs(data->input_dev, ABS_MT_SUMSIZE,
+ data->sumsize);
+#endif
}
report_count++;
#if TSP_DEBUG_INFO
if (data->fingers[i].state == MXT_STATE_PRESS)
- dev_info(&data->client->dev, "P: id[%d] X[%d],Y[%d]\n",
- i, data->fingers[i].x, data->fingers[i].y);
+ dev_info(&data->client->dev, "P: id[%d] X[%d],Y[%d]"
+ " comp[%d], sum[%d] size[%d], pressure[%d]\n",
+ i, data->fingers[i].x, data->fingers[i].y,
+ data->fingers[i].component, data->sumsize,
+ data->fingers[i].w, data->fingers[i].z);
#else
if (data->fingers[i].state == MXT_STATE_PRESS)
dev_info(&data->client->dev, "P: id[%d]\n", i);
@@ -481,14 +707,16 @@ static void mxt_report_input_data(struct mxt_data *data)
#endif
input_sync(data->input_dev);
}
-#if TSP_BOOSTER
+
+#if (TSP_USE_SHAPETOUCH || TSP_BOOSTER)
/* all fingers are released */
if (count == 0) {
- if (data->booster.touch_cpu_lock_status) {
- cancel_delayed_work(&data->booster.dvfs_dwork);
- schedule_delayed_work(&data->booster.dvfs_dwork,
- msecs_to_jiffies(TOUCH_BOOSTER_TIME));
- }
+#if TSP_USE_SHAPETOUCH
+ data->sumsize = 0;
+#endif
+#if TSP_BOOSTER
+ mxt_set_dvfs_on(data, false);
+#endif
}
#endif
@@ -507,17 +735,40 @@ static void mxt_treat_T6_object(struct mxt_data *data, u8 *msg)
if (msg[1] & 0x08)
dev_err(&data->client->dev, "config error\n");
/* calibration */
- if (msg[1] & 0x10)
+ if (msg[1] & 0x10) {
dev_info(&data->client->dev, "calibration is on going !!\n");
+#if CHECK_ANTITOUCH
+ /* After Calibration */
+ data->check_antitouch = 1;
+ mxt_t61_timer_set(data,
+ MXT_T61_TIMER_ONESHOT,
+ MXT_T61_TIMER_CMD_STOP, 0);
+ data->check_timer = 0;
+ data->check_calgood = 0;
+#endif
+ }
/* signal error */
if (msg[1] & 0x20)
dev_err(&data->client->dev, "signal error\n");
/* overflow */
- if (msg[1] & 0x40)
+ if (msg[1] & 0x40) {
dev_err(&data->client->dev, "overflow detected\n");
+ mxt_write_object(data,
+ GEN_POWERCONFIG_T7, 1, 0xff);
+ mxt_write_object(data,
+ TOUCH_MULTITOUCHSCREEN_T9, 8, 2);
+ mxt_write_object(data,
+ SPT_CTECONFIG_T46, 3, 24);
+ }
/* reset */
- if (msg[1] & 0x80)
+ if (msg[1] & 0x80) {
dev_info(&data->client->dev, "reset is ongoing\n");
+
+ if (data->charging_mode)
+ set_charger_config(data, 0);
+ else
+ schedule_delayed_work(&data->acq_int_dwork, HZ * 3);
+ }
}
static void mxt_treat_T9_object(struct mxt_data *data, u8 *msg)
@@ -531,35 +782,64 @@ static void mxt_treat_T9_object(struct mxt_data *data, u8 *msg)
return;
if (msg[1] & RELEASE_MSG_MASK) {
- data->fingers[id].z = 0;
data->fingers[id].w = msg[5];
- data->finger_mask |= 1U << id;
data->fingers[id].state = MXT_STATE_RELEASE;
+ mxt_report_input_data(data);
} else if ((msg[1] & DETECT_MSG_MASK)
&& (msg[1] & (PRESS_MSG_MASK | MOVE_MSG_MASK))) {
- data->fingers[id].z = msg[6];
- data->fingers[id].w = msg[5];
data->fingers[id].x = (((msg[2] << 4) | (msg[4] >> 4))
>> data->x_dropbits);
data->fingers[id].y = (((msg[3] << 4) | (msg[4] & 0xF))
>> data->y_dropbits);
+ data->fingers[id].w = msg[5];
+#ifndef CONFIG_INPUT_WACOM
+ /* workaround for the hovering issue */
+ if (msg[1] & PRESS_MSG_MASK) {
+ if (data->fingers[id].z == msg[6]) {
+ if (data->pdata->max_z == msg[6])
+ data->fingers[id].z = msg[6] - 1;
+ else
+ data->fingers[id].z = msg[6] + 1;
+ }
+ } else
+ data->fingers[id].z = msg[6];
+#else
+ data->fingers[id].z = msg[6];
+#endif
+
+#if TSP_USE_SHAPETOUCH
+ data->fingers[id].component = msg[7];
+#endif
data->finger_mask |= 1U << id;
if (msg[1] & PRESS_MSG_MASK) {
data->fingers[id].state = MXT_STATE_PRESS;
data->fingers[id].mcount = 0;
+
+#if CHECK_ANTITOUCH
+ if (data->check_autocal)
+ mxt_check_coordinate(data, 1, id,
+ &data->fingers[id].x,
+ &data->fingers[id].y);
+#endif
+
} else if (msg[1] & MOVE_MSG_MASK) {
data->fingers[id].mcount += 1;
+
+#if CHECK_ANTITOUCH
+ if (data->check_autocal)
+ mxt_check_coordinate(data, 0, id,
+ &data->fingers[id].x,
+ &data->fingers[id].y);
+#endif
}
#if TSP_BOOSTER
- if (data->booster.touch_cpu_lock_status == false)
- mxt_set_dvfs_on(data);
+ mxt_set_dvfs_on(data, true);
#endif
} else if ((msg[1] & SUPPRESS_MSG_MASK)
&& (data->fingers[id].state != MXT_STATE_INACTIVE)) {
- data->fingers[id].z = 0;
data->fingers[id].w = msg[5];
data->fingers[id].state = MXT_STATE_RELEASE;
data->finger_mask |= 1U << id;
@@ -582,6 +862,116 @@ static void mxt_treat_T42_object(struct mxt_data *data, u8 *msg)
dev_info(&data->client->dev, "palm touch released\n");
}
+static void mxt_treat_T57_object(struct mxt_data *data, u8 *msg)
+{
+#if CHECK_ANTITOUCH
+ u16 tch_area = 0, atch_area = 0;
+
+ tch_area = msg[3] | (msg[4] << 8);
+ atch_area = msg[5] | (msg[6] << 8);
+ if (data->check_antitouch) {
+ if (tch_area) {
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "TCHAREA=%d\n", tch_area);
+
+ /* First Touch After Calibration */
+ if (data->check_timer == 0) {
+ mxt_t61_timer_set(data,
+ MXT_T61_TIMER_ONESHOT,
+ MXT_T61_TIMER_CMD_START,
+ 3000);
+ data->check_timer = 1;
+ }
+
+ if (tch_area <= 2)
+ mxt_t8_autocal_set(data, 5);
+
+ if (atch_area > 5) {
+ if (atch_area - tch_area > 0) {
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "Case:1 TCHAREA=%d ATCHAREA=%d\n",
+ tch_area, atch_area);
+ mxt_calibrate_chip(data);
+ }
+ }
+
+ } else {
+ if (atch_area) {
+ /* Only Anti-touch */
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "Case:2 TCHAREA=%d ATCHAREA=%d\n",
+ tch_area, atch_area);
+ mxt_calibrate_chip(data);
+ }
+ }
+ }
+
+ if (data->check_calgood == 1) {
+ if (tch_area) {
+ if ((atch_area - tch_area) > 8) {
+ if (tch_area < 35) {
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "Cal Not Good 1 - %d %d\n",
+ atch_area, tch_area);
+ mxt_calibrate_chip(data);
+ }
+ }
+ if (((tch_area - atch_area) >= 40) &&
+ (atch_area > 4)) {
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "Cal Not Good 2 - %d %d\n",
+ atch_area, tch_area);
+ mxt_calibrate_chip(data);
+ }
+ } else {
+ if (atch_area) {
+ /* Only Anti-touch */
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "Cal Not Good 3 - %d %d\n",
+ atch_area, tch_area);
+ mxt_calibrate_chip(data);
+ }
+ }
+ }
+
+#endif /* CHECK_ANTITOUCH */
+
+#if TSP_USE_SHAPETOUCH
+ data->sumsize = msg[1] + (msg[2] << 8);
+#endif /* TSP_USE_SHAPETOUCH */
+
+}
+
+#if CHECK_ANTITOUCH
+static void mxt_treat_T61_object(struct mxt_data *data, u8 *msg)
+{
+ if ((msg[1] & 0xa0) == 0xa0) {
+
+ if (data->check_calgood == 1)
+ data->check_calgood = 0;
+
+ if (data->check_antitouch) {
+ if (data->debug_log)
+ dev_info(&data->client->dev,
+ "SPT_TIMER_T61 Stop\n");
+ data->check_antitouch = 0;
+ data->check_timer = 0;
+ mxt_t8_autocal_set(data, 0);
+ data->check_calgood = 1;
+ mxt_t61_timer_set(data,
+ MXT_T61_TIMER_ONESHOT,
+ MXT_T61_TIMER_CMD_START, 10000);
+ }
+ }
+}
+#endif /* CHECK_ANTITOUCH */
+
static irqreturn_t mxt_irq_thread(int irq, void *ptr)
{
struct mxt_data *data = ptr;
@@ -597,7 +987,7 @@ static irqreturn_t mxt_irq_thread(int irq, void *ptr)
print_hex_dump(KERN_INFO, "MXT MSG:",
DUMP_PREFIX_NONE, 16, 1,
msg, sizeof(msg), false);
-#endif
+#endif /* TSP_ITDEV */
object_type = mxt_reportid_to_type(data, msg[0] , &instance);
if (object_type == RESERVED_T0)
@@ -607,20 +997,33 @@ static irqreturn_t mxt_irq_thread(int irq, void *ptr)
case GEN_COMMANDPROCESSOR_T6:
mxt_treat_T6_object(data, msg);
break;
+
case TOUCH_MULTITOUCHSCREEN_T9:
mxt_treat_T9_object(data, msg);
break;
+
case PROCI_TOUCHSUPPRESSION_T42:
mxt_treat_T42_object(data, msg);
break;
+
+ case PROCI_EXTRATOUCHSCREENDATA_T57:
+ mxt_treat_T57_object(data, msg);
+ break;
+
+#if CHECK_ANTITOUCH
+ case SPT_TIMER_T61:
+ mxt_treat_T61_object(data, msg);
+ break;
+#endif /* CHECK_ANTITOUCH */
+
default:
-#if TSP_DEBUG_INFO
- dev_info(&data->client->dev, "Untreated Object type[%d]\t"
- "message[0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,"
- "0x%x,0x%x,0x%x]\n",
- object_type, msg[0], msg[1], msg[2],
- msg[3], msg[4], msg[5], msg[6], msg[7], msg[8]);
-#endif
+ if (data->debug_log)
+ dev_info(&data->client->dev, "Untreated Object type[%d]\t"
+ "message[0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,"
+ "0x%x,0x%x,0x%x]\n",
+ object_type, msg[0], msg[1],
+ msg[2], msg[3], msg[4], msg[5],
+ msg[6], msg[7], msg[8]);
break;
}
} while (!gpio_get_value(data->pdata->gpio_read_done));
@@ -639,7 +1042,6 @@ static int mxt_internal_suspend(struct mxt_data *data)
for (i = 0; i < data->num_fingers; i++) {
if (data->fingers[i].state == MXT_STATE_INACTIVE)
continue;
- data->fingers[i].z = 0;
data->fingers[i].state = MXT_STATE_RELEASE;
count++;
}
@@ -647,11 +1049,7 @@ static int mxt_internal_suspend(struct mxt_data *data)
mxt_report_input_data(data);
#if TSP_BOOSTER
- cancel_delayed_work(&data->booster.dvfs_dwork);
- if (data->booster.touch_cpu_lock_status) {
- exynos_cpufreq_lock_free(DVFS_LOCK_ID_TSP);
- data->booster.touch_cpu_lock_status = false;
- }
+ mxt_set_dvfs_on(data, false);
#endif
data->pdata->power_off();
@@ -662,7 +1060,6 @@ static int mxt_internal_suspend(struct mxt_data *data)
static int mxt_internal_resume(struct mxt_data *data)
{
data->pdata->power_on();
-
return 0;
}
@@ -769,8 +1166,8 @@ static int mxt_fw_write(struct i2c_client *client,
return 0;
}
-static int mxt_load_fw(struct mxt_data *data,
- const char *fn, bool is_bootmode)
+static int mxt_flash_fw(struct mxt_data *data,
+ const u8 *fw_data, size_t fw_size)
{
struct device *dev = &data->client->dev;
struct i2c_client *client = data->client_boot;
@@ -778,29 +1175,6 @@ static int mxt_load_fw(struct mxt_data *data,
unsigned int pos = 0;
int ret;
- const struct firmware *fw = NULL;
-
- dev_info(dev, "Enter updating firmware from %s\n",
- is_bootmode ? "Boot" : "App");
-
- ret = request_firmware(&fw, fn, dev);
- if (ret) {
- dev_err(dev, "Unable to open firmware %s\n", fn);
- return ret;
- }
-
- if (!is_bootmode) {
- /* Change to the bootloader mode */
- ret = mxt_write_object(data, GEN_COMMANDPROCESSOR_T6,
- CMD_RESET_OFFSET, MXT_BOOT_VALUE);
- if (ret) {
- dev_err(dev, "Fail to change bootloader mode\n");
- release_firmware(fw);
- return ret;
- }
- msleep(MXT_1664S_SW_RESET_TIME);
- }
-
ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
if (ret) {
/*may still be unlocked from previous update attempt */
@@ -812,7 +1186,7 @@ static int mxt_load_fw(struct mxt_data *data,
/* Unlock bootloader */
mxt_unlock_bootloader(client);
}
- while (pos < fw->size) {
+ while (pos < fw_size) {
ret = mxt_check_bootloader(client,
MXT_WAITING_FRAME_DATA);
if (ret) {
@@ -820,7 +1194,7 @@ static int mxt_load_fw(struct mxt_data *data,
goto out;
}
- frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+ frame_size = ((*(fw_data + pos) << 8) | *(fw_data + pos + 1));
/*
* We should add 2 at frame size as the the firmware data is not
@@ -830,7 +1204,7 @@ static int mxt_load_fw(struct mxt_data *data,
frame_size += 2;
/* Write one frame to device */
- mxt_fw_write(client, fw->data + pos, frame_size);
+ mxt_fw_write(client, fw_data + pos, frame_size);
ret = mxt_check_bootloader(client,
MXT_FRAME_CRC_PASS);
@@ -842,30 +1216,62 @@ static int mxt_load_fw(struct mxt_data *data,
pos += frame_size;
dev_info(dev, "Updated %d bytes / %zd bytes\n",
- pos, fw->size);
+ pos, fw_size);
msleep(20);
}
dev_info(dev, "Sucess updating firmware\n");
out:
- release_firmware(fw);
-
return ret;
}
-static void mxt_start(struct mxt_data *data)
+static int mxt_load_fw(struct mxt_data *data, bool is_bootmode)
{
- /* Touch report enable */
- mxt_write_object(data,
- TOUCH_MULTITOUCHSCREEN_T9, 0, 139);
-}
+ struct i2c_client *client = data->client;
+ struct device *dev = &client->dev;
+ const struct firmware *fw = NULL;
+ char *fw_path;
+ int ret;
-static void mxt_stop(struct mxt_data *data)
-{
- /* Touch report disable */
- mxt_write_object(data,
- TOUCH_MULTITOUCHSCREEN_T9, 0, 0);
+ dev_info(dev, "Enter updating firmware from %s\n",
+ is_bootmode ? "Boot" : "App");
+
+ fw_path = kzalloc(MXT_MAX_FW_PATH, GFP_KERNEL);
+ if (fw_path == NULL) {
+ dev_err(dev, "failed to allocate firmware path.\n");
+ return -ENOMEM;
+ }
+
+ snprintf(fw_path, MXT_MAX_FW_PATH, "tsp_atmel/%s", MXT_FW_NAME);
+ ret = request_firmware(&fw, fw_path, dev);
+ if (ret) {
+ dev_err(dev, "Unable to open firmware %s\n", fw_path);
+ goto out;
+ }
+
+ if (!is_bootmode) {
+ /* Change to the bootloader mode */
+ ret = mxt_write_object(data, GEN_COMMANDPROCESSOR_T6,
+ CMD_RESET_OFFSET, MXT_BOOT_VALUE);
+ if (ret) {
+ dev_err(dev, "Fail to change bootloader mode\n");
+ goto out;
+ }
+ msleep(MXT_1664S_SW_RESET_TIME);
+ }
+
+ ret = mxt_flash_fw(data, fw->data, fw->size);
+ if (ret)
+ goto out;
+ else
+ msleep(MXT_1664S_FW_RESET_TIME);
+
+out:
+ kfree(fw_path);
+ release_firmware(fw);
+
+ return ret;
}
static int mxt_input_open(struct input_dev *dev)
@@ -884,6 +1290,20 @@ static void mxt_input_close(struct input_dev *dev)
mxt_stop(data);
}
+static void late_resume_dwork(struct work_struct *work)
+{
+ struct mxt_data *data =
+ container_of(work, struct mxt_data,
+ resume_dwork.work);
+
+ set_charger_config(data, 0);
+
+ if (!data->charging_mode)
+ schedule_delayed_work(&data->acq_int_dwork, HZ * 3);
+
+ enable_irq(data->client->irq);
+}
+
#ifdef CONFIG_HAS_EARLYSUSPEND
#define mxt_suspend NULL
#define mxt_resume NULL
@@ -892,12 +1312,16 @@ static void mxt_early_suspend(struct early_suspend *h)
{
struct mxt_data *data = container_of(h, struct mxt_data,
early_suspend);
+#if TSP_INFORM_CHARGER
+ cancel_delayed_work_sync(&data->noti_dwork);
+#endif
+
mutex_lock(&data->lock);
if (data->mxt_enabled) {
disable_irq(data->client->irq);
- mxt_internal_suspend(data);
data->mxt_enabled = false;
+ mxt_internal_suspend(data);
} else {
dev_err(&data->client->dev,
"%s. but touch already off\n", __func__);
@@ -910,6 +1334,7 @@ static void mxt_late_resume(struct early_suspend *h)
{
struct mxt_data *data = container_of(h, struct mxt_data,
early_suspend);
+
mutex_lock(&data->lock);
if (data->mxt_enabled) {
@@ -918,7 +1343,8 @@ static void mxt_late_resume(struct early_suspend *h)
} else {
mxt_internal_resume(data);
data->mxt_enabled = true;
- enable_irq(data->client->irq);
+ schedule_delayed_work(&data->resume_dwork,
+ msecs_to_jiffies(MXT_1664S_HW_RESET_TIME));
}
mutex_unlock(&data->lock);
@@ -973,12 +1399,10 @@ static int mxt_init_touch(struct mxt_data *data)
dev_err(dev, "Failed to verify bootloader's status\n");
goto out;
} else {
- ret = mxt_load_fw(data, MXT_FW_NAME, true);
+ ret = mxt_load_fw(data, true);
if (ret) {
dev_err(dev, "Failed updating firmware\n");
goto out;
- } else {
- msleep(MXT_1664S_FW_RESET_TIME);
}
}
ret = mxt_get_id_info(data);
@@ -1067,13 +1491,11 @@ static int mxt_rest_init_touch(struct mxt_data *data)
if (data->info.version != MXT_FIRM_VERSION
|| (data->info.version == MXT_FIRM_VERSION
&& data->info.build != MXT_FIRM_BUILD)) {
- if (mxt_load_fw(data, MXT_FW_NAME, false)) {
+ if (mxt_load_fw(data, false))
goto out;
- } else {
- msleep(MXT_1664S_FW_RESET_TIME);
+ else
mxt_init_touch(data);
}
- }
#endif
} else {
dev_err(dev, "There is no valid TSP ID\n");
@@ -1102,6 +1524,60 @@ out:
return ret;
}
+#if TSP_SEC_SYSFS
+int mxt_flash_fw_from_sysfs(struct mxt_data *data,
+ const u8 *fw_data, size_t fw_size)
+{
+ struct i2c_client *client = data->client;
+ int ret;
+
+ /* Change to the bootloader mode */
+ ret = mxt_write_object(data, GEN_COMMANDPROCESSOR_T6,
+ CMD_RESET_OFFSET, MXT_BOOT_VALUE);
+ if (ret) {
+ dev_err(&client->dev, "Fail to change bootloader mode\n");
+ goto out;
+ }
+ msleep(MXT_1664S_SW_RESET_TIME);
+
+ /* writing firmware */
+ ret = mxt_flash_fw(data, fw_data, fw_size);
+ if (ret) {
+ dev_err(&client->dev, "Failed updating firmware: %s\n",
+ __func__);
+ goto out;
+ }
+ msleep(MXT_1664S_FW_RESET_TIME);
+
+ ret = mxt_init_touch(data);
+ if (ret) {
+ dev_err(&client->dev, "initialization failed: %s\n", __func__);
+ goto out;
+ }
+
+ /* rest touch ic such as write config and backup */
+ ret = mxt_write_configuration(data);
+ if (ret) {
+ dev_err(&client->dev, "Failed init write config\n");
+ goto out;
+ }
+ ret = mxt_backup(data);
+ if (ret) {
+ dev_err(&client->dev, "Failed backup NV data\n");
+ goto out;
+ }
+ /* reset the touch IC. */
+ ret = mxt_reset(data);
+ if (ret) {
+ dev_err(&client->dev, "Failed Reset IC\n");
+ goto out;
+ }
+ msleep(MXT_1664S_SW_RESET_TIME);
+out:
+ return ret;
+}
+#endif
+
static int __devinit mxt_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1133,6 +1609,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
data->pdata = pdata;
data->num_fingers = pdata->max_finger_touches;
data->mxt_enabled = true;
+ data->config_version = pdata->config_version;
mutex_init(&data->lock);
input_dev->name = "sec_touchscreen";
@@ -1157,6 +1634,11 @@ static int __devinit mxt_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_MT_PRESSURE, pdata->min_z,
pdata->max_z, 0, 0);
+#if TSP_USE_SHAPETOUCH
+ input_set_abs_params(input_dev, ABS_MT_COMPONENT, 0, 255, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_SUMSIZE, 0, 16 * 26, 0, 0);
+#endif
+
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
@@ -1181,7 +1663,10 @@ static int __devinit mxt_probe(struct i2c_client *client,
if (ret)
goto err_reg_dev;
+ INIT_DELAYED_WORK(&data->resume_dwork, late_resume_dwork);
+
data->pdata->power_on();
+ msleep(MXT_1664S_HW_RESET_TIME);
/* init touch ic */
ret = mxt_init_touch(data);
@@ -1200,6 +1685,16 @@ static int __devinit mxt_probe(struct i2c_client *client,
*/
mxt_stop(data);
+#if TSP_INFORM_CHARGER
+ /* Register callbacks */
+ /* To inform tsp , charger connection status*/
+ data->callbacks.inform_charger = inform_charger;
+ if (pdata->register_cb) {
+ u8 *tmp = pdata->register_cb(&data->callbacks);
+ inform_charger_init(data, tmp);
+ }
+#endif
+
ret = request_threaded_irq(client->irq, NULL, mxt_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mxt_ts", data);
@@ -1208,7 +1703,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
goto err_free_mem;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
- data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ data->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
data->early_suspend.suspend = mxt_early_suspend;
data->early_suspend.resume = mxt_late_resume;
register_early_suspend(&data->early_suspend);
@@ -1224,7 +1719,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
ret = mxt_init_dvfs(data);
if (ret < 0) {
dev_err(&client->dev, "Fail get dvfs level for touch booster\n");
- goto err_irq;
+ goto err_free_mem;
}
#endif
dev_info(&client->dev, "Mxt touch success initialization\n");
@@ -1256,6 +1751,9 @@ static int __devexit mxt_remove(struct i2c_client *client)
unregister_early_suspend(&data->early_suspend);
#endif
free_irq(client->irq, data);
+#if TSP_INFORM_CHARGER
+ kfree(data->charger_inform_buf);
+#endif
kfree(data->objects);
kfree(data->rid_map);
gpio_free(data->pdata->gpio_read_done);