diff options
author | Nicolas Boichat <drinkcat@google.com> | 2016-11-02 11:15:12 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-11-08 23:24:52 -0800 |
commit | de0f53afef1822cd32c917d91452ff6eec5fd17f (patch) | |
tree | 0a420a8771ba276b3a0a5e67b705bdd86d7fb222 | |
parent | 840ba2b6e48f6378e4d70ad29dfa26190019536d (diff) | |
download | chrome-ec-de0f53afef1822cd32c917d91452ff6eec5fd17f.tar.gz |
driver/touchpad_elan: Basic elan touchpad driver
BRANCH=none
BUG=chrome-os-partner:59083
TEST=make BOARD=hammer -j && bash flash_hammer
Change-Id: I0ff4f48ff1399e054f745ac13ffacf81dffedeab
Reviewed-on: https://chromium-review.googlesource.com/407740
Commit-Ready: Nicolas Boichat <drinkcat@chromium.org>
Tested-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | driver/build.mk | 3 | ||||
-rw-r--r-- | driver/touchpad_elan.c | 245 | ||||
-rw-r--r-- | driver/touchpad_elan.h | 13 | ||||
-rw-r--r-- | include/config.h | 10 | ||||
-rw-r--r-- | include/console_channel.inc | 3 |
5 files changed, 274 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk index 281afc92d0..0a6d109adc 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -74,6 +74,9 @@ driver-$(CONFIG_TEMP_SENSOR_G782)+=temp_sensor/g78x.o driver-$(CONFIG_TEMP_SENSOR_TMP006)+=temp_sensor/tmp006.o driver-$(CONFIG_TEMP_SENSOR_TMP432)+=temp_sensor/tmp432.o +# Touchpads +driver-$(CONFIG_TOUCHPAD_ELAN)+=touchpad_elan.o + # Thermistors driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o diff --git a/driver/touchpad_elan.c b/driver/touchpad_elan.c new file mode 100644 index 0000000000..e6b52fed1e --- /dev/null +++ b/driver/touchpad_elan.c @@ -0,0 +1,245 @@ +/* Copyright 2016 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 "common.h" +#include "console.h" +#include "touchpad_elan.h" +#include "gpio.h" +#include "i2c.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Console output macros */ +#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) + +/******************************************************************************/ +/* How to talk to the controller */ +/******************************************************************************/ + +#define ETP_I2C_RESET 0x0100 +#define ETP_I2C_WAKE_UP 0x0800 +#define ETP_I2C_SLEEP 0x0801 +#define ETP_I2C_STAND_CMD 0x0005 +#define ETP_I2C_XY_TRACENUM_CMD 0x0105 +#define ETP_I2C_MAX_X_AXIS_CMD 0x0106 +#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 +#define ETP_I2C_PRESSURE_CMD 0x010A +#define ETP_I2C_SET_CMD 0x0300 + +#define ETP_ENABLE_ABS 0x0001 + +#define ETP_I2C_REPORT_LEN 34 + +#define ETP_MAX_FINGERS 5 +#define ETP_FINGER_DATA_LEN 5 + +#define ETP_PRESSURE_OFFSET 25 +#define ETP_FWIDTH_REDUCE 90 + +#define ETP_REPORT_ID 0x5D +#define ETP_REPORT_ID_OFFSET 2 +#define ETP_TOUCH_INFO_OFFSET 3 +#define ETP_FINGER_DATA_OFFSET 4 +#define ETP_HOVER_INFO_OFFSET 30 +#define ETP_MAX_REPORT_LEN 34 + +struct { + /* Max X/Y position */ + uint16_t max_x; + uint16_t max_y; + /* Scaling factor for finger width/height */ + uint16_t width_x; + uint16_t width_y; + /* Pressure adjustment */ + uint8_t pressure_adj; +} elan_tp_params; + +static int elan_tp_read_cmd(uint16_t reg, uint16_t *val) +{ + uint8_t buf[2]; + int rv; + + buf[0] = reg; + buf[1] = reg >> 8; + + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1); + rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, CONFIG_TOUCHPAD_I2C_ADDR, + buf, sizeof(buf), (uint8_t *)val, sizeof(*val), + I2C_XFER_SINGLE); + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0); + + return rv; +} + +static int elan_tp_write_cmd(uint16_t reg, uint16_t val) +{ + uint8_t buf[4]; + int rv; + + buf[0] = reg; + buf[1] = reg >> 8; + buf[2] = val; + buf[3] = val >> 8; + + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1); + rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, CONFIG_TOUCHPAD_I2C_ADDR, + buf, sizeof(buf), NULL, 0, I2C_XFER_SINGLE); + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0); + + return rv; +} + +static int elan_tp_read_report(void) +{ + int rv; + uint8_t tp_buf[ETP_I2C_REPORT_LEN]; + int i; + uint8_t touch_info; + uint8_t hover_info; + uint8_t *finger = tp_buf+ETP_FINGER_DATA_OFFSET; + + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1); + rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, CONFIG_TOUCHPAD_I2C_ADDR, + NULL, 0, tp_buf, ETP_I2C_REPORT_LEN, I2C_XFER_SINGLE); + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0); + + if (rv) { + CPRINTS("read report error"); + return rv; + } + + CPRINTF("[%T "); +#if 0 + for (i = 0; i < ETP_I2C_REPORT_LEN; i++) + CPRINTF("%02x", tp_buf[i]); + CPRINTF(" || "); +#endif + + if (tp_buf[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID) { + CPRINTS("Invalid report id (%x)", tp_buf[ETP_REPORT_ID_OFFSET]); + return -1; + } + + touch_info = tp_buf[ETP_TOUCH_INFO_OFFSET]; + hover_info = tp_buf[ETP_HOVER_INFO_OFFSET]; + + if (touch_info & 0x01) + CPRINTF("click|"); + if (hover_info & 0x40) + CPRINTF("hover|"); + + for (i = 0; i < ETP_MAX_FINGERS; i++) { + int valid = touch_info & (1 << (3+i)); + + if (valid) { + int x = ((finger[0] & 0xf0) << 4) | finger[1]; + int y = ((finger[0] & 0x0f) << 8) | finger[2]; + int width = (finger[3] & 0xf0) >> 4; + int height = finger[3] & 0x0f; + int pressure = finger[4]; + + y = elan_tp_params.max_y - y; + width = width * elan_tp_params.width_x; + height = height * elan_tp_params.width_y; + pressure = pressure + elan_tp_params.pressure_adj; + + if (1) + CPRINTF("i=%d %d/%d %d/%d %d|", i, x, y, + width, height, pressure); + finger += ETP_FINGER_DATA_LEN; + } + } + CPRINTF("]\n"); + + return 0; +} + +/* Initialize the controller ICs after reset */ +static int elan_tp_init(void) +{ + int rv; + uint8_t val[2]; + + CPRINTS("%s", __func__); + + elan_tp_write_cmd(ETP_I2C_STAND_CMD, ETP_I2C_RESET); + msleep(100); + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1); + rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, CONFIG_TOUCHPAD_I2C_ADDR, + NULL, 0, val, sizeof(val), I2C_XFER_SINGLE); + i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0); + + CPRINTS("reset rv %d buf=%04x", rv, *((uint16_t *)val)); + 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) + goto out; + rv = elan_tp_read_cmd(ETP_I2C_MAX_Y_AXIS_CMD, &elan_tp_params.max_y); + if (rv) + goto out; + + /* Read min/max */ + rv = elan_tp_read_cmd(ETP_I2C_XY_TRACENUM_CMD, (uint16_t *)val); + if (rv) + goto out; + if (val[0] == 0 || val[1] == 0) { + CPRINTS("Invalid XY_TRACENUM"); + goto out; + } + + /* ETP_FWIDTH_REDUCE reduces the apparent width to avoid treating large + * finger as palm. Multiply value by 2 as HID multitouch divides it. + */ + elan_tp_params.width_x = + 2 * ((elan_tp_params.max_x / val[0]) - ETP_FWIDTH_REDUCE); + elan_tp_params.width_y = + 2 * ((elan_tp_params.max_y / val[1]) - ETP_FWIDTH_REDUCE); + + rv = elan_tp_read_cmd(ETP_I2C_PRESSURE_CMD, (uint16_t *)val); + if (rv) + goto out; + elan_tp_params.pressure_adj = (val[0] & 0x10) ? 0 : ETP_PRESSURE_OFFSET; + + CPRINTS("max=%d/%d width=%d/%d adj=%d", + elan_tp_params.max_x, elan_tp_params.max_y, + elan_tp_params.width_x, elan_tp_params.width_y, + elan_tp_params.pressure_adj); + + /* Switch to absolute mode */ + rv = elan_tp_write_cmd(ETP_I2C_SET_CMD, ETP_ENABLE_ABS); + if (rv) + goto out; + + /* Sleep control off */ + rv = elan_tp_write_cmd(ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP); + +out: + CPRINTS("%s:%d", __func__, rv); + return rv; +} + +void elan_tp_interrupt(enum gpio_signal signal) +{ + task_wake(TASK_ID_TOUCHPAD); +} + +void elan_tp_task(void) +{ + elan_tp_init(); + + gpio_enable_interrupt(GPIO_TOUCHPAD_INT); + + while (1) { + task_wait_event(-1); + + elan_tp_read_report(); + } +} diff --git a/driver/touchpad_elan.h b/driver/touchpad_elan.h new file mode 100644 index 0000000000..4fb6d6e278 --- /dev/null +++ b/driver/touchpad_elan.h @@ -0,0 +1,13 @@ +/* Copyright 2016 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. + */ + +/* Elan touchpad driver for Chrome EC */ + +#ifndef __CROS_EC_TOUCHPAD_ELAN_H +#define __CROS_EC_TOUCHPAD_ELAN_H + +void elan_tp_interrupt(enum gpio_signal signal); + +#endif diff --git a/include/config.h b/include/config.h index 5cc38a6c14..3f8637e3f8 100644 --- a/include/config.h +++ b/include/config.h @@ -1904,6 +1904,16 @@ #undef CONFIG_DPTF /*****************************************************************************/ +/* Touchpad config */ + +/* Enable Elan driver */ +#undef CONFIG_TOUCHPAD_ELAN + +/* Set I2C port and address (8-bit) */ +#undef CONFIG_TOUCHPAD_I2C_PORT +#undef CONFIG_TOUCHPAD_I2C_ADDR + +/*****************************************************************************/ /* TPM-like configuration */ /* Speak the TPM SPI Hardware Protocol on the SPI slave interface */ diff --git a/include/console_channel.inc b/include/console_channel.inc index ba48a31563..7c3e8b3c99 100644 --- a/include/console_channel.inc +++ b/include/console_channel.inc @@ -66,6 +66,9 @@ CONSOLE_CHANNEL(CC_SWITCH, "switch") #endif CONSOLE_CHANNEL(CC_SYSTEM, "system") CONSOLE_CHANNEL(CC_TASK, "task") +#ifdef CONFIG_TOUCHPAD_ELAN +CONSOLE_CHANNEL(CC_TOUCHPAD, "touchpad") +#endif #ifdef CONFIG_DPTF CONSOLE_CHANNEL(CC_DPTF, "dptf") #endif |