|
@@ -87,6 +87,9 @@
|
|
#define MXT_COMMAND_REPORTALL 3
|
|
#define MXT_COMMAND_REPORTALL 3
|
|
#define MXT_COMMAND_DIAGNOSTIC 5
|
|
#define MXT_COMMAND_DIAGNOSTIC 5
|
|
|
|
|
|
|
|
+/* Define for T6 status byte */
|
|
|
|
+#define MXT_T6_STATUS_RESET (1 << 7)
|
|
|
|
+
|
|
/* MXT_GEN_POWER_T7 field */
|
|
/* MXT_GEN_POWER_T7 field */
|
|
#define MXT_POWER_IDLEACQINT 0
|
|
#define MXT_POWER_IDLEACQINT 0
|
|
#define MXT_POWER_ACTVACQINT 1
|
|
#define MXT_POWER_ACTVACQINT 1
|
|
@@ -178,9 +181,13 @@
|
|
|
|
|
|
/* Define for MXT_GEN_COMMAND_T6 */
|
|
/* Define for MXT_GEN_COMMAND_T6 */
|
|
#define MXT_BOOT_VALUE 0xa5
|
|
#define MXT_BOOT_VALUE 0xa5
|
|
|
|
+#define MXT_RESET_VALUE 0x01
|
|
#define MXT_BACKUP_VALUE 0x55
|
|
#define MXT_BACKUP_VALUE 0x55
|
|
|
|
+
|
|
|
|
+/* Delay times */
|
|
#define MXT_BACKUP_TIME 50 /* msec */
|
|
#define MXT_BACKUP_TIME 50 /* msec */
|
|
#define MXT_RESET_TIME 200 /* msec */
|
|
#define MXT_RESET_TIME 200 /* msec */
|
|
|
|
+#define MXT_RESET_TIMEOUT 3000 /* msec */
|
|
#define MXT_FW_RESET_TIME 3000 /* msec */
|
|
#define MXT_FW_RESET_TIME 3000 /* msec */
|
|
#define MXT_FW_CHG_TIMEOUT 300 /* msec */
|
|
#define MXT_FW_CHG_TIMEOUT 300 /* msec */
|
|
|
|
|
|
@@ -255,12 +262,16 @@ struct mxt_data {
|
|
|
|
|
|
/* Cached parameters from object table */
|
|
/* Cached parameters from object table */
|
|
u8 T6_reportid;
|
|
u8 T6_reportid;
|
|
|
|
+ u16 T6_address;
|
|
u8 T9_reportid_min;
|
|
u8 T9_reportid_min;
|
|
u8 T9_reportid_max;
|
|
u8 T9_reportid_max;
|
|
u8 T19_reportid;
|
|
u8 T19_reportid;
|
|
|
|
|
|
/* for fw update in bootloader */
|
|
/* for fw update in bootloader */
|
|
struct completion bl_completion;
|
|
struct completion bl_completion;
|
|
|
|
+
|
|
|
|
+ /* for reset handling */
|
|
|
|
+ struct completion reset_completion;
|
|
};
|
|
};
|
|
|
|
|
|
static size_t mxt_obj_size(const struct mxt_object *obj)
|
|
static size_t mxt_obj_size(const struct mxt_object *obj)
|
|
@@ -344,10 +355,11 @@ static void mxt_dump_message(struct device *dev,
|
|
message->reportid, 7, message->message);
|
|
message->reportid, 7, message->message);
|
|
}
|
|
}
|
|
|
|
|
|
-static int mxt_wait_for_chg(struct mxt_data *data, unsigned int timeout_ms)
|
|
|
|
|
|
+static int mxt_wait_for_completion(struct mxt_data *data,
|
|
|
|
+ struct completion *comp,
|
|
|
|
+ unsigned int timeout_ms)
|
|
{
|
|
{
|
|
struct device *dev = &data->client->dev;
|
|
struct device *dev = &data->client->dev;
|
|
- struct completion *comp = &data->bl_completion;
|
|
|
|
unsigned long timeout = msecs_to_jiffies(timeout_ms);
|
|
unsigned long timeout = msecs_to_jiffies(timeout_ms);
|
|
long ret;
|
|
long ret;
|
|
|
|
|
|
@@ -375,7 +387,8 @@ recheck:
|
|
* CHG assertion before reading the status byte.
|
|
* CHG assertion before reading the status byte.
|
|
* Once the status byte has been read, the line is deasserted.
|
|
* Once the status byte has been read, the line is deasserted.
|
|
*/
|
|
*/
|
|
- ret = mxt_wait_for_chg(data, MXT_FW_CHG_TIMEOUT);
|
|
|
|
|
|
+ ret = mxt_wait_for_completion(data, &data->bl_completion,
|
|
|
|
+ MXT_FW_CHG_TIMEOUT);
|
|
if (ret) {
|
|
if (ret) {
|
|
/*
|
|
/*
|
|
* TODO: handle -ERESTARTSYS better by terminating
|
|
* TODO: handle -ERESTARTSYS better by terminating
|
|
@@ -654,6 +667,9 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
|
|
unsigned csum = mxt_extract_T6_csum(&payload[1]);
|
|
unsigned csum = mxt_extract_T6_csum(&payload[1]);
|
|
dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
|
|
dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
|
|
status, csum);
|
|
status, csum);
|
|
|
|
+
|
|
|
|
+ if (status & MXT_T6_STATUS_RESET)
|
|
|
|
+ complete(&data->reset_completion);
|
|
} else if (mxt_is_T9_message(data, &message)) {
|
|
} else if (mxt_is_T9_message(data, &message)) {
|
|
int id = reportid - data->T9_reportid_min;
|
|
int id = reportid - data->T9_reportid_min;
|
|
mxt_input_touchevent(data, &message, id);
|
|
mxt_input_touchevent(data, &message, id);
|
|
@@ -687,6 +703,59 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
|
|
return mxt_process_messages_until_invalid(data);
|
|
return mxt_process_messages_until_invalid(data);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
|
|
|
|
+ u8 value, bool wait)
|
|
|
|
+{
|
|
|
|
+ u16 reg;
|
|
|
|
+ u8 command_register;
|
|
|
|
+ int timeout_counter = 0;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ reg = data->T6_address + cmd_offset;
|
|
|
|
+
|
|
|
|
+ ret = mxt_write_reg(data->client, reg, value);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ if (!wait)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ do {
|
|
|
|
+ msleep(20);
|
|
|
|
+ ret = __mxt_read_reg(data->client, reg, 1, &command_register);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+ } while (command_register != 0 && timeout_counter++ <= 100);
|
|
|
|
+
|
|
|
|
+ if (timeout_counter > 100) {
|
|
|
|
+ dev_err(&data->client->dev, "Command failed!\n");
|
|
|
|
+ return -EIO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mxt_soft_reset(struct mxt_data *data)
|
|
|
|
+{
|
|
|
|
+ struct device *dev = &data->client->dev;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ dev_info(dev, "Resetting chip\n");
|
|
|
|
+
|
|
|
|
+ reinit_completion(&data->reset_completion);
|
|
|
|
+
|
|
|
|
+ ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ ret = mxt_wait_for_completion(data, &data->reset_completion,
|
|
|
|
+ MXT_RESET_TIMEOUT);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int mxt_check_reg_init(struct mxt_data *data)
|
|
static int mxt_check_reg_init(struct mxt_data *data)
|
|
{
|
|
{
|
|
const struct mxt_platform_data *pdata = data->pdata;
|
|
const struct mxt_platform_data *pdata = data->pdata;
|
|
@@ -800,6 +869,7 @@ static int mxt_get_object_table(struct mxt_data *data)
|
|
switch (object->type) {
|
|
switch (object->type) {
|
|
case MXT_GEN_COMMAND_T6:
|
|
case MXT_GEN_COMMAND_T6:
|
|
data->T6_reportid = min_id;
|
|
data->T6_reportid = min_id;
|
|
|
|
+ data->T6_address = object->start_address;
|
|
break;
|
|
break;
|
|
case MXT_TOUCH_MULTI_T9:
|
|
case MXT_TOUCH_MULTI_T9:
|
|
data->T9_reportid_min = min_id;
|
|
data->T9_reportid_min = min_id;
|
|
@@ -853,16 +923,10 @@ static int mxt_initialize(struct mxt_data *data)
|
|
if (error)
|
|
if (error)
|
|
goto err_free_object_table;
|
|
goto err_free_object_table;
|
|
|
|
|
|
- /* Backup to memory */
|
|
|
|
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
|
|
|
- MXT_COMMAND_BACKUPNV,
|
|
|
|
- MXT_BACKUP_VALUE);
|
|
|
|
- msleep(MXT_BACKUP_TIME);
|
|
|
|
-
|
|
|
|
- /* Soft reset */
|
|
|
|
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
|
|
|
- MXT_COMMAND_RESET, 1);
|
|
|
|
- msleep(MXT_RESET_TIME);
|
|
|
|
|
|
+ error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV,
|
|
|
|
+ MXT_BACKUP_VALUE, false);
|
|
|
|
+ if (!error)
|
|
|
|
+ mxt_soft_reset(data);
|
|
|
|
|
|
/* Update matrix size at info struct */
|
|
/* Update matrix size at info struct */
|
|
error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
|
|
error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
|
|
@@ -1004,8 +1068,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
|
|
/* Change to the bootloader mode */
|
|
/* Change to the bootloader mode */
|
|
data->in_bootloader = true;
|
|
data->in_bootloader = true;
|
|
|
|
|
|
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
|
|
|
- MXT_COMMAND_RESET, MXT_BOOT_VALUE);
|
|
|
|
|
|
+ ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto release_firmware;
|
|
|
|
+
|
|
msleep(MXT_RESET_TIME);
|
|
msleep(MXT_RESET_TIME);
|
|
|
|
|
|
/* Change to slave address of bootloader */
|
|
/* Change to slave address of bootloader */
|
|
@@ -1048,7 +1114,8 @@ static int mxt_load_fw(struct device *dev, const char *fn)
|
|
}
|
|
}
|
|
|
|
|
|
/* Wait for flash. */
|
|
/* Wait for flash. */
|
|
- ret = mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
|
|
|
|
|
|
+ ret = mxt_wait_for_completion(data, &data->bl_completion,
|
|
|
|
+ MXT_FW_RESET_TIME);
|
|
if (ret)
|
|
if (ret)
|
|
goto disable_irq;
|
|
goto disable_irq;
|
|
|
|
|
|
@@ -1057,12 +1124,13 @@ static int mxt_load_fw(struct device *dev, const char *fn)
|
|
* the CHG line after bootloading has finished, so ignore potential
|
|
* the CHG line after bootloading has finished, so ignore potential
|
|
* errors.
|
|
* errors.
|
|
*/
|
|
*/
|
|
- mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
|
|
|
|
|
|
+ mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
|
|
|
|
|
|
data->in_bootloader = false;
|
|
data->in_bootloader = false;
|
|
|
|
|
|
disable_irq:
|
|
disable_irq:
|
|
disable_irq(data->irq);
|
|
disable_irq(data->irq);
|
|
|
|
+release_firmware:
|
|
release_firmware(fw);
|
|
release_firmware(fw);
|
|
|
|
|
|
/* Change to slave address of application */
|
|
/* Change to slave address of application */
|
|
@@ -1187,6 +1255,7 @@ static int mxt_probe(struct i2c_client *client,
|
|
data->irq = client->irq;
|
|
data->irq = client->irq;
|
|
|
|
|
|
init_completion(&data->bl_completion);
|
|
init_completion(&data->bl_completion);
|
|
|
|
+ init_completion(&data->reset_completion);
|
|
|
|
|
|
mxt_calc_resolution(data);
|
|
mxt_calc_resolution(data);
|
|
|
|
|
|
@@ -1314,11 +1383,7 @@ static int mxt_resume(struct device *dev)
|
|
struct mxt_data *data = i2c_get_clientdata(client);
|
|
struct mxt_data *data = i2c_get_clientdata(client);
|
|
struct input_dev *input_dev = data->input_dev;
|
|
struct input_dev *input_dev = data->input_dev;
|
|
|
|
|
|
- /* Soft reset */
|
|
|
|
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
|
|
|
- MXT_COMMAND_RESET, 1);
|
|
|
|
-
|
|
|
|
- msleep(MXT_RESET_TIME);
|
|
|
|
|
|
+ mxt_soft_reset(data);
|
|
|
|
|
|
mutex_lock(&input_dev->mutex);
|
|
mutex_lock(&input_dev->mutex);
|
|
|
|
|