Skip to content

Commit

Permalink
Input: elan_i2c - handle firmware updated on newer ICs
Browse files Browse the repository at this point in the history
Newer ICs with IC type value starting with 0x0D and newer bootloader code
use 128-byte firmware pages. Their bootloader also needs to be switched to
proper mode before executing firmware update.

Signed-off-by: Jingle Wu <jingle.wu@emc.com.tw>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Jingle Wu authored and Dmitry Torokhov committed Jul 18, 2020
1 parent 059d6c2 commit bfd9b92
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 7 deletions.
3 changes: 2 additions & 1 deletion drivers/input/mouse/elan_i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ struct elan_transport_ops {
int (*iap_get_mode)(struct i2c_client *client, enum tp_mode *mode);
int (*iap_reset)(struct i2c_client *client);

int (*prepare_fw_update)(struct i2c_client *client);
int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type,
u8 iap_version);
int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size,
const u8 *page, u16 checksum, int idx);
int (*finish_fw_update)(struct i2c_client *client,
Expand Down
15 changes: 11 additions & 4 deletions drivers/input/mouse/elan_i2c_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ struct elan_tp_data {
bool middle_button;
};

static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count,
u32 *signature_address, u16 *page_size)
{
switch (ic_type) {
Expand Down Expand Up @@ -138,7 +138,12 @@ static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
*signature_address =
(*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;

*page_size = ETP_FW_PAGE_SIZE;
if (ic_type >= 0x0D && iap_version >= 1) {
*validpage_count /= 2;
*page_size = ETP_FW_PAGE_SIZE_128;
} else {
*page_size = ETP_FW_PAGE_SIZE;
}

return 0;
}
Expand Down Expand Up @@ -339,7 +344,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;

error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count,
error = elan_get_fwinfo(data->ic_type, data->iap_version,
&data->fw_validpage_count,
&data->fw_signature_address,
&data->fw_page_size);
if (error)
Expand Down Expand Up @@ -459,7 +465,8 @@ static int __elan_update_firmware(struct elan_tp_data *data,
u16 boot_page_count;
u16 sw_checksum = 0, fw_checksum = 0;

error = data->ops->prepare_fw_update(client);
error = data->ops->prepare_fw_update(client, data->ic_type,
data->iap_version);
if (error)
return error;

Expand Down
46 changes: 45 additions & 1 deletion drivers/input/mouse/elan_i2c_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
#define ETP_I2C_CALIBRATE_CMD 0x0316
#define ETP_I2C_MAX_BASELINE_CMD 0x0317
#define ETP_I2C_MIN_BASELINE_CMD 0x0318
#define ETP_I2C_IAP_TYPE_REG 0x0040
#define ETP_I2C_IAP_TYPE_CMD 0x0304

#define ETP_I2C_REPORT_LEN 34
#define ETP_I2C_DESC_LENGTH 30
Expand Down Expand Up @@ -528,7 +530,43 @@ static int elan_i2c_set_flash_key(struct i2c_client *client)
return 0;
}

static int elan_i2c_prepare_fw_update(struct i2c_client *client)
static int elan_read_write_iap_type(struct i2c_client *client)
{
int error;
u16 constant;
u8 val[3];
int retry = 3;

do {
error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD,
ETP_I2C_IAP_TYPE_REG);
if (error) {
dev_err(&client->dev,
"cannot write iap type: %d\n", error);
return error;
}

error = elan_i2c_read_cmd(client, ETP_I2C_IAP_TYPE_CMD, val);
if (error) {
dev_err(&client->dev,
"failed to read iap type register: %d\n",
error);
return error;
}
constant = le16_to_cpup((__le16 *)val);
dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant);

if (constant == ETP_I2C_IAP_TYPE_REG)
return 0;

} while (--retry > 0);

dev_err(&client->dev, "cannot set iap type\n");
return -EIO;
}

static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type,
u8 iap_version)
{
struct device *dev = &client->dev;
int error;
Expand Down Expand Up @@ -568,6 +606,12 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client)
return -EIO;
}

if (ic_type >= 0x0D && iap_version >= 1) {
error = elan_read_write_iap_type(client);
if (error)
return error;
}

/* Set flash key again */
error = elan_i2c_set_flash_key(client);
if (error)
Expand Down
3 changes: 2 additions & 1 deletion drivers/input/mouse/elan_i2c_smbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ static int elan_smbus_set_flash_key(struct i2c_client *client)
return 0;
}

static int elan_smbus_prepare_fw_update(struct i2c_client *client)
static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type,
u8 iap_version)
{
struct device *dev = &client->dev;
int len;
Expand Down

0 comments on commit bfd9b92

Please sign in to comment.