drivers: input: gt911: Add support for multitouch events
The gt911 can recognize up to 5 touch points at a time. Add code to support these multi-touch events. Signed-off-by: Farah Fliss <farah.fliss@nxp.com> Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
This commit is contained in:
parent
bd658642e1
commit
ad254b06c8
2 changed files with 74 additions and 30 deletions
|
|
@ -26,4 +26,11 @@ config INPUT_GT911_INTERRUPT
|
|||
help
|
||||
Enable interrupt support (requires GPIO).
|
||||
|
||||
config INPUT_GT911_MAX_TOUCH_POINTS
|
||||
int "Touch Number"
|
||||
default 1
|
||||
range 1 5
|
||||
help
|
||||
Maximum number of touch points to be handled.
|
||||
Multitouch is ignored if equal to 1.
|
||||
endif # INPUT_GT911
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@
|
|||
LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL);
|
||||
|
||||
/* GT911 used registers */
|
||||
#define DEVICE_ID BSWAP_16(0x8140U)
|
||||
#define REG_STATUS BSWAP_16(0x814EU)
|
||||
#define REG_FIRST_POINT BSWAP_16(0x814FU)
|
||||
#define DEVICE_ID BSWAP_16(0x8140U)
|
||||
#define REG_STATUS BSWAP_16(0x814EU)
|
||||
|
||||
/* REG_TD_STATUS: Touch points. */
|
||||
#define TOUCH_POINTS_MSK 0x0FU
|
||||
|
|
@ -28,10 +27,16 @@ LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL);
|
|||
#define TOUCH_STATUS_MSK (1 << 7U)
|
||||
|
||||
/* The GT911's config */
|
||||
#define REG_GT911_CONFIG BSWAP_16(0x8047U)
|
||||
#define REG_CONFIG_VERSION REG_GT911_CONFIG
|
||||
#define REG_CONFIG_SIZE 186U
|
||||
#define GT911_PRODUCT_ID 0x00313139U
|
||||
#define REG_GT911_CONFIG BSWAP_16(0x8047U)
|
||||
#define REG_CONFIG_VERSION REG_GT911_CONFIG
|
||||
#define REG_CONFIG_TOUCH_NUM_OFFSET 0x5
|
||||
#define REG_CONFIG_SIZE 186U
|
||||
#define GT911_PRODUCT_ID 0x00313139U
|
||||
|
||||
/* Points registers */
|
||||
#define REG_POINT_0 0x814F
|
||||
#define POINT_OFFSET 0x8
|
||||
#define REG_POINT_ADDR(n) BSWAP_16(REG_POINT_0 + POINT_OFFSET * n)
|
||||
|
||||
/** GT911 configuration (DT). */
|
||||
struct gt911_config {
|
||||
|
|
@ -101,27 +106,29 @@ static int gt911_process(const struct device *dev)
|
|||
int r;
|
||||
uint16_t reg_addr;
|
||||
uint8_t status;
|
||||
uint8_t i;
|
||||
uint8_t j;
|
||||
uint16_t row;
|
||||
uint16_t col;
|
||||
uint8_t points;
|
||||
struct gt911_point_reg point_reg;
|
||||
uint16_t row, col;
|
||||
bool pressed;
|
||||
static uint8_t prev_points;
|
||||
struct gt911_point_reg point_reg[CONFIG_INPUT_GT911_MAX_TOUCH_POINTS];
|
||||
static struct gt911_point_reg prev_point_reg[CONFIG_INPUT_GT911_MAX_TOUCH_POINTS];
|
||||
|
||||
/* obtain number of touch points (NOTE: multi-touch ignored) */
|
||||
/* obtain number of touch points */
|
||||
reg_addr = REG_STATUS;
|
||||
r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), &status, sizeof(status));
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
points = status & TOUCH_POINTS_MSK;
|
||||
if (points != 0U && points != 1U && (0 != (status & TOUCH_STATUS_MSK))) {
|
||||
points = 1;
|
||||
}
|
||||
|
||||
if (!(status & TOUCH_STATUS_MSK)) {
|
||||
/* Status bit not set, ignore this event */
|
||||
return 0;
|
||||
}
|
||||
|
||||
points = status & TOUCH_POINTS_MSK;
|
||||
|
||||
/* need to clear the status */
|
||||
uint8_t clear_buffer[3] = {(uint8_t)REG_STATUS, (uint8_t)(REG_STATUS >> 8), 0};
|
||||
|
||||
|
|
@ -130,29 +137,56 @@ static int gt911_process(const struct device *dev)
|
|||
return r;
|
||||
}
|
||||
|
||||
/* obtain first point X, Y coordinates and event from:
|
||||
* REG_P1_XH, REG_P1_XL, REG_P1_YH, REG_P1_YL.
|
||||
*/
|
||||
reg_addr = REG_FIRST_POINT;
|
||||
r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), &point_reg, sizeof(point_reg));
|
||||
if (r < 0) {
|
||||
return r;
|
||||
/* current points array */
|
||||
for (i = 0; i <= points; i++) {
|
||||
reg_addr = REG_POINT_ADDR(i);
|
||||
r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), &point_reg[i],
|
||||
sizeof(point_reg[i]));
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
pressed = (points == 1);
|
||||
row = ((point_reg.high_y) << 8U) | point_reg.low_y;
|
||||
col = ((point_reg.high_x) << 8U) | point_reg.low_x;
|
||||
/* touch events */
|
||||
for (i = 0; i < points; i++) {
|
||||
if (CONFIG_INPUT_GT911_MAX_TOUCH_POINTS > 1) {
|
||||
input_report_abs(dev, INPUT_ABS_MT_SLOT, point_reg[i].id, true, K_FOREVER);
|
||||
}
|
||||
|
||||
LOG_DBG("pressed: %d, row: %d, col: %d", pressed, row, col);
|
||||
row = ((point_reg[i].high_y) << 8U) | point_reg[i].low_y;
|
||||
col = ((point_reg[i].high_x) << 8U) | point_reg[i].low_x;
|
||||
|
||||
if (pressed) {
|
||||
input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER);
|
||||
input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER);
|
||||
input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER);
|
||||
} else {
|
||||
input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER);
|
||||
}
|
||||
|
||||
/* release events */
|
||||
for (i = 0; i < prev_points; i++) {
|
||||
/* We look for the prev_point in the current points list */
|
||||
for (j = 0; j < points; j++) {
|
||||
if (prev_point_reg[i].id == point_reg[j].id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == points) {
|
||||
if (CONFIG_INPUT_GT911_MAX_TOUCH_POINTS > 1) {
|
||||
input_report_abs(dev, INPUT_ABS_MT_SLOT, prev_point_reg[i].id, true,
|
||||
K_FOREVER);
|
||||
}
|
||||
row = ((prev_point_reg[i].high_y) << 8U) | prev_point_reg[i].low_y;
|
||||
col = ((prev_point_reg[i].high_x) << 8U) | prev_point_reg[i].low_x;
|
||||
input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER);
|
||||
input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER);
|
||||
input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(prev_point_reg, point_reg, sizeof(point_reg));
|
||||
prev_points = points;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -328,6 +362,9 @@ static int gt911_init(const struct device *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
gt911_config_firmware[REG_CONFIG_TOUCH_NUM_OFFSET + 2] =
|
||||
CONFIG_INPUT_GT911_MAX_TOUCH_POINTS;
|
||||
|
||||
gt911_config_firmware[REG_CONFIG_SIZE] =
|
||||
gt911_get_firmware_checksum(gt911_config_firmware + 2);
|
||||
gt911_config_firmware[REG_CONFIG_SIZE + 1] = 1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue