Skip to content

Commit 059d6c2

Browse files
jinglewudtor
authored andcommitted
Input: elan_i2c - add support for different firmware page sizes
Prepare driver for devices that use different sizes of firmware pages. Signed-off-by: Jingle Wu <[email protected]> Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent df10cc8 commit 059d6c2

File tree

4 files changed

+41
-25
lines changed

4 files changed

+41
-25
lines changed

drivers/input/mouse/elan_i2c.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
3434
#define ETP_FW_IAP_INTF_ERR (1 << 4)
3535
#define ETP_FW_PAGE_SIZE 64
36+
#define ETP_FW_PAGE_SIZE_128 128
37+
#define ETP_FW_PAGE_SIZE_512 512
3638
#define ETP_FW_SIGNATURE_SIZE 6
3739

3840
struct i2c_client;
@@ -73,7 +75,7 @@ struct elan_transport_ops {
7375
int (*iap_reset)(struct i2c_client *client);
7476

7577
int (*prepare_fw_update)(struct i2c_client *client);
76-
int (*write_fw_block)(struct i2c_client *client,
78+
int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size,
7779
const u8 *page, u16 checksum, int idx);
7880
int (*finish_fw_update)(struct i2c_client *client,
7981
struct completion *reset_done);

drivers/input/mouse/elan_i2c_core.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ struct elan_tp_data {
8989
u8 mode;
9090
u16 ic_type;
9191
u16 fw_validpage_count;
92-
u16 fw_signature_address;
92+
u16 fw_page_size;
93+
u32 fw_signature_address;
9394

9495
bool irq_wake;
9596

@@ -101,7 +102,7 @@ struct elan_tp_data {
101102
};
102103

103104
static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
104-
u16 *signature_address)
105+
u32 *signature_address, u16 *page_size)
105106
{
106107
switch (ic_type) {
107108
case 0x00:
@@ -130,12 +131,15 @@ static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
130131
/* unknown ic type clear value */
131132
*validpage_count = 0;
132133
*signature_address = 0;
134+
*page_size = 0;
133135
return -ENXIO;
134136
}
135137

136138
*signature_address =
137139
(*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
138140

141+
*page_size = ETP_FW_PAGE_SIZE;
142+
139143
return 0;
140144
}
141145

@@ -336,7 +340,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
336340
return error;
337341

338342
error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count,
339-
&data->fw_signature_address);
343+
&data->fw_signature_address,
344+
&data->fw_page_size);
340345
if (error)
341346
dev_warn(&data->client->dev,
342347
"unexpected iap version %#04x (ic type: %#04x), firmware update will not work\n",
@@ -424,14 +429,14 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
424429
* IAP firmware updater related routines
425430
**********************************************************
426431
*/
427-
static int elan_write_fw_block(struct elan_tp_data *data,
432+
static int elan_write_fw_block(struct elan_tp_data *data, u16 page_size,
428433
const u8 *page, u16 checksum, int idx)
429434
{
430435
int retry = ETP_RETRY_COUNT;
431436
int error;
432437

433438
do {
434-
error = data->ops->write_fw_block(data->client,
439+
error = data->ops->write_fw_block(data->client, page_size,
435440
page, checksum, idx);
436441
if (!error)
437442
return 0;
@@ -460,15 +465,16 @@ static int __elan_update_firmware(struct elan_tp_data *data,
460465

461466
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
462467

463-
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
468+
boot_page_count = (iap_start_addr * 2) / data->fw_page_size;
464469
for (i = boot_page_count; i < data->fw_validpage_count; i++) {
465470
u16 checksum = 0;
466-
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
471+
const u8 *page = &fw->data[i * data->fw_page_size];
467472

468-
for (j = 0; j < ETP_FW_PAGE_SIZE; j += 2)
473+
for (j = 0; j < data->fw_page_size; j += 2)
469474
checksum += ((page[j + 1] << 8) | page[j]);
470475

471-
error = elan_write_fw_block(data, page, checksum, i);
476+
error = elan_write_fw_block(data, data->fw_page_size,
477+
page, checksum, i);
472478
if (error) {
473479
dev_err(dev, "write page %d fail: %d\n", i, error);
474480
return error;

drivers/input/mouse/elan_i2c_i2c.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/interrupt.h>
2020
#include <linux/jiffies.h>
2121
#include <linux/kernel.h>
22+
#include <linux/slab.h>
2223
#include <linux/sched.h>
2324
#include <asm/unaligned.h>
2425

@@ -592,45 +593,52 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client)
592593
return 0;
593594
}
594595

595-
static int elan_i2c_write_fw_block(struct i2c_client *client,
596+
static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size,
596597
const u8 *page, u16 checksum, int idx)
597598
{
598599
struct device *dev = &client->dev;
599-
u8 page_store[ETP_FW_PAGE_SIZE + 4];
600+
u8 *page_store;
600601
u8 val[3];
601602
u16 result;
602603
int ret, error;
603604

605+
page_store = kmalloc(fw_page_size + 4, GFP_KERNEL);
606+
if (!page_store)
607+
return -ENOMEM;
608+
604609
page_store[0] = ETP_I2C_IAP_REG_L;
605610
page_store[1] = ETP_I2C_IAP_REG_H;
606-
memcpy(&page_store[2], page, ETP_FW_PAGE_SIZE);
611+
memcpy(&page_store[2], page, fw_page_size);
607612
/* recode checksum at last two bytes */
608-
put_unaligned_le16(checksum, &page_store[ETP_FW_PAGE_SIZE + 2]);
613+
put_unaligned_le16(checksum, &page_store[fw_page_size + 2]);
609614

610-
ret = i2c_master_send(client, page_store, sizeof(page_store));
611-
if (ret != sizeof(page_store)) {
615+
ret = i2c_master_send(client, page_store, fw_page_size + 4);
616+
if (ret != fw_page_size + 4) {
612617
error = ret < 0 ? ret : -EIO;
613618
dev_err(dev, "Failed to write page %d: %d\n", idx, error);
614-
return error;
619+
goto exit;
615620
}
616621

617622
/* Wait for F/W to update one page ROM data. */
618-
msleep(35);
623+
msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35);
619624

620625
error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val);
621626
if (error) {
622627
dev_err(dev, "Failed to read IAP write result: %d\n", error);
623-
return error;
628+
goto exit;
624629
}
625630

626631
result = le16_to_cpup((__le16 *)val);
627632
if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) {
628633
dev_err(dev, "IAP reports failed write: %04hx\n",
629634
result);
630-
return -EIO;
635+
error = -EIO;
636+
goto exit;
631637
}
632638

633-
return 0;
639+
exit:
640+
kfree(page_store);
641+
return error;
634642
}
635643

636644
static int elan_i2c_finish_fw_update(struct i2c_client *client,

drivers/input/mouse/elan_i2c_smbus.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client)
414414
}
415415

416416

417-
static int elan_smbus_write_fw_block(struct i2c_client *client,
417+
static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size,
418418
const u8 *page, u16 checksum, int idx)
419419
{
420420
struct device *dev = &client->dev;
@@ -429,7 +429,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
429429
*/
430430
error = i2c_smbus_write_block_data(client,
431431
ETP_SMBUS_WRITE_FW_BLOCK,
432-
ETP_FW_PAGE_SIZE / 2,
432+
fw_page_size / 2,
433433
page);
434434
if (error) {
435435
dev_err(dev, "Failed to write page %d (part %d): %d\n",
@@ -439,8 +439,8 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
439439

440440
error = i2c_smbus_write_block_data(client,
441441
ETP_SMBUS_WRITE_FW_BLOCK,
442-
ETP_FW_PAGE_SIZE / 2,
443-
page + ETP_FW_PAGE_SIZE / 2);
442+
fw_page_size / 2,
443+
page + fw_page_size / 2);
444444
if (error) {
445445
dev_err(dev, "Failed to write page %d (part %d): %d\n",
446446
idx, 2, error);

0 commit comments

Comments
 (0)