mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
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>
This commit is contained in:
committed by
chrome-bot
parent
840ba2b6e4
commit
de0f53afef
@@ -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
|
||||
|
||||
|
||||
245
driver/touchpad_elan.c
Normal file
245
driver/touchpad_elan.c
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
13
driver/touchpad_elan.h
Normal file
13
driver/touchpad_elan.h
Normal file
@@ -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
|
||||
@@ -1903,6 +1903,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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user