diff options
Diffstat (limited to 'driver')
-rw-r--r-- | driver/build.mk | 1 | ||||
-rw-r--r-- | driver/touchpad_st.c | 474 | ||||
-rw-r--r-- | driver/touchpad_st.h | 245 |
3 files changed, 720 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk index cc0a119640..541b8df235 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -90,6 +90,7 @@ driver-$(CONFIG_TEMP_SENSOR_F75303)+=temp_sensor/f75303.o # Touchpads driver-$(CONFIG_TOUCHPAD_ELAN)+=touchpad_elan.o +driver-$(CONFIG_TOUCHPAD_ST)+=touchpad_st.o # Thermistors driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o diff --git a/driver/touchpad_st.c b/driver/touchpad_st.c new file mode 100644 index 0000000000..0806f93a6a --- /dev/null +++ b/driver/touchpad_st.c @@ -0,0 +1,474 @@ +/* Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "atomic.h" +#include "board.h" +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "hwtimer.h" +#include "hooks.h" +#include "i2c.h" +#include "registers.h" +#include "spi.h" +#include "task.h" +#include "timer.h" +#include "touchpad.h" +#include "touchpad_st.h" +#include "update_fw.h" +#include "usb_hid_touchpad.h" +#include "util.h" + +/* Console output macros */ +#define CC_TOUCHPAD CC_USB +#define CPUTS(outstr) cputs(CC_TOUCHPAD, outstr) +#define CPRINTF(format, args...) cprintf(CC_TOUCHPAD, format, ## args) +#define CPRINTS(format, args...) cprints(CC_TOUCHPAD, format, ## args) + +#define SPI (&(spi_devices[SPI_ST_TP_DEVICE_ID])) + +BUILD_ASSERT(sizeof(struct st_tp_event_t) == 8); + +static struct st_tp_system_info_t system_info; + +static int st_tp_read_all_events(void); +static int st_tp_send_ack(void); +static int st_tp_start_scan(void); +static int st_tp_read_host_buffer_header(void); + +/* + * Current system state, meaning of each bit is defined below. + */ +static int system_state; + +#define SYSTEM_STATE_DEBUG_MODE (1 << 0) +#define SYSTEM_STATE_ENABLE_HEAT_MAP (1 << 1) +#define SYSTEM_STATE_ENABLE_DOME_SWITCH (1 << 2) +#define SYSTEM_STATE_ACTIVE_MODE (1 << 3) +#define SYSTEM_STATE_DOME_SWITCH_LEVEL (1 << 4) + +/* + * Timestamp of last interrupt (32 bits are enough as we divide the value by 100 + * and then put it in a 16-bit field). + */ +static uint32_t irq_ts; + +static struct { +#if ST_TP_DUMMY_BYTE == 1 + uint8_t dummy; +#endif + union { + uint8_t bytes[512]; + struct st_tp_host_buffer_header_t buffer_header; + struct st_tp_host_buffer_heat_map_t heat_map; + struct st_tp_host_data_header_t data_header; + struct st_tp_event_t events[32]; + } /* anonymous */; +} __packed rx_buf; + +static void set_bits(int *lvalue, int rvalue, int mask) +{ + *lvalue &= ~mask; + *lvalue |= rvalue & mask; +} + +/* + * Parse a finger report from ST event and save it to (report)->finger. + * + * @param report: pointer to a USB HID touchpad report. + * @param event: a pointer event from ST. + * @param i: array index for next finger. + * + * @return array index of next finger (i.e. (i + 1) if a finger is added). + */ +static int st_tp_parse_finger(struct usb_hid_touchpad_report *report, + struct st_tp_event_t *event, + int i) +{ + /* We cannot report more fingers */ + if (i >= ARRAY_SIZE(report->finger)) + return i; + + /* This is not a finger */ + if (event->finger.touch_type == ST_TP_TOUCH_TYPE_INVALID) + return i; + + switch (event->evt_id) { + case ST_TP_EVENT_ID_ENTER_POINTER: + case ST_TP_EVENT_ID_MOTION_POINTER: + report->finger[i].tip = 1; + report->finger[i].inrange = 1; + report->finger[i].id = event->finger.touch_id; + report->finger[i].pressure = event->finger.z; + report->finger[i].width = (event->finger.minor | + (event->minor_high << 4)); + report->finger[i].height = (event->finger.major | + (event->major_high << 4)); + report->finger[i].x = (CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_X - + event->finger.x); + report->finger[i].y = (CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_Y - + event->finger.y); + break; + case ST_TP_EVENT_ID_LEAVE_POINTER: + report->finger[i].id = event->finger.touch_id; + break; + } + return i + 1; +} + +static int st_tp_write_hid_report(void) +{ + int ret, i, num_finger; + struct usb_hid_touchpad_report report; + struct st_tp_event_t *event; + + ret = st_tp_read_host_buffer_header(); + if (ret) + return ret; + + if (rx_buf.buffer_header.flags & ST_TP_BUFFER_HEADER_DOMESWITCH_CHG) { + /* + * dome_switch_level from device is inverted. + * That is, 0 => pressed, 1 => released. + */ + set_bits(&system_state, + (rx_buf.buffer_header.dome_switch_level ? + 0 : SYSTEM_STATE_DOME_SWITCH_LEVEL), + SYSTEM_STATE_DOME_SWITCH_LEVEL); + } + + ret = st_tp_read_all_events(); + if (ret) + return ret; + + memset(&report, 0, sizeof(report)); + report.id = 0x1; + num_finger = 0; + + for (i = 0; i < ARRAY_SIZE(rx_buf.events); i++) { + event = &rx_buf.events[i]; + + /* + * this is not a valid event, and assume all following + * events are invalid too + */ + if (event->magic != 0x3) + break; + + switch (event->evt_id) { + case ST_TP_EVENT_ID_ENTER_POINTER: + case ST_TP_EVENT_ID_MOTION_POINTER: + case ST_TP_EVENT_ID_LEAVE_POINTER: + num_finger = st_tp_parse_finger(&report, + event, + num_finger); + break; + default: + break; + } + } + + report.button = !!(system_state & SYSTEM_STATE_DOME_SWITCH_LEVEL); + report.count = num_finger; + report.timestamp = irq_ts / USB_HID_TOUCHPAD_TIMESTAMP_UNIT; + + set_touchpad_report(&report); + return ret; +} + +static int st_tp_read_report(void) +{ + if (system_state & SYSTEM_STATE_ENABLE_HEAT_MAP) { + /* TODO(stimim): implement this */ + } else { + st_tp_write_hid_report(); + } + return st_tp_send_ack(); +} + +static int st_tp_read_host_buffer_header(void) +{ + const uint8_t tx_buf[] = { ST_TP_CMD_READ_SPI_HOST_BUFFER, 0x00, 0x00 }; + int rx_len = ST_TP_DUMMY_BYTE + sizeof(rx_buf.buffer_header); + + return spi_transaction(SPI, tx_buf, sizeof(tx_buf), + (uint8_t *)&rx_buf, rx_len); +} + +static int st_tp_send_ack(void) +{ + uint8_t tx_buf[] = { ST_TP_CMD_SPI_HOST_BUFFER_ACK }; + + return spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); +} + +static int st_tp_update_system_state(int new_state, int mask) +{ + int ret = EC_SUCCESS; + + /* copy reserved bits */ + set_bits(&new_state, system_state, ~mask); + + mask = SYSTEM_STATE_DEBUG_MODE; + if ((new_state & mask) != (system_state & mask)) + set_bits(&system_state, new_state, mask); + + mask = SYSTEM_STATE_ENABLE_HEAT_MAP | SYSTEM_STATE_ENABLE_DOME_SWITCH; + if ((new_state & mask) != (system_state & mask)) { + uint8_t tx_buf[] = { + ST_TP_CMD_WRITE_FEATURE_SELECT, + 0x05, + 0 + }; + if (new_state & SYSTEM_STATE_ENABLE_HEAT_MAP) + tx_buf[2] |= 1 << 0; + if (new_state & SYSTEM_STATE_ENABLE_DOME_SWITCH) + tx_buf[2] |= 1 << 1; + ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); + if (ret) + return ret; + set_bits(&system_state, new_state, mask); + } + + mask = SYSTEM_STATE_ACTIVE_MODE; + if ((new_state & mask) != (system_state & mask)) { + uint8_t tx_buf[] = { + ST_TP_CMD_WRITE_SCAN_MODE_SELECT, + ST_TP_SCAN_MODE_ACTIVE, + !!(new_state & SYSTEM_STATE_ACTIVE_MODE), + }; + CPRINTS("Enable Multi-Touch: %d", tx_buf[2]); + ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); + if (ret) + return ret; + set_bits(&system_state, new_state, mask); + } + return ret; +} + +static void st_tp_enable_interrupt(int enable) +{ + uint8_t tx_buf[] = { + ST_TP_CMD_WRITE_SYSTEM_COMMAND, 0x01, enable ? 1 : 0}; + if (enable) + gpio_enable_interrupt(GPIO_TOUCHPAD_INT); + spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); + if (!enable) + gpio_disable_interrupt(GPIO_TOUCHPAD_INT); +} + +static int st_tp_start_scan(void) +{ + int new_state = (SYSTEM_STATE_ACTIVE_MODE | + SYSTEM_STATE_ENABLE_DOME_SWITCH); + int mask = new_state; + int ret; + + ret = st_tp_update_system_state(new_state, mask); + if (ret) + return ret; + st_tp_send_ack(); + st_tp_enable_interrupt(1); + return ret; +} + +static int st_tp_read_host_data_memory(uint16_t addr, void *rx_buf, int len) { + uint8_t tx_buf[] = { + ST_TP_CMD_READ_HOST_DATA_MEMORY, addr >> 8, addr & 0xFF + }; + + return spi_transaction(SPI, tx_buf, sizeof(tx_buf), rx_buf, len); +} + +static int st_tp_load_host_data(uint8_t mem_id) +{ + uint8_t tx_buf[] = { + ST_TP_CMD_WRITE_SYSTEM_COMMAND, 0x06, mem_id + }; + int retry, ret; + uint16_t count; + struct st_tp_host_data_header_t *header = &rx_buf.data_header; + int rx_len = sizeof(*header) + ST_TP_DUMMY_BYTE; + + st_tp_read_host_data_memory(0x0000, &rx_buf, rx_len); + if (header->host_data_mem_id == mem_id) + return EC_SUCCESS; /* already loaded no need to reload */ + + count = header->count; + + ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); + if (ret) + return ret; + + ret = EC_ERROR_TIMEOUT; + retry = 5; + while (retry--) { + st_tp_read_host_data_memory(0x0000, &rx_buf, rx_len); + if (header->magic == ST_TP_HEADER_MAGIC && + header->host_data_mem_id == mem_id && + header->count != count) { + ret = EC_SUCCESS; + break; + } + usleep(10 * MSEC); + } + return ret; +} + +/* + * Read System Info from Host Data Memory. + * + * @param reload: true to force reloading system info into host data memory + * before reading. + */ +static int st_tp_read_system_info(int reload) +{ + int ret = EC_SUCCESS; + int rx_len = ST_TP_DUMMY_BYTE + ST_TP_SYSTEM_INFO_LEN; + uint8_t *ptr = rx_buf.bytes; + + if (reload) + ret = st_tp_load_host_data(ST_TP_MEM_ID_SYSTEM_INFO); + if (ret) + return ret; + ret = st_tp_read_host_data_memory(0x0000, &rx_buf, rx_len); + if (ret) + return ret; + + /* Parse the content */ + memcpy(&system_info, ptr, ST_TP_SYSTEM_INFO_PART_1_SIZE); + + /* Check header */ + if (system_info.header.magic != ST_TP_HEADER_MAGIC || + system_info.header.host_data_mem_id != ST_TP_MEM_ID_SYSTEM_INFO) + return EC_ERROR_UNKNOWN; + + ptr += ST_TP_SYSTEM_INFO_PART_1_SIZE; + ptr += ST_TP_SYSTEM_INFO_PART_1_RESERVED; + memcpy(&system_info.scr_res_x, ptr, ST_TP_SYSTEM_INFO_PART_2_SIZE); + +#define ST_TP_SHOW(attr) CPRINTS(#attr ": %04x", system_info.attr) + ST_TP_SHOW(chip0_id[0]); + ST_TP_SHOW(chip0_id[1]); + ST_TP_SHOW(chip0_ver); + ST_TP_SHOW(scr_tx_len); + ST_TP_SHOW(scr_rx_len); + ST_TP_SHOW(release_info); +#undef ST_TP_SHOW + return ret; +} + +static int st_tp_read_all_events(void) +{ + uint8_t cmd = ST_TP_CMD_READ_ALL_EVENTS; + int rx_len = sizeof(rx_buf.events) + ST_TP_DUMMY_BYTE; + + return spi_transaction(SPI, &cmd, 1, (uint8_t *)&rx_buf, rx_len); +} + +static int st_tp_reset(void) +{ + board_touchpad_reset(); + return st_tp_read_all_events(); +} + +/* Initialize the controller ICs after reset */ +static void st_tp_init(void) +{ + st_tp_reset(); + /* + * On boot, ST firmware will load system info to host data memory, + * So we don't need to reload it. + */ + st_tp_read_system_info(0); + + system_state = 0; + + st_tp_start_scan(); +} + +#ifdef CONFIG_USB_UPDATE +int touchpad_get_info(struct touchpad_info *tp) +{ + if (st_tp_read_system_info(1)) { + tp->status = EC_RES_SUCCESS; + tp->vendor = ST_VENDOR_ID; + /* + * failed to get system info, FW corrupted, return some default + * values. + */ + tp->st.id = 0x3936; + tp->st.fw_version = 0; + tp->st.fw_checksum = 0; + return sizeof(*tp); + } + + tp->status = EC_RES_SUCCESS; + tp->vendor = ST_VENDOR_ID; + tp->st.id = (system_info.chip0_id[0] << 8) | system_info.chip0_id[1]; + tp->st.fw_version = system_info.release_info; + tp->st.fw_checksum = system_info.fw_crc; + + return sizeof(*tp); +} + +/* + * @param offset: should be address between 0 to 1M, aligned with + * ST_TP_DMA_CHUNK_SIZE. + * @param size: length of `data` array. + * @param data: content of new touchpad firmware. + */ +int touchpad_update_write(int offset, int size, const uint8_t *data) +{ + CPRINTS("%s %08x %d", __func__, offset, size); + + return EC_RES_INVALID_COMMAND; +} + +int touchpad_debug(const uint8_t *param, unsigned int param_size, + uint8_t **data, unsigned int *data_size) +{ + return EC_RES_INVALID_COMMAND; +} +#endif + +void touchpad_interrupt(enum gpio_signal signal) +{ + irq_ts = __hw_clock_source_read(); + + task_wake(TASK_ID_TOUCHPAD); +} + +void touchpad_task(void *u) +{ + st_tp_init(); + + while (1) { + task_wait_event(-1); + + while (!gpio_get_level(GPIO_TOUCHPAD_INT)) + st_tp_read_report(); + } +} + +/* Debugging commands */ +static int command_touchpad_st(int argc, char **argv) +{ + if (argc != 2) + return EC_ERROR_PARAM_COUNT; + if (strcasecmp(argv[1], "enable") == 0) { + return EC_ERROR_NOT_HANDLED; + } else if (strcasecmp(argv[1], "disable") == 0) { + return EC_ERROR_NOT_HANDLED; + } else if (strcasecmp(argv[1], "version") == 0) { + st_tp_read_system_info(1); + return 0; + } else { + return EC_ERROR_PARAM1; + } +} +DECLARE_CONSOLE_COMMAND(touchpad_st, command_touchpad_st, + "<enable|disable|version>", + "Read write spi. id is spi_devices array index"); diff --git a/driver/touchpad_st.h b/driver/touchpad_st.h new file mode 100644 index 0000000000..23bb404d36 --- /dev/null +++ b/driver/touchpad_st.h @@ -0,0 +1,245 @@ +/* Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __CROS_EC_TOUCHPAD_ST_H +#define __CROS_EC_TOUCHPAD_ST_H + +#include <stdint.h> + +#include "common.h" + +#define ST_VENDOR_ID 0x0483 + +#define ST_TP_DUMMY_BYTE 1 + +#define ST_TP_CMD_READ_ALL_EVENTS 0x87 +#define ST_TP_CMD_WRITE_SCAN_MODE_SELECT 0xA0 +#define ST_TP_CMD_WRITE_FEATURE_SELECT 0xA2 +#define ST_TP_CMD_WRITE_SYSTEM_COMMAND 0xA4 +#define ST_TP_CMD_WRITE_HOST_DATA_MEMORY 0xA6 +#define ST_TP_CMD_READ_HOST_DATA_MEMORY 0xA7 +#define ST_TP_CMD_WRITE_FW_CONFIG 0xA8 +#define ST_TP_CMD_READ_FW_CONFIG 0xA9 +#define ST_TP_CMD_SPI_HOST_BUFFER_ACK 0xC0 +#define ST_TP_CMD_READ_SPI_HOST_BUFFER 0xC1 + +#define ST_TP_CMD_WRITE_HW_REG 0xFA +#define ST_TP_CMD_READ_HW_REG 0xFB + +/* Max number of bytes that the DMA can burn on the flash in one shot in FTI */ +#define ST_TP_FLASH_BUFFER_SIZE (64 * 1024) +/* Max number of bytes that can be written in I2C to the DMA */ +#define ST_TP_DMA_CHUNK_SIZE 32 + +#define ST_HOST_BUFFER_DATA_VALID (1 << 0) +#define ST_HOST_BUFFER_MT_READY (1 << 3) +#define ST_HOST_BUFFER_SF_READY (1 << 4) +#define ST_HOST_BUFFER_SS_READY (1 << 5) + +#define ST_TP_SCAN_MODE_ACTIVE 0x00 +#define ST_TP_SCAN_MODE_LOW_POWER 0x01 +#define ST_TP_SCAN_MODE_TUNING_WIZARD 0x02 +#define ST_TP_SCAN_MODE_LOCKED 0x03 + +#define ST_TOUCH_ROWS (18) /* force len */ +#define ST_TOUCH_COLS (25) /* sense len */ + +#define ST_TOUCH_HEADER_SIZE 32 + +#define BYTES_PER_PIXEL 2 +/* Number of bits per pixel, this value is decided by experiments. */ +#define BITS_PER_PIXEL (11) + +#define ST_TOUCH_FRAME_SIZE (ST_TOUCH_ROWS * ST_TOUCH_COLS * \ + BYTES_PER_PIXEL) +#define ST_TOUCH_FORCE_SIZE (ST_TOUCH_ROWS * BYTES_PER_PIXEL) +#define ST_TOUCH_SENSE_SIZE (ST_TOUCH_COLS * BYTES_PER_PIXEL) + +#define ST_TP_MEM_ID_SYSTEM_INFO 0x01 + +#define ST_TP_FLASH_OFFSET_CODE (0x0000 << 2) +#define ST_TP_FLASH_OFFSET_CONFIG (0x7C00 << 2) +#define ST_TP_FLASH_OFFSET_CX (0x7000 << 2) + + +struct st_tp_host_data_header_t { +#define ST_TP_HEADER_MAGIC 0xA5 + uint8_t magic; /* this should always be ST_TP_HEADER_MAGIC */ + uint8_t host_data_mem_id; + uint16_t count; +} __packed; + +/* Compute offset of end of a member in given type */ +#define endof(type, member) (offsetof(type, member) + \ + sizeof(((type *)NULL)->member)) + +struct st_tp_system_info_t { + /* Part 1, basic info */ + struct st_tp_host_data_header_t header; + uint16_t api_ver_rev; + uint8_t api_ver_minor; + uint8_t api_ver_major; + uint16_t chip0_ver; + uint8_t chip0_id[2]; /* should be 0x3936 */ + uint16_t chip1_ver; + uint16_t chip1_id; + uint16_t fw_ver; + uint16_t svn_rev; + uint16_t cfg_ver; + uint16_t cfg_project_id; + uint16_t cx_ver; + uint16_t cx_project_id; + uint8_t cfg_afe_ver; + uint8_t cx_afe_ver; + uint8_t panel_cfg_afe_ver; + uint8_t protocol; + uint8_t die_id[16]; + uint64_t release_info; /* unsigned little endian 64 bit integer */ + uint32_t fw_crc; + uint32_t cfg_crc; +#define ST_TP_SYSTEM_INFO_PART_1_SIZE endof(struct st_tp_system_info_t, cfg_crc) +#define ST_TP_SYSTEM_INFO_PART_1_RESERVED 16 + + uint16_t scr_res_x; + uint16_t scr_res_y; + uint8_t scr_tx_len; + uint8_t scr_rx_len; + uint8_t key_len; + uint8_t frc_len; +#define ST_TP_SYSTEM_INFO_PART_2_SIZE (endof(struct st_tp_system_info_t, \ + frc_len) - \ + offsetof(struct st_tp_system_info_t, \ + scr_res_x)) +#define ST_TP_SYSTEM_INFO_PART_2_RESERVED 40 + +#if 0 /* the following parts are defined in spec, but not currently used. */ + + uint16_t dbg_frame_addr; +#define ST_TP_SYSTEM_INFO_PART_3_SIZE (endof(struct st_tp_system_info_t, \ + dbg_frame_addr) - \ + offsetof(struct st_tp_system_info_t, \ + dbg_frame_addr)) +#define ST_TP_SYSTEM_INFO_PART_3_RESERVED 6 + + uint16_t ms_scr_raw_addr; + uint16_t ms_scr_filter_addr; + uint16_t ms_scr_str_addr; + uint16_t ms_scr_bl_addr; + uint16_t ss_tch_tx_raw_addr; + uint16_t ss_tch_tx_filter_addr; + uint16_t ss_tch_tx_str_addr; + uint16_t ss_tch_tx_bl_addr; + uint16_t ss_tch_rx_raw_addr; + uint16_t ss_tch_rx_filter_addr; + uint16_t ss_tch_rx_str_addr; + uint16_t ss_tch_rx_bl_addr; + uint16_t key_raw_addr; + uint16_t key_filter_addr; + uint16_t key_str_addr; + uint16_t key_bl_addr; + uint16_t frc_raw_addr; + uint16_t frc_filter_addr; + uint16_t frc_str_addr; + uint16_t frc_bl_addr; + uint16_t ss_hvr_tx_raw_addr; + uint16_t ss_hvr_tx_filter_addr; + uint16_t ss_hvr_tx_str_addr; + uint16_t ss_hvr_tx_bl_addr; + uint16_t ss_hvr_rx_raw_addr; + uint16_t ss_hvr_rx_filter_addr; + uint16_t ss_hvr_rx_str_addr; + uint16_t ss_hvr_rx_bl_addr; + uint16_t ss_prx_tx_raw_addr; + uint16_t ss_prx_tx_filter_addr; + uint16_t ss_prx_tx_str_addr; + uint16_t ss_prx_tx_bl_addr; + uint16_t ss_prx_rx_raw_addr; + uint16_t ss_prx_rx_filter_addr; + uint16_t ss_prx_rx_str_addr; + uint16_t ss_prx_rx_bl_addr; +#define ST_TP_SYSTEM_INFO_PART_4_SIZE (endof(struct st_tp_system_info_t, \ + ss_prx_rx_bl_addr) - \ + offsetof(struct st_tp_system_info_t, \ + ms_scr_raw_addr)) +#endif /* if 0 */ +} __packed; + +#define ST_TP_SYSTEM_INFO_LEN (sizeof(struct st_tp_system_info_t) + \ + ST_TP_SYSTEM_INFO_PART_1_RESERVED) + +struct st_tp_host_buffer_header_t { +#define ST_TP_BUFFER_HEADER_DATA_VALID (1 << 0) +#define ST_TP_BUFFER_HEADER_EVT_FIFO_NOT_EMPTY (1 << 1) +#define ST_TP_BUFFER_HEADER_SYS_FAULT (1 << 2) +#define ST_TP_BUFFER_HEADER_HEAT_MAP_MT_RDY (1 << 3) +#define ST_TP_BUFFER_HEADER_HEAT_MAP_SF_RDY (1 << 4) +#define ST_TP_BUFFER_HEADER_HEAT_MAP_SS_RDY (1 << 5) +#define ST_TP_BUFFER_HEADER_DOMESWITCH_CHG (1 << 6) + uint8_t flags; + uint8_t reserved[3]; + uint8_t heatmap_miss_count; + uint8_t event_count; + uint8_t event_miss_count; + uint8_t dome_switch_down_count:3; + uint8_t dome_switch_up_count:3; + uint8_t dome_switch_level:1; + uint8_t dome_switch_overflow:1; +} __packed; + +struct st_tp_host_buffer_heat_map_t { + uint8_t frame[ST_TOUCH_FRAME_SIZE]; +#if 0 /* we are not using these now */ + uint8_t force[ST_TOUCH_FORCE_SIZE]; + uint8_t sense[ST_TOUCH_SENSE_SIZE]; +#endif +} __packed; + +struct st_tp_event_t { + unsigned magic:2; /* should always be 0x3 */ + unsigned major_high:2; +#define ST_TP_EVENT_ID_ENTER_POINTER 0x1 +#define ST_TP_EVENT_ID_MOTION_POINTER 0x2 +#define ST_TP_EVENT_ID_LEAVE_POINTER 0x3 +#define ST_TP_EVENT_ID_STATUS_REPORT 0x4 +#define ST_TP_EVENT_ID_USER_REPORT 0x5 +#define ST_TP_EVENT_ID_DEBUG_REPORT 0xe +#define ST_TP_EVENT_ID_ERROR_REPORT 0xf + unsigned evt_id:4; + + union { + struct { +#define ST_TP_TOUCH_TYPE_INVALID 0x0 +#define ST_TP_TOUCH_TYPE_FINGER 0x1 +#define ST_TP_TOUCH_TYPE_GLOVE 0x2 +#define ST_TP_TOUCH_TYPE_STYLUS 0x3 +#define ST_TP_TOUCH_TYPE_PALM 0x4 + unsigned touch_type:4; + unsigned touch_id:4; + unsigned y:12; + unsigned x:12; + uint8_t z; + uint8_t minor:4; // need to be concat with minor_high + uint8_t major:4; // need to be concat with major_high + } __packed finger; + + struct { + uint8_t report_type; + uint32_t info; + uint8_t reserved; + } __packed report; + } __packed ; /* anonymous */ + + unsigned minor_high:2; + unsigned reserved:1; + unsigned evt_left:5; +} __packed; + +enum ST_TP_MODE { + X_Y_MODE = 0, + HEAT_MAP_MODE, +}; + +#endif /* __CROS_EC_TOUCHPAD_ST_H */ + |