touchpad_elan: add support for CoachZ touchpad
Port probe / update logic from linux driver code (drivers/input/mouse/elan_i2c_i2c.c), and support different page size. BUG=b:169651794 TEST=flash fw successfully on Zed. BRANCH=none Signed-off-by: Ting Shen <phoenixshen@google.com> Change-Id: I2aa7316219d235e28e446de13b0d24fe3c6dac15 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2537415 Reviewed-by: Nicolas Boichat <drinkcat@chromium.org> Commit-Queue: Ting Shen <phoenixshen@chromium.org> Tested-by: Ting Shen <phoenixshen@chromium.org>
This commit is contained in:
parent
8705e537da
commit
215ffecfca
|
@ -91,7 +91,7 @@
|
|||
#define CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_PRESSURE 511
|
||||
#define CONFIG_USB_HID_TOUCHPAD_PHYSICAL_MAX_X 1018 /* tenth of mm */
|
||||
#define CONFIG_USB_HID_TOUCHPAD_PHYSICAL_MAX_Y 566 /* tenth of mm */
|
||||
#define CONFIG_TOUCHPAD_VIRTUAL_SIZE (48*1024)
|
||||
#define CONFIG_TOUCHPAD_VIRTUAL_SIZE (64*1024)
|
||||
#else
|
||||
#error "No touchpad information for board."
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,10 @@ static inline uint64_t be64toh(uint64_t in)
|
|||
#define htobe32 be32toh
|
||||
#define htobe64 be64toh
|
||||
|
||||
#define htole16(x) (uint16_t)(x)
|
||||
#define htole32(x) (uint32_t)(x)
|
||||
#define htole64(x) (uint64_t)(x)
|
||||
|
||||
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "gpio.h"
|
||||
|
@ -46,8 +47,10 @@
|
|||
#define ETP_I2C_MAX_X_AXIS_CMD 0x0106
|
||||
#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107
|
||||
#define ETP_I2C_RESOLUTION_CMD 0x0108
|
||||
#define ETP_I2C_IAP_VERSION_CMD 0x0110
|
||||
#define ETP_I2C_PRESSURE_CMD 0x010A
|
||||
#define ETP_I2C_SET_CMD 0x0300
|
||||
#define ETP_I2C_IAP_TYPE_CMD 0x0304
|
||||
#define ETP_I2C_POWER_CMD 0x0307
|
||||
#define ETP_I2C_FW_CHECKSUM_CMD 0x030F
|
||||
|
||||
|
@ -88,7 +91,6 @@
|
|||
#ifdef CONFIG_USB_UPDATE
|
||||
/* The actual FW_SIZE depends on IC. */
|
||||
#define FW_SIZE CONFIG_TOUCHPAD_VIRTUAL_SIZE
|
||||
#define FW_PAGE_SIZE 64
|
||||
#endif
|
||||
|
||||
struct {
|
||||
|
@ -100,6 +102,10 @@ struct {
|
|||
uint16_t width_y;
|
||||
/* Pressure adjustment */
|
||||
uint8_t pressure_adj;
|
||||
uint16_t ic_type;
|
||||
uint16_t page_count;
|
||||
uint16_t page_size;
|
||||
uint16_t iap_version;
|
||||
} elan_tp_params;
|
||||
|
||||
/*
|
||||
|
@ -270,6 +276,41 @@ static int elan_tp_read_report(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int elan_get_fwinfo(void)
|
||||
{
|
||||
uint16_t ic_type = elan_tp_params.ic_type;
|
||||
uint16_t iap_version = elan_tp_params.iap_version;
|
||||
|
||||
switch (ic_type) {
|
||||
case 0x09:
|
||||
elan_tp_params.page_count = 768;
|
||||
break;
|
||||
case 0x0D:
|
||||
elan_tp_params.page_count = 896;
|
||||
break;
|
||||
case 0x00:
|
||||
case 0x10:
|
||||
case 0x14:
|
||||
elan_tp_params.page_count = 1024;
|
||||
break;
|
||||
default:
|
||||
CPRINTS("unknown ic_type: %d", ic_type);
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (ic_type == 0x14 && iap_version >= 2) {
|
||||
elan_tp_params.page_count /= 8;
|
||||
elan_tp_params.page_size = 512;
|
||||
} else if (ic_type >= 0x0D && iap_version >= 1) {
|
||||
elan_tp_params.page_count /= 2;
|
||||
elan_tp_params.page_size = 128;
|
||||
} else {
|
||||
elan_tp_params.page_size = 64;
|
||||
}
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Initialize the controller ICs after reset */
|
||||
static void elan_tp_init(void)
|
||||
{
|
||||
|
@ -289,6 +330,24 @@ static void elan_tp_init(void)
|
|||
if (rv)
|
||||
goto out;
|
||||
|
||||
/* Read IC type, IAP version */
|
||||
rv = elan_tp_read_cmd(ETP_I2C_OSM_VERSION_CMD, &elan_tp_params.ic_type);
|
||||
CPRINTS("%s: ic_type:%04X.", __func__, elan_tp_params.ic_type);
|
||||
elan_tp_params.ic_type >>= 8;
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
rv = elan_tp_read_cmd(ETP_I2C_IAP_VERSION_CMD,
|
||||
&elan_tp_params.iap_version);
|
||||
CPRINTS("%s: iap_version:%04X.", __func__, elan_tp_params.iap_version);
|
||||
elan_tp_params.iap_version >>= 8;
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
rv = elan_get_fwinfo();
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
/* Read min/max */
|
||||
rv = elan_tp_read_cmd(ETP_I2C_MAX_X_AXIS_CMD, &elan_tp_params.max_x);
|
||||
if (rv)
|
||||
|
@ -401,22 +460,23 @@ static int elan_in_main_mode(void)
|
|||
return val & ETP_I2C_MAIN_MODE_ON;
|
||||
}
|
||||
|
||||
static int elan_get_ic_page_count(void)
|
||||
static int elan_read_write_iap_type(void)
|
||||
{
|
||||
uint16_t ic_type;
|
||||
for (int retry = 0; retry < 3; ++retry) {
|
||||
uint16_t val;
|
||||
|
||||
if (elan_tp_write_cmd(ETP_I2C_IAP_TYPE_CMD,
|
||||
elan_tp_params.page_size / 2))
|
||||
return EC_ERROR_UNKNOWN;
|
||||
|
||||
if (elan_tp_read_cmd(ETP_I2C_IAP_TYPE_CMD, &val))
|
||||
return EC_ERROR_UNKNOWN;
|
||||
|
||||
if (val == elan_tp_params.page_size / 2)
|
||||
return EC_SUCCESS;
|
||||
|
||||
elan_tp_read_cmd(ETP_I2C_OSM_VERSION_CMD, &ic_type);
|
||||
CPRINTS("%s: ic_type:%04X.", __func__, ic_type);
|
||||
switch (ic_type >> 8) {
|
||||
case 0x09:
|
||||
return 768;
|
||||
case 0x0D:
|
||||
return 896;
|
||||
case 0x00:
|
||||
case 0x10:
|
||||
return 1024;
|
||||
}
|
||||
return -1;
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
static int elan_prepare_for_update(void)
|
||||
|
@ -440,6 +500,11 @@ static int elan_prepare_for_update(void)
|
|||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (elan_tp_params.ic_type >= 0x0D && elan_tp_params.iap_version >= 1) {
|
||||
if (elan_read_write_iap_type())
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Send the passphrase again */
|
||||
elan_tp_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD);
|
||||
msleep(30);
|
||||
|
@ -459,26 +524,39 @@ static int elan_prepare_for_update(void)
|
|||
|
||||
static int touchpad_update_page(const uint8_t *data)
|
||||
{
|
||||
uint8_t page_store[FW_PAGE_SIZE + 4];
|
||||
const uint8_t cmd[2] = {ETP_I2C_IAP_REG_L, ETP_I2C_IAP_REG_H};
|
||||
uint16_t checksum = 0;
|
||||
uint16_t rx_buf;
|
||||
int i, rv;
|
||||
|
||||
for (i = 0; i < FW_PAGE_SIZE; i += 2)
|
||||
for (i = 0; i < elan_tp_params.page_size; i += 2)
|
||||
checksum += ((uint16_t)(data[i + 1]) << 8) | (data[i]);
|
||||
checksum = htole16(checksum);
|
||||
|
||||
page_store[0] = ETP_I2C_IAP_REG_L;
|
||||
page_store[1] = ETP_I2C_IAP_REG_H;
|
||||
memcpy(page_store + 2, data, FW_PAGE_SIZE);
|
||||
page_store[FW_PAGE_SIZE + 2 + 0] = checksum & 0xff;
|
||||
page_store[FW_PAGE_SIZE + 2 + 1] = (checksum >> 8) & 0xff;
|
||||
i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1);
|
||||
|
||||
rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT,
|
||||
CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
|
||||
page_store, sizeof(page_store), NULL, 0);
|
||||
rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT,
|
||||
CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
|
||||
cmd, sizeof(cmd), NULL, 0, I2C_XFER_START);
|
||||
if (rv)
|
||||
goto fail;
|
||||
rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT,
|
||||
CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
|
||||
data, elan_tp_params.page_size, NULL, 0, 0);
|
||||
if (rv)
|
||||
goto fail;
|
||||
rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT,
|
||||
CONFIG_TOUCHPAD_I2C_ADDR_FLAGS,
|
||||
(uint8_t *)&checksum, sizeof(checksum), NULL, 0,
|
||||
I2C_XFER_STOP);
|
||||
if (rv)
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0);
|
||||
if (rv)
|
||||
return rv;
|
||||
msleep(20);
|
||||
msleep(elan_tp_params.page_size >= 512 ? 50 : 35);
|
||||
|
||||
rv = elan_tp_read_cmd(ETP_I2C_IAP_CTRL_CMD, &rx_buf);
|
||||
|
||||
|
@ -493,16 +571,17 @@ static int touchpad_update_page(const uint8_t *data)
|
|||
int touchpad_update_write(int offset, int size, const uint8_t *data)
|
||||
{
|
||||
static int iap_addr = -1;
|
||||
int addr, rv, page_count;
|
||||
int addr, rv;
|
||||
|
||||
CPRINTS("%s %08x %d", __func__, offset, size);
|
||||
|
||||
if (offset == 0) {
|
||||
/* Verify the IC type is aligned with defined firmware size */
|
||||
page_count = elan_get_ic_page_count();
|
||||
if (FW_PAGE_SIZE * page_count != FW_SIZE) {
|
||||
if (elan_tp_params.page_size * elan_tp_params.page_count
|
||||
!= FW_SIZE) {
|
||||
CPRINTS("%s: IC(%d*%d) size and FW_SIZE(%d) mismatch",
|
||||
__func__, page_count, FW_PAGE_SIZE, FW_SIZE);
|
||||
__func__, elan_tp_params.page_count,
|
||||
elan_tp_params.page_size, FW_SIZE);
|
||||
return EC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -521,18 +600,18 @@ int touchpad_update_write(int offset, int size, const uint8_t *data)
|
|||
CPRINTS("%s: payload starts from 0x%x.", __func__, iap_addr);
|
||||
}
|
||||
|
||||
/* Data that comes in must align with FW_PAGE_SIZE */
|
||||
if (offset % FW_PAGE_SIZE)
|
||||
/* Data that comes in must align with page_size */
|
||||
if (offset % elan_tp_params.page_size)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
for (addr = (offset / FW_PAGE_SIZE) * FW_PAGE_SIZE;
|
||||
addr < (offset + size); addr += FW_PAGE_SIZE) {
|
||||
for (addr = offset; addr < (offset + size);
|
||||
addr += elan_tp_params.page_size) {
|
||||
if (iap_addr > addr) /* Skip chunk */
|
||||
continue;
|
||||
rv = touchpad_update_page(data + addr - offset);
|
||||
if (rv)
|
||||
return rv;
|
||||
CPRINTF("/p%d", addr / FW_PAGE_SIZE);
|
||||
CPRINTF("/p%d", addr / elan_tp_params.page_size);
|
||||
watchdog_reload();
|
||||
}
|
||||
CPRINTF("\n");
|
||||
|
|
Loading…
Reference in New Issue