18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Goodix Touchscreens 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Red Hat Inc. 68c2ecf20Sopenharmony_ci * Copyright (c) 2015 K. Merker <merker@debian.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This code is based on gt9xx.c authored by andrew@goodix.com: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * 2010 - 2012 Goodix Technology. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/dmi.h> 168c2ecf20Sopenharmony_ci#include <linux/firmware.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/i2c.h> 198c2ecf20Sopenharmony_ci#include <linux/input.h> 208c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 218c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/irq.h> 258c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 268c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/acpi.h> 298c2ecf20Sopenharmony_ci#include <linux/of.h> 308c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define GOODIX_GPIO_INT_NAME "irq" 338c2ecf20Sopenharmony_ci#define GOODIX_GPIO_RST_NAME "reset" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define GOODIX_MAX_HEIGHT 4096 368c2ecf20Sopenharmony_ci#define GOODIX_MAX_WIDTH 4096 378c2ecf20Sopenharmony_ci#define GOODIX_INT_TRIGGER 1 388c2ecf20Sopenharmony_ci#define GOODIX_CONTACT_SIZE 8 398c2ecf20Sopenharmony_ci#define GOODIX_MAX_CONTACT_SIZE 9 408c2ecf20Sopenharmony_ci#define GOODIX_MAX_CONTACTS 10 418c2ecf20Sopenharmony_ci#define GOODIX_MAX_KEYS 7 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_MIN_LENGTH 186 448c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_911_LENGTH 186 458c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_967_LENGTH 228 468c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_GT9X_LENGTH 240 478c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_MAX_LENGTH 240 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Register defines */ 508c2ecf20Sopenharmony_ci#define GOODIX_REG_COMMAND 0x8040 518c2ecf20Sopenharmony_ci#define GOODIX_CMD_SCREEN_OFF 0x05 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define GOODIX_READ_COOR_ADDR 0x814E 548c2ecf20Sopenharmony_ci#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 558c2ecf20Sopenharmony_ci#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 568c2ecf20Sopenharmony_ci#define GOODIX_REG_ID 0x8140 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define GOODIX_BUFFER_STATUS_READY BIT(7) 598c2ecf20Sopenharmony_ci#define GOODIX_HAVE_KEY BIT(4) 608c2ecf20Sopenharmony_ci#define GOODIX_BUFFER_STATUS_TIMEOUT 20 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define RESOLUTION_LOC 1 638c2ecf20Sopenharmony_ci#define MAX_CONTACTS_LOC 5 648c2ecf20Sopenharmony_ci#define TRIGGER_LOC 6 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Our special handling for GPIO accesses through ACPI is x86 specific */ 678c2ecf20Sopenharmony_ci#if defined CONFIG_X86 && defined CONFIG_ACPI 688c2ecf20Sopenharmony_ci#define ACPI_GPIO_SUPPORT 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct goodix_ts_data; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cienum goodix_irq_pin_access_method { 748c2ecf20Sopenharmony_ci IRQ_PIN_ACCESS_NONE, 758c2ecf20Sopenharmony_ci IRQ_PIN_ACCESS_GPIO, 768c2ecf20Sopenharmony_ci IRQ_PIN_ACCESS_ACPI_GPIO, 778c2ecf20Sopenharmony_ci IRQ_PIN_ACCESS_ACPI_METHOD, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct goodix_chip_data { 818c2ecf20Sopenharmony_ci u16 config_addr; 828c2ecf20Sopenharmony_ci int config_len; 838c2ecf20Sopenharmony_ci int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len); 848c2ecf20Sopenharmony_ci void (*calc_config_checksum)(struct goodix_ts_data *ts); 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct goodix_chip_id { 888c2ecf20Sopenharmony_ci const char *id; 898c2ecf20Sopenharmony_ci const struct goodix_chip_data *data; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define GOODIX_ID_MAX_LEN 4 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct goodix_ts_data { 958c2ecf20Sopenharmony_ci struct i2c_client *client; 968c2ecf20Sopenharmony_ci struct input_dev *input_dev; 978c2ecf20Sopenharmony_ci const struct goodix_chip_data *chip; 988c2ecf20Sopenharmony_ci struct touchscreen_properties prop; 998c2ecf20Sopenharmony_ci unsigned int max_touch_num; 1008c2ecf20Sopenharmony_ci unsigned int int_trigger_type; 1018c2ecf20Sopenharmony_ci struct regulator *avdd28; 1028c2ecf20Sopenharmony_ci struct regulator *vddio; 1038c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_int; 1048c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_rst; 1058c2ecf20Sopenharmony_ci int gpio_count; 1068c2ecf20Sopenharmony_ci int gpio_int_idx; 1078c2ecf20Sopenharmony_ci char id[GOODIX_ID_MAX_LEN + 1]; 1088c2ecf20Sopenharmony_ci u16 version; 1098c2ecf20Sopenharmony_ci const char *cfg_name; 1108c2ecf20Sopenharmony_ci bool reset_controller_at_probe; 1118c2ecf20Sopenharmony_ci bool load_cfg_from_disk; 1128c2ecf20Sopenharmony_ci struct completion firmware_loading_complete; 1138c2ecf20Sopenharmony_ci unsigned long irq_flags; 1148c2ecf20Sopenharmony_ci enum goodix_irq_pin_access_method irq_pin_access_method; 1158c2ecf20Sopenharmony_ci unsigned int contact_size; 1168c2ecf20Sopenharmony_ci u8 config[GOODIX_CONFIG_MAX_LENGTH]; 1178c2ecf20Sopenharmony_ci unsigned short keymap[GOODIX_MAX_KEYS]; 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts, 1218c2ecf20Sopenharmony_ci const u8 *cfg, int len); 1228c2ecf20Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts, 1238c2ecf20Sopenharmony_ci const u8 *cfg, int len); 1248c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts); 1258c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt1x_chip_data = { 1288c2ecf20Sopenharmony_ci .config_addr = GOODIX_GT1X_REG_CONFIG_DATA, 1298c2ecf20Sopenharmony_ci .config_len = GOODIX_CONFIG_GT9X_LENGTH, 1308c2ecf20Sopenharmony_ci .check_config = goodix_check_cfg_16, 1318c2ecf20Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_16, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt911_chip_data = { 1358c2ecf20Sopenharmony_ci .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, 1368c2ecf20Sopenharmony_ci .config_len = GOODIX_CONFIG_911_LENGTH, 1378c2ecf20Sopenharmony_ci .check_config = goodix_check_cfg_8, 1388c2ecf20Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_8, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt967_chip_data = { 1428c2ecf20Sopenharmony_ci .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, 1438c2ecf20Sopenharmony_ci .config_len = GOODIX_CONFIG_967_LENGTH, 1448c2ecf20Sopenharmony_ci .check_config = goodix_check_cfg_8, 1458c2ecf20Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_8, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt9x_chip_data = { 1498c2ecf20Sopenharmony_ci .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, 1508c2ecf20Sopenharmony_ci .config_len = GOODIX_CONFIG_GT9X_LENGTH, 1518c2ecf20Sopenharmony_ci .check_config = goodix_check_cfg_8, 1528c2ecf20Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_8, 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const struct goodix_chip_id goodix_chip_ids[] = { 1568c2ecf20Sopenharmony_ci { .id = "1151", .data = >1x_chip_data }, 1578c2ecf20Sopenharmony_ci { .id = "1158", .data = >1x_chip_data }, 1588c2ecf20Sopenharmony_ci { .id = "5663", .data = >1x_chip_data }, 1598c2ecf20Sopenharmony_ci { .id = "5688", .data = >1x_chip_data }, 1608c2ecf20Sopenharmony_ci { .id = "917S", .data = >1x_chip_data }, 1618c2ecf20Sopenharmony_ci { .id = "9286", .data = >1x_chip_data }, 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci { .id = "911", .data = >911_chip_data }, 1648c2ecf20Sopenharmony_ci { .id = "9271", .data = >911_chip_data }, 1658c2ecf20Sopenharmony_ci { .id = "9110", .data = >911_chip_data }, 1668c2ecf20Sopenharmony_ci { .id = "9111", .data = >911_chip_data }, 1678c2ecf20Sopenharmony_ci { .id = "927", .data = >911_chip_data }, 1688c2ecf20Sopenharmony_ci { .id = "928", .data = >911_chip_data }, 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci { .id = "912", .data = >967_chip_data }, 1718c2ecf20Sopenharmony_ci { .id = "9147", .data = >967_chip_data }, 1728c2ecf20Sopenharmony_ci { .id = "967", .data = >967_chip_data }, 1738c2ecf20Sopenharmony_ci { } 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic const unsigned long goodix_irq_flags[] = { 1778c2ecf20Sopenharmony_ci IRQ_TYPE_EDGE_RISING, 1788c2ecf20Sopenharmony_ci IRQ_TYPE_EDGE_FALLING, 1798c2ecf20Sopenharmony_ci IRQ_TYPE_LEVEL_LOW, 1808c2ecf20Sopenharmony_ci IRQ_TYPE_LEVEL_HIGH, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const struct dmi_system_id nine_bytes_report[] = { 1848c2ecf20Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86) 1858c2ecf20Sopenharmony_ci { 1868c2ecf20Sopenharmony_ci /* Lenovo Yoga Book X90F / X90L */ 1878c2ecf20Sopenharmony_ci .matches = { 1888c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 1898c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), 1908c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci }, 1938c2ecf20Sopenharmony_ci { 1948c2ecf20Sopenharmony_ci /* Lenovo Yoga Book X91F / X91L */ 1958c2ecf20Sopenharmony_ci .matches = { 1968c2ecf20Sopenharmony_ci /* Non exact match to match F + L versions */ 1978c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci }, 2008c2ecf20Sopenharmony_ci#endif 2018c2ecf20Sopenharmony_ci {} 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * Those tablets have their x coordinate inverted 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_cistatic const struct dmi_system_id inverted_x_screen[] = { 2088c2ecf20Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86) 2098c2ecf20Sopenharmony_ci { 2108c2ecf20Sopenharmony_ci .ident = "Cube I15-TC", 2118c2ecf20Sopenharmony_ci .matches = { 2128c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Cube"), 2138c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "I15-TC") 2148c2ecf20Sopenharmony_ci }, 2158c2ecf20Sopenharmony_ci }, 2168c2ecf20Sopenharmony_ci#endif 2178c2ecf20Sopenharmony_ci {} 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/** 2218c2ecf20Sopenharmony_ci * goodix_i2c_read - read data from a register of the i2c slave device. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * @client: i2c device. 2248c2ecf20Sopenharmony_ci * @reg: the register to read from. 2258c2ecf20Sopenharmony_ci * @buf: raw write data buffer. 2268c2ecf20Sopenharmony_ci * @len: length of the buffer to write 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic int goodix_i2c_read(struct i2c_client *client, 2298c2ecf20Sopenharmony_ci u16 reg, u8 *buf, int len) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct i2c_msg msgs[2]; 2328c2ecf20Sopenharmony_ci __be16 wbuf = cpu_to_be16(reg); 2338c2ecf20Sopenharmony_ci int ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci msgs[0].flags = 0; 2368c2ecf20Sopenharmony_ci msgs[0].addr = client->addr; 2378c2ecf20Sopenharmony_ci msgs[0].len = 2; 2388c2ecf20Sopenharmony_ci msgs[0].buf = (u8 *)&wbuf; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci msgs[1].flags = I2C_M_RD; 2418c2ecf20Sopenharmony_ci msgs[1].addr = client->addr; 2428c2ecf20Sopenharmony_ci msgs[1].len = len; 2438c2ecf20Sopenharmony_ci msgs[1].buf = buf; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, msgs, 2); 2468c2ecf20Sopenharmony_ci return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/** 2508c2ecf20Sopenharmony_ci * goodix_i2c_write - write data to a register of the i2c slave device. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * @client: i2c device. 2538c2ecf20Sopenharmony_ci * @reg: the register to write to. 2548c2ecf20Sopenharmony_ci * @buf: raw data buffer to write. 2558c2ecf20Sopenharmony_ci * @len: length of the buffer to write 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, 2588c2ecf20Sopenharmony_ci unsigned len) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci u8 *addr_buf; 2618c2ecf20Sopenharmony_ci struct i2c_msg msg; 2628c2ecf20Sopenharmony_ci int ret; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci addr_buf = kmalloc(len + 2, GFP_KERNEL); 2658c2ecf20Sopenharmony_ci if (!addr_buf) 2668c2ecf20Sopenharmony_ci return -ENOMEM; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci addr_buf[0] = reg >> 8; 2698c2ecf20Sopenharmony_ci addr_buf[1] = reg & 0xFF; 2708c2ecf20Sopenharmony_ci memcpy(&addr_buf[2], buf, len); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci msg.flags = 0; 2738c2ecf20Sopenharmony_ci msg.addr = client->addr; 2748c2ecf20Sopenharmony_ci msg.buf = addr_buf; 2758c2ecf20Sopenharmony_ci msg.len = len + 2; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &msg, 1); 2788c2ecf20Sopenharmony_ci kfree(addr_buf); 2798c2ecf20Sopenharmony_ci return ret < 0 ? ret : (ret != 1 ? -EIO : 0); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci return goodix_i2c_write(client, reg, &value, sizeof(value)); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic const struct goodix_chip_data *goodix_get_chip_data(const char *id) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci unsigned int i; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for (i = 0; goodix_chip_ids[i].id; i++) { 2928c2ecf20Sopenharmony_ci if (!strcmp(goodix_chip_ids[i].id, id)) 2938c2ecf20Sopenharmony_ci return goodix_chip_ids[i].data; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return >9x_chip_data; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci unsigned long max_timeout; 3028c2ecf20Sopenharmony_ci int touch_num; 3038c2ecf20Sopenharmony_ci int error; 3048c2ecf20Sopenharmony_ci u16 addr = GOODIX_READ_COOR_ADDR; 3058c2ecf20Sopenharmony_ci /* 3068c2ecf20Sopenharmony_ci * We are going to read 1-byte header, 3078c2ecf20Sopenharmony_ci * ts->contact_size * max(1, touch_num) bytes of coordinates 3088c2ecf20Sopenharmony_ci * and 1-byte footer which contains the touch-key code. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci const int header_contact_keycode_size = 1 + ts->contact_size + 1; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * The 'buffer status' bit, which indicates that the data is valid, is 3148c2ecf20Sopenharmony_ci * not set as soon as the interrupt is raised, but slightly after. 3158c2ecf20Sopenharmony_ci * This takes around 10 ms to happen, so we poll for 20 ms. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT); 3188c2ecf20Sopenharmony_ci do { 3198c2ecf20Sopenharmony_ci error = goodix_i2c_read(ts->client, addr, data, 3208c2ecf20Sopenharmony_ci header_contact_keycode_size); 3218c2ecf20Sopenharmony_ci if (error) { 3228c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "I2C transfer error: %d\n", 3238c2ecf20Sopenharmony_ci error); 3248c2ecf20Sopenharmony_ci return error; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (data[0] & GOODIX_BUFFER_STATUS_READY) { 3288c2ecf20Sopenharmony_ci touch_num = data[0] & 0x0f; 3298c2ecf20Sopenharmony_ci if (touch_num > ts->max_touch_num) 3308c2ecf20Sopenharmony_ci return -EPROTO; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (touch_num > 1) { 3338c2ecf20Sopenharmony_ci addr += header_contact_keycode_size; 3348c2ecf20Sopenharmony_ci data += header_contact_keycode_size; 3358c2ecf20Sopenharmony_ci error = goodix_i2c_read(ts->client, 3368c2ecf20Sopenharmony_ci addr, data, 3378c2ecf20Sopenharmony_ci ts->contact_size * 3388c2ecf20Sopenharmony_ci (touch_num - 1)); 3398c2ecf20Sopenharmony_ci if (error) 3408c2ecf20Sopenharmony_ci return error; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return touch_num; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci usleep_range(1000, 2000); /* Poll every 1 - 2 ms */ 3478c2ecf20Sopenharmony_ci } while (time_before(jiffies, max_timeout)); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * The Goodix panel will send spurious interrupts after a 3518c2ecf20Sopenharmony_ci * 'finger up' event, which will always cause a timeout. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci return -ENOMSG; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci int id = coor_data[0] & 0x0F; 3598c2ecf20Sopenharmony_ci int input_x = get_unaligned_le16(&coor_data[1]); 3608c2ecf20Sopenharmony_ci int input_y = get_unaligned_le16(&coor_data[3]); 3618c2ecf20Sopenharmony_ci int input_w = get_unaligned_le16(&coor_data[5]); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci input_mt_slot(ts->input_dev, id); 3648c2ecf20Sopenharmony_ci input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); 3658c2ecf20Sopenharmony_ci touchscreen_report_pos(ts->input_dev, &ts->prop, 3668c2ecf20Sopenharmony_ci input_x, input_y, true); 3678c2ecf20Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); 3688c2ecf20Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci int id = coor_data[1] & 0x0F; 3748c2ecf20Sopenharmony_ci int input_x = get_unaligned_le16(&coor_data[3]); 3758c2ecf20Sopenharmony_ci int input_y = get_unaligned_le16(&coor_data[5]); 3768c2ecf20Sopenharmony_ci int input_w = get_unaligned_le16(&coor_data[7]); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci input_mt_slot(ts->input_dev, id); 3798c2ecf20Sopenharmony_ci input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); 3808c2ecf20Sopenharmony_ci touchscreen_report_pos(ts->input_dev, &ts->prop, 3818c2ecf20Sopenharmony_ci input_x, input_y, true); 3828c2ecf20Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); 3838c2ecf20Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int touch_num; 3898c2ecf20Sopenharmony_ci u8 key_value; 3908c2ecf20Sopenharmony_ci int i; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (data[0] & GOODIX_HAVE_KEY) { 3938c2ecf20Sopenharmony_ci touch_num = data[0] & 0x0f; 3948c2ecf20Sopenharmony_ci key_value = data[1 + ts->contact_size * touch_num]; 3958c2ecf20Sopenharmony_ci for (i = 0; i < GOODIX_MAX_KEYS; i++) 3968c2ecf20Sopenharmony_ci if (key_value & BIT(i)) 3978c2ecf20Sopenharmony_ci input_report_key(ts->input_dev, 3988c2ecf20Sopenharmony_ci ts->keymap[i], 1); 3998c2ecf20Sopenharmony_ci } else { 4008c2ecf20Sopenharmony_ci for (i = 0; i < GOODIX_MAX_KEYS; i++) 4018c2ecf20Sopenharmony_ci input_report_key(ts->input_dev, ts->keymap[i], 0); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/** 4068c2ecf20Sopenharmony_ci * goodix_process_events - Process incoming events 4078c2ecf20Sopenharmony_ci * 4088c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * Called when the IRQ is triggered. Read the current device state, and push 4118c2ecf20Sopenharmony_ci * the input events to the user space. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_cistatic void goodix_process_events(struct goodix_ts_data *ts) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci u8 point_data[2 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; 4168c2ecf20Sopenharmony_ci int touch_num; 4178c2ecf20Sopenharmony_ci int i; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci touch_num = goodix_ts_read_input_report(ts, point_data); 4208c2ecf20Sopenharmony_ci if (touch_num < 0) 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci goodix_ts_report_key(ts, point_data); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci for (i = 0; i < touch_num; i++) 4268c2ecf20Sopenharmony_ci if (ts->contact_size == 9) 4278c2ecf20Sopenharmony_ci goodix_ts_report_touch_9b(ts, 4288c2ecf20Sopenharmony_ci &point_data[1 + ts->contact_size * i]); 4298c2ecf20Sopenharmony_ci else 4308c2ecf20Sopenharmony_ci goodix_ts_report_touch_8b(ts, 4318c2ecf20Sopenharmony_ci &point_data[1 + ts->contact_size * i]); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci input_mt_sync_frame(ts->input_dev); 4348c2ecf20Sopenharmony_ci input_sync(ts->input_dev); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci/** 4388c2ecf20Sopenharmony_ci * goodix_ts_irq_handler - The IRQ handler 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * @irq: interrupt number. 4418c2ecf20Sopenharmony_ci * @dev_id: private data pointer. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_cistatic irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = dev_id; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci goodix_process_events(ts); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0) 4508c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "I2C write end_cmd error\n"); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic void goodix_free_irq(struct goodix_ts_data *ts) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci devm_free_irq(&ts->client->dev, ts->client->irq, ts); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int goodix_request_irq(struct goodix_ts_data *ts) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, 4638c2ecf20Sopenharmony_ci NULL, goodix_ts_irq_handler, 4648c2ecf20Sopenharmony_ci ts->irq_flags, ts->client->name, ts); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int i, raw_cfg_len = len - 2; 4708c2ecf20Sopenharmony_ci u8 check_sum = 0; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci for (i = 0; i < raw_cfg_len; i++) 4738c2ecf20Sopenharmony_ci check_sum += cfg[i]; 4748c2ecf20Sopenharmony_ci check_sum = (~check_sum) + 1; 4758c2ecf20Sopenharmony_ci if (check_sum != cfg[raw_cfg_len]) { 4768c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 4778c2ecf20Sopenharmony_ci "The checksum of the config fw is not correct"); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (cfg[raw_cfg_len + 1] != 1) { 4828c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 4838c2ecf20Sopenharmony_ci "Config fw must have Config_Fresh register set"); 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci int i, raw_cfg_len = ts->chip->config_len - 2; 4938c2ecf20Sopenharmony_ci u8 check_sum = 0; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci for (i = 0; i < raw_cfg_len; i++) 4968c2ecf20Sopenharmony_ci check_sum += ts->config[i]; 4978c2ecf20Sopenharmony_ci check_sum = (~check_sum) + 1; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci ts->config[raw_cfg_len] = check_sum; 5008c2ecf20Sopenharmony_ci ts->config[raw_cfg_len + 1] = 1; /* Set "config_fresh" bit */ 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts, const u8 *cfg, 5048c2ecf20Sopenharmony_ci int len) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci int i, raw_cfg_len = len - 3; 5078c2ecf20Sopenharmony_ci u16 check_sum = 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i = 0; i < raw_cfg_len; i += 2) 5108c2ecf20Sopenharmony_ci check_sum += get_unaligned_be16(&cfg[i]); 5118c2ecf20Sopenharmony_ci check_sum = (~check_sum) + 1; 5128c2ecf20Sopenharmony_ci if (check_sum != get_unaligned_be16(&cfg[raw_cfg_len])) { 5138c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 5148c2ecf20Sopenharmony_ci "The checksum of the config fw is not correct"); 5158c2ecf20Sopenharmony_ci return -EINVAL; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (cfg[raw_cfg_len + 2] != 1) { 5198c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 5208c2ecf20Sopenharmony_ci "Config fw must have Config_Fresh register set"); 5218c2ecf20Sopenharmony_ci return -EINVAL; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return 0; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci int i, raw_cfg_len = ts->chip->config_len - 3; 5308c2ecf20Sopenharmony_ci u16 check_sum = 0; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci for (i = 0; i < raw_cfg_len; i += 2) 5338c2ecf20Sopenharmony_ci check_sum += get_unaligned_be16(&ts->config[i]); 5348c2ecf20Sopenharmony_ci check_sum = (~check_sum) + 1; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci put_unaligned_be16(check_sum, &ts->config[raw_cfg_len]); 5378c2ecf20Sopenharmony_ci ts->config[raw_cfg_len + 2] = 1; /* Set "config_fresh" bit */ 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/** 5418c2ecf20Sopenharmony_ci * goodix_check_cfg - Checks if config fw is valid 5428c2ecf20Sopenharmony_ci * 5438c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer 5448c2ecf20Sopenharmony_ci * @cfg: firmware config data 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_cistatic int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci if (len < GOODIX_CONFIG_MIN_LENGTH || 5498c2ecf20Sopenharmony_ci len > GOODIX_CONFIG_MAX_LENGTH) { 5508c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 5518c2ecf20Sopenharmony_ci "The length of the config fw is not correct"); 5528c2ecf20Sopenharmony_ci return -EINVAL; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return ts->chip->check_config(ts, cfg, len); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/** 5598c2ecf20Sopenharmony_ci * goodix_send_cfg - Write fw config to device 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer 5628c2ecf20Sopenharmony_ci * @cfg: config firmware to write to device 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_cistatic int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci int error; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci error = goodix_check_cfg(ts, cfg, len); 5698c2ecf20Sopenharmony_ci if (error) 5708c2ecf20Sopenharmony_ci return error; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len); 5738c2ecf20Sopenharmony_ci if (error) { 5748c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "Failed to write config data: %d", 5758c2ecf20Sopenharmony_ci error); 5768c2ecf20Sopenharmony_ci return error; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci dev_dbg(&ts->client->dev, "Config sent successfully."); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Let the firmware reconfigure itself, so sleep for 10ms */ 5818c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT 5878c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(&ts->client->dev); 5908c2ecf20Sopenharmony_ci acpi_status status; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "INTI", NULL, NULL); 5938c2ecf20Sopenharmony_ci return ACPI_SUCCESS(status) ? 0 : -EIO; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(&ts->client->dev); 5998c2ecf20Sopenharmony_ci acpi_status status; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci status = acpi_execute_simple_method(handle, "INTO", value); 6028c2ecf20Sopenharmony_ci return ACPI_SUCCESS(status) ? 0 : -EIO; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci#else 6058c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 6088c2ecf20Sopenharmony_ci "%s called on device without ACPI support\n", __func__); 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 6158c2ecf20Sopenharmony_ci "%s called on device without ACPI support\n", __func__); 6168c2ecf20Sopenharmony_ci return -EINVAL; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci#endif 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int goodix_irq_direction_output(struct goodix_ts_data *ts, int value) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci switch (ts->irq_pin_access_method) { 6238c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_NONE: 6248c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 6258c2ecf20Sopenharmony_ci "%s called without an irq_pin_access_method set\n", 6268c2ecf20Sopenharmony_ci __func__); 6278c2ecf20Sopenharmony_ci return -EINVAL; 6288c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_GPIO: 6298c2ecf20Sopenharmony_ci return gpiod_direction_output(ts->gpiod_int, value); 6308c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_GPIO: 6318c2ecf20Sopenharmony_ci /* 6328c2ecf20Sopenharmony_ci * The IRQ pin triggers on a falling edge, so its gets marked 6338c2ecf20Sopenharmony_ci * as active-low, use output_raw to avoid the value inversion. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci return gpiod_direction_output_raw(ts->gpiod_int, value); 6368c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_METHOD: 6378c2ecf20Sopenharmony_ci return goodix_pin_acpi_output_method(ts, value); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci return -EINVAL; /* Never reached */ 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int goodix_irq_direction_input(struct goodix_ts_data *ts) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci switch (ts->irq_pin_access_method) { 6468c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_NONE: 6478c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 6488c2ecf20Sopenharmony_ci "%s called without an irq_pin_access_method set\n", 6498c2ecf20Sopenharmony_ci __func__); 6508c2ecf20Sopenharmony_ci return -EINVAL; 6518c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_GPIO: 6528c2ecf20Sopenharmony_ci return gpiod_direction_input(ts->gpiod_int); 6538c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_GPIO: 6548c2ecf20Sopenharmony_ci return gpiod_direction_input(ts->gpiod_int); 6558c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_METHOD: 6568c2ecf20Sopenharmony_ci return goodix_pin_acpi_direction_input(ts); 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return -EINVAL; /* Never reached */ 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int goodix_int_sync(struct goodix_ts_data *ts) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int error; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci error = goodix_irq_direction_output(ts, 0); 6678c2ecf20Sopenharmony_ci if (error) 6688c2ecf20Sopenharmony_ci return error; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci msleep(50); /* T5: 50ms */ 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci error = goodix_irq_direction_input(ts); 6738c2ecf20Sopenharmony_ci if (error) 6748c2ecf20Sopenharmony_ci return error; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci/** 6808c2ecf20Sopenharmony_ci * goodix_reset - Reset device during power on 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_cistatic int goodix_reset(struct goodix_ts_data *ts) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci int error; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* begin select I2C slave addr */ 6898c2ecf20Sopenharmony_ci error = gpiod_direction_output(ts->gpiod_rst, 0); 6908c2ecf20Sopenharmony_ci if (error) 6918c2ecf20Sopenharmony_ci return error; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci msleep(20); /* T2: > 10ms */ 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ 6968c2ecf20Sopenharmony_ci error = goodix_irq_direction_output(ts, ts->client->addr == 0x14); 6978c2ecf20Sopenharmony_ci if (error) 6988c2ecf20Sopenharmony_ci return error; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci usleep_range(100, 2000); /* T3: > 100us */ 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci error = gpiod_direction_output(ts->gpiod_rst, 1); 7038c2ecf20Sopenharmony_ci if (error) 7048c2ecf20Sopenharmony_ci return error; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci usleep_range(6000, 10000); /* T4: > 5ms */ 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* end select I2C slave addr */ 7098c2ecf20Sopenharmony_ci error = gpiod_direction_input(ts->gpiod_rst); 7108c2ecf20Sopenharmony_ci if (error) 7118c2ecf20Sopenharmony_ci return error; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci error = goodix_int_sync(ts); 7148c2ecf20Sopenharmony_ci if (error) 7158c2ecf20Sopenharmony_ci return error; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return 0; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT 7218c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h> 7228c2ecf20Sopenharmony_ci#include <asm/intel-family.h> 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic const struct x86_cpu_id baytrail_cpu_ids[] = { 7258c2ecf20Sopenharmony_ci { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, X86_FEATURE_ANY, }, 7268c2ecf20Sopenharmony_ci {} 7278c2ecf20Sopenharmony_ci}; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic inline bool is_byt(void) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci const struct x86_cpu_id *id = x86_match_cpu(baytrail_cpu_ids); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return !!id; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params first_gpio = { 0, 0, false }; 7378c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params second_gpio = { 1, 0, false }; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_first_gpios[] = { 7408c2ecf20Sopenharmony_ci { GOODIX_GPIO_INT_NAME "-gpios", &first_gpio, 1 }, 7418c2ecf20Sopenharmony_ci { GOODIX_GPIO_RST_NAME "-gpios", &second_gpio, 1 }, 7428c2ecf20Sopenharmony_ci { }, 7438c2ecf20Sopenharmony_ci}; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_last_gpios[] = { 7468c2ecf20Sopenharmony_ci { GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 }, 7478c2ecf20Sopenharmony_ci { GOODIX_GPIO_INT_NAME "-gpios", &second_gpio, 1 }, 7488c2ecf20Sopenharmony_ci { }, 7498c2ecf20Sopenharmony_ci}; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_reset_only_gpios[] = { 7528c2ecf20Sopenharmony_ci { GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 }, 7538c2ecf20Sopenharmony_ci { }, 7548c2ecf20Sopenharmony_ci}; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int goodix_resource(struct acpi_resource *ares, void *data) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = data; 7598c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 7608c2ecf20Sopenharmony_ci struct acpi_resource_gpio *gpio; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci switch (ares->type) { 7638c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_GPIO: 7648c2ecf20Sopenharmony_ci gpio = &ares->data.gpio; 7658c2ecf20Sopenharmony_ci if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) { 7668c2ecf20Sopenharmony_ci if (ts->gpio_int_idx == -1) { 7678c2ecf20Sopenharmony_ci ts->gpio_int_idx = ts->gpio_count; 7688c2ecf20Sopenharmony_ci } else { 7698c2ecf20Sopenharmony_ci dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n"); 7708c2ecf20Sopenharmony_ci ts->gpio_int_idx = -2; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci ts->gpio_count++; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci default: 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/* 7838c2ecf20Sopenharmony_ci * This function gets called in case we fail to get the irq GPIO directly 7848c2ecf20Sopenharmony_ci * because the ACPI tables lack GPIO-name to APCI _CRS index mappings 7858c2ecf20Sopenharmony_ci * (no _DSD UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 data). 7868c2ecf20Sopenharmony_ci * In that case we add our own mapping and then goodix_get_gpio_config() 7878c2ecf20Sopenharmony_ci * retries to get the GPIOs based on the added mapping. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci const struct acpi_gpio_mapping *gpio_mapping = NULL; 7928c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 7938c2ecf20Sopenharmony_ci LIST_HEAD(resources); 7948c2ecf20Sopenharmony_ci int ret; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci ts->gpio_count = 0; 7978c2ecf20Sopenharmony_ci ts->gpio_int_idx = -1; 7988c2ecf20Sopenharmony_ci ret = acpi_dev_get_resources(ACPI_COMPANION(dev), &resources, 7998c2ecf20Sopenharmony_ci goodix_resource, ts); 8008c2ecf20Sopenharmony_ci if (ret < 0) { 8018c2ecf20Sopenharmony_ci dev_err(dev, "Error getting ACPI resources: %d\n", ret); 8028c2ecf20Sopenharmony_ci return ret; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci acpi_dev_free_resource_list(&resources); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) { 8088c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO; 8098c2ecf20Sopenharmony_ci gpio_mapping = acpi_goodix_int_first_gpios; 8108c2ecf20Sopenharmony_ci } else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) { 8118c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO; 8128c2ecf20Sopenharmony_ci gpio_mapping = acpi_goodix_int_last_gpios; 8138c2ecf20Sopenharmony_ci } else if (ts->gpio_count == 1 && ts->gpio_int_idx == -1 && 8148c2ecf20Sopenharmony_ci acpi_has_method(ACPI_HANDLE(dev), "INTI") && 8158c2ecf20Sopenharmony_ci acpi_has_method(ACPI_HANDLE(dev), "INTO")) { 8168c2ecf20Sopenharmony_ci dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n"); 8178c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD; 8188c2ecf20Sopenharmony_ci gpio_mapping = acpi_goodix_reset_only_gpios; 8198c2ecf20Sopenharmony_ci } else if (is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) { 8208c2ecf20Sopenharmony_ci dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n"); 8218c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO; 8228c2ecf20Sopenharmony_ci gpio_mapping = acpi_goodix_int_last_gpios; 8238c2ecf20Sopenharmony_ci } else if (ts->gpio_count == 1 && ts->gpio_int_idx == 0) { 8248c2ecf20Sopenharmony_ci /* 8258c2ecf20Sopenharmony_ci * On newer devices there is only 1 GpioInt resource and _PS0 8268c2ecf20Sopenharmony_ci * does the whole reset sequence for us. 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci acpi_device_fix_up_power(ACPI_COMPANION(dev)); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* 8318c2ecf20Sopenharmony_ci * Before the _PS0 call the int GPIO may have been in output 8328c2ecf20Sopenharmony_ci * mode and the call should have put the int GPIO in input mode, 8338c2ecf20Sopenharmony_ci * but the GPIO subsys cached state may still think it is 8348c2ecf20Sopenharmony_ci * in output mode, causing gpiochip_lock_as_irq() failure. 8358c2ecf20Sopenharmony_ci * 8368c2ecf20Sopenharmony_ci * Add a mapping for the int GPIO to make the 8378c2ecf20Sopenharmony_ci * gpiod_int = gpiod_get(..., GPIOD_IN) call succeed, 8388c2ecf20Sopenharmony_ci * which will explicitly set the direction to input. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE; 8418c2ecf20Sopenharmony_ci gpio_mapping = acpi_goodix_int_first_gpios; 8428c2ecf20Sopenharmony_ci } else { 8438c2ecf20Sopenharmony_ci dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n", 8448c2ecf20Sopenharmony_ci ts->gpio_count, ts->gpio_int_idx); 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping); 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci#else 8518c2ecf20Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci return -EINVAL; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci#endif /* CONFIG_X86 && CONFIG_ACPI */ 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci/** 8588c2ecf20Sopenharmony_ci * goodix_get_gpio_config - Get GPIO config from ACPI/DT 8598c2ecf20Sopenharmony_ci * 8608c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_cistatic int goodix_get_gpio_config(struct goodix_ts_data *ts) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci int error; 8658c2ecf20Sopenharmony_ci struct device *dev; 8668c2ecf20Sopenharmony_ci struct gpio_desc *gpiod; 8678c2ecf20Sopenharmony_ci bool added_acpi_mappings = false; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (!ts->client) 8708c2ecf20Sopenharmony_ci return -EINVAL; 8718c2ecf20Sopenharmony_ci dev = &ts->client->dev; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci ts->avdd28 = devm_regulator_get(dev, "AVDD28"); 8748c2ecf20Sopenharmony_ci if (IS_ERR(ts->avdd28)) { 8758c2ecf20Sopenharmony_ci error = PTR_ERR(ts->avdd28); 8768c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 8778c2ecf20Sopenharmony_ci dev_err(dev, 8788c2ecf20Sopenharmony_ci "Failed to get AVDD28 regulator: %d\n", error); 8798c2ecf20Sopenharmony_ci return error; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci ts->vddio = devm_regulator_get(dev, "VDDIO"); 8838c2ecf20Sopenharmony_ci if (IS_ERR(ts->vddio)) { 8848c2ecf20Sopenharmony_ci error = PTR_ERR(ts->vddio); 8858c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 8868c2ecf20Sopenharmony_ci dev_err(dev, 8878c2ecf20Sopenharmony_ci "Failed to get VDDIO regulator: %d\n", error); 8888c2ecf20Sopenharmony_ci return error; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ciretry_get_irq_gpio: 8928c2ecf20Sopenharmony_ci /* Get the interrupt GPIO pin number */ 8938c2ecf20Sopenharmony_ci gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN); 8948c2ecf20Sopenharmony_ci if (IS_ERR(gpiod)) { 8958c2ecf20Sopenharmony_ci error = PTR_ERR(gpiod); 8968c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 8978c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to get %s GPIO: %d\n", 8988c2ecf20Sopenharmony_ci GOODIX_GPIO_INT_NAME, error); 8998c2ecf20Sopenharmony_ci return error; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) { 9028c2ecf20Sopenharmony_ci added_acpi_mappings = true; 9038c2ecf20Sopenharmony_ci if (goodix_add_acpi_gpio_mappings(ts) == 0) 9048c2ecf20Sopenharmony_ci goto retry_get_irq_gpio; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci ts->gpiod_int = gpiod; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* Get the reset line GPIO pin number */ 9108c2ecf20Sopenharmony_ci gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN); 9118c2ecf20Sopenharmony_ci if (IS_ERR(gpiod)) { 9128c2ecf20Sopenharmony_ci error = PTR_ERR(gpiod); 9138c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 9148c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to get %s GPIO: %d\n", 9158c2ecf20Sopenharmony_ci GOODIX_GPIO_RST_NAME, error); 9168c2ecf20Sopenharmony_ci return error; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci ts->gpiod_rst = gpiod; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci switch (ts->irq_pin_access_method) { 9228c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_GPIO: 9238c2ecf20Sopenharmony_ci /* 9248c2ecf20Sopenharmony_ci * We end up here if goodix_add_acpi_gpio_mappings() has 9258c2ecf20Sopenharmony_ci * called devm_acpi_dev_add_driver_gpios() because the ACPI 9268c2ecf20Sopenharmony_ci * tables did not contain name to index mappings. 9278c2ecf20Sopenharmony_ci * Check that we successfully got both GPIOs after we've 9288c2ecf20Sopenharmony_ci * added our own acpi_gpio_mapping and if we did not get both 9298c2ecf20Sopenharmony_ci * GPIOs reset irq_pin_access_method to IRQ_PIN_ACCESS_NONE. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_ci if (!ts->gpiod_int || !ts->gpiod_rst) 9328c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE; 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_METHOD: 9358c2ecf20Sopenharmony_ci if (!ts->gpiod_rst) 9368c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE; 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci default: 9398c2ecf20Sopenharmony_ci if (ts->gpiod_int && ts->gpiod_rst) { 9408c2ecf20Sopenharmony_ci ts->reset_controller_at_probe = true; 9418c2ecf20Sopenharmony_ci ts->load_cfg_from_disk = true; 9428c2ecf20Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_GPIO; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci/** 9508c2ecf20Sopenharmony_ci * goodix_read_config - Read the embedded configuration of the panel 9518c2ecf20Sopenharmony_ci * 9528c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer 9538c2ecf20Sopenharmony_ci * 9548c2ecf20Sopenharmony_ci * Must be called during probe 9558c2ecf20Sopenharmony_ci */ 9568c2ecf20Sopenharmony_cistatic void goodix_read_config(struct goodix_ts_data *ts) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci int x_max, y_max; 9598c2ecf20Sopenharmony_ci int error; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci error = goodix_i2c_read(ts->client, ts->chip->config_addr, 9628c2ecf20Sopenharmony_ci ts->config, ts->chip->config_len); 9638c2ecf20Sopenharmony_ci if (error) { 9648c2ecf20Sopenharmony_ci dev_warn(&ts->client->dev, "Error reading config: %d\n", 9658c2ecf20Sopenharmony_ci error); 9668c2ecf20Sopenharmony_ci ts->int_trigger_type = GOODIX_INT_TRIGGER; 9678c2ecf20Sopenharmony_ci ts->max_touch_num = GOODIX_MAX_CONTACTS; 9688c2ecf20Sopenharmony_ci return; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; 9728c2ecf20Sopenharmony_ci ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]); 9758c2ecf20Sopenharmony_ci y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]); 9768c2ecf20Sopenharmony_ci if (x_max && y_max) { 9778c2ecf20Sopenharmony_ci input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1); 9788c2ecf20Sopenharmony_ci input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci ts->chip->calc_config_checksum(ts); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci/** 9858c2ecf20Sopenharmony_ci * goodix_read_version - Read goodix touchscreen version 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_cistatic int goodix_read_version(struct goodix_ts_data *ts) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci int error; 9928c2ecf20Sopenharmony_ci u8 buf[6]; 9938c2ecf20Sopenharmony_ci char id_str[GOODIX_ID_MAX_LEN + 1]; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf)); 9968c2ecf20Sopenharmony_ci if (error) { 9978c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "read version failed: %d\n", error); 9988c2ecf20Sopenharmony_ci return error; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci memcpy(id_str, buf, GOODIX_ID_MAX_LEN); 10028c2ecf20Sopenharmony_ci id_str[GOODIX_ID_MAX_LEN] = 0; 10038c2ecf20Sopenharmony_ci strscpy(ts->id, id_str, GOODIX_ID_MAX_LEN + 1); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci ts->version = get_unaligned_le16(&buf[4]); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci dev_info(&ts->client->dev, "ID %s, version: %04x\n", ts->id, 10088c2ecf20Sopenharmony_ci ts->version); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci/** 10148c2ecf20Sopenharmony_ci * goodix_i2c_test - I2C test function to check if the device answers. 10158c2ecf20Sopenharmony_ci * 10168c2ecf20Sopenharmony_ci * @client: the i2c client 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_cistatic int goodix_i2c_test(struct i2c_client *client) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci int retry = 0; 10218c2ecf20Sopenharmony_ci int error; 10228c2ecf20Sopenharmony_ci u8 test; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci while (retry++ < 2) { 10258c2ecf20Sopenharmony_ci error = goodix_i2c_read(client, GOODIX_REG_ID, 10268c2ecf20Sopenharmony_ci &test, 1); 10278c2ecf20Sopenharmony_ci if (!error) 10288c2ecf20Sopenharmony_ci return 0; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c test failed attempt %d: %d\n", 10318c2ecf20Sopenharmony_ci retry, error); 10328c2ecf20Sopenharmony_ci msleep(20); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return error; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/** 10398c2ecf20Sopenharmony_ci * goodix_configure_dev - Finish device initialization 10408c2ecf20Sopenharmony_ci * 10418c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer 10428c2ecf20Sopenharmony_ci * 10438c2ecf20Sopenharmony_ci * Must be called from probe to finish initialization of the device. 10448c2ecf20Sopenharmony_ci * Contains the common initialization code for both devices that 10458c2ecf20Sopenharmony_ci * declare gpio pins and devices that do not. It is either called 10468c2ecf20Sopenharmony_ci * directly from probe or from request_firmware_wait callback. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_cistatic int goodix_configure_dev(struct goodix_ts_data *ts) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci int error; 10518c2ecf20Sopenharmony_ci int i; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci ts->int_trigger_type = GOODIX_INT_TRIGGER; 10548c2ecf20Sopenharmony_ci ts->max_touch_num = GOODIX_MAX_CONTACTS; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci ts->input_dev = devm_input_allocate_device(&ts->client->dev); 10578c2ecf20Sopenharmony_ci if (!ts->input_dev) { 10588c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "Failed to allocate input device."); 10598c2ecf20Sopenharmony_ci return -ENOMEM; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci ts->input_dev->name = "Goodix Capacitive TouchScreen"; 10638c2ecf20Sopenharmony_ci ts->input_dev->phys = "input/ts"; 10648c2ecf20Sopenharmony_ci ts->input_dev->id.bustype = BUS_I2C; 10658c2ecf20Sopenharmony_ci ts->input_dev->id.vendor = 0x0416; 10668c2ecf20Sopenharmony_ci if (kstrtou16(ts->id, 10, &ts->input_dev->id.product)) 10678c2ecf20Sopenharmony_ci ts->input_dev->id.product = 0x1001; 10688c2ecf20Sopenharmony_ci ts->input_dev->id.version = ts->version; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci ts->input_dev->keycode = ts->keymap; 10718c2ecf20Sopenharmony_ci ts->input_dev->keycodesize = sizeof(ts->keymap[0]); 10728c2ecf20Sopenharmony_ci ts->input_dev->keycodemax = GOODIX_MAX_KEYS; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* Capacitive Windows/Home button on some devices */ 10758c2ecf20Sopenharmony_ci for (i = 0; i < GOODIX_MAX_KEYS; ++i) { 10768c2ecf20Sopenharmony_ci if (i == 0) 10778c2ecf20Sopenharmony_ci ts->keymap[i] = KEY_LEFTMETA; 10788c2ecf20Sopenharmony_ci else 10798c2ecf20Sopenharmony_ci ts->keymap[i] = KEY_F1 + (i - 1); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci input_set_capability(ts->input_dev, EV_KEY, ts->keymap[i]); 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X); 10858c2ecf20Sopenharmony_ci input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y); 10868c2ecf20Sopenharmony_ci input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); 10878c2ecf20Sopenharmony_ci input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ciretry_read_config: 10908c2ecf20Sopenharmony_ci /* Read configuration and apply touchscreen parameters */ 10918c2ecf20Sopenharmony_ci goodix_read_config(ts); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* Try overriding touchscreen parameters via device properties */ 10948c2ecf20Sopenharmony_ci touchscreen_parse_properties(ts->input_dev, true, &ts->prop); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) { 10978c2ecf20Sopenharmony_ci if (!ts->reset_controller_at_probe && 10988c2ecf20Sopenharmony_ci ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) { 10998c2ecf20Sopenharmony_ci dev_info(&ts->client->dev, "Config not set, resetting controller\n"); 11008c2ecf20Sopenharmony_ci /* Retry after a controller reset */ 11018c2ecf20Sopenharmony_ci ts->reset_controller_at_probe = true; 11028c2ecf20Sopenharmony_ci error = goodix_reset(ts); 11038c2ecf20Sopenharmony_ci if (error) 11048c2ecf20Sopenharmony_ci return error; 11058c2ecf20Sopenharmony_ci goto retry_read_config; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 11088c2ecf20Sopenharmony_ci "Invalid config (%d, %d, %d), using defaults\n", 11098c2ecf20Sopenharmony_ci ts->prop.max_x, ts->prop.max_y, ts->max_touch_num); 11108c2ecf20Sopenharmony_ci ts->prop.max_x = GOODIX_MAX_WIDTH - 1; 11118c2ecf20Sopenharmony_ci ts->prop.max_y = GOODIX_MAX_HEIGHT - 1; 11128c2ecf20Sopenharmony_ci ts->max_touch_num = GOODIX_MAX_CONTACTS; 11138c2ecf20Sopenharmony_ci input_abs_set_max(ts->input_dev, 11148c2ecf20Sopenharmony_ci ABS_MT_POSITION_X, ts->prop.max_x); 11158c2ecf20Sopenharmony_ci input_abs_set_max(ts->input_dev, 11168c2ecf20Sopenharmony_ci ABS_MT_POSITION_Y, ts->prop.max_y); 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (dmi_check_system(nine_bytes_report)) { 11208c2ecf20Sopenharmony_ci ts->contact_size = 9; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci dev_dbg(&ts->client->dev, 11238c2ecf20Sopenharmony_ci "Non-standard 9-bytes report format quirk\n"); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (dmi_check_system(inverted_x_screen)) { 11278c2ecf20Sopenharmony_ci ts->prop.invert_x = true; 11288c2ecf20Sopenharmony_ci dev_dbg(&ts->client->dev, 11298c2ecf20Sopenharmony_ci "Applying 'inverted x screen' quirk\n"); 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci error = input_mt_init_slots(ts->input_dev, ts->max_touch_num, 11338c2ecf20Sopenharmony_ci INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 11348c2ecf20Sopenharmony_ci if (error) { 11358c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 11368c2ecf20Sopenharmony_ci "Failed to initialize MT slots: %d", error); 11378c2ecf20Sopenharmony_ci return error; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci error = input_register_device(ts->input_dev); 11418c2ecf20Sopenharmony_ci if (error) { 11428c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 11438c2ecf20Sopenharmony_ci "Failed to register input device: %d", error); 11448c2ecf20Sopenharmony_ci return error; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; 11488c2ecf20Sopenharmony_ci error = goodix_request_irq(ts); 11498c2ecf20Sopenharmony_ci if (error) { 11508c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "request IRQ failed: %d\n", error); 11518c2ecf20Sopenharmony_ci return error; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return 0; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci/** 11588c2ecf20Sopenharmony_ci * goodix_config_cb - Callback to finish device init 11598c2ecf20Sopenharmony_ci * 11608c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer 11618c2ecf20Sopenharmony_ci * 11628c2ecf20Sopenharmony_ci * request_firmware_wait callback that finishes 11638c2ecf20Sopenharmony_ci * initialization of the device. 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_cistatic void goodix_config_cb(const struct firmware *cfg, void *ctx) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = ctx; 11688c2ecf20Sopenharmony_ci int error; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (cfg) { 11718c2ecf20Sopenharmony_ci /* send device configuration to the firmware */ 11728c2ecf20Sopenharmony_ci error = goodix_send_cfg(ts, cfg->data, cfg->size); 11738c2ecf20Sopenharmony_ci if (error) 11748c2ecf20Sopenharmony_ci goto err_release_cfg; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci goodix_configure_dev(ts); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cierr_release_cfg: 11808c2ecf20Sopenharmony_ci release_firmware(cfg); 11818c2ecf20Sopenharmony_ci complete_all(&ts->firmware_loading_complete); 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic void goodix_disable_regulators(void *arg) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = arg; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci regulator_disable(ts->vddio); 11898c2ecf20Sopenharmony_ci regulator_disable(ts->avdd28); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic int goodix_ts_probe(struct i2c_client *client, 11938c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct goodix_ts_data *ts; 11968c2ecf20Sopenharmony_ci int error; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 12018c2ecf20Sopenharmony_ci dev_err(&client->dev, "I2C check functionality failed.\n"); 12028c2ecf20Sopenharmony_ci return -ENXIO; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 12068c2ecf20Sopenharmony_ci if (!ts) 12078c2ecf20Sopenharmony_ci return -ENOMEM; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ts->client = client; 12108c2ecf20Sopenharmony_ci i2c_set_clientdata(client, ts); 12118c2ecf20Sopenharmony_ci init_completion(&ts->firmware_loading_complete); 12128c2ecf20Sopenharmony_ci ts->contact_size = GOODIX_CONTACT_SIZE; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci error = goodix_get_gpio_config(ts); 12158c2ecf20Sopenharmony_ci if (error) 12168c2ecf20Sopenharmony_ci return error; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* power up the controller */ 12198c2ecf20Sopenharmony_ci error = regulator_enable(ts->avdd28); 12208c2ecf20Sopenharmony_ci if (error) { 12218c2ecf20Sopenharmony_ci dev_err(&client->dev, 12228c2ecf20Sopenharmony_ci "Failed to enable AVDD28 regulator: %d\n", 12238c2ecf20Sopenharmony_ci error); 12248c2ecf20Sopenharmony_ci return error; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci error = regulator_enable(ts->vddio); 12288c2ecf20Sopenharmony_ci if (error) { 12298c2ecf20Sopenharmony_ci dev_err(&client->dev, 12308c2ecf20Sopenharmony_ci "Failed to enable VDDIO regulator: %d\n", 12318c2ecf20Sopenharmony_ci error); 12328c2ecf20Sopenharmony_ci regulator_disable(ts->avdd28); 12338c2ecf20Sopenharmony_ci return error; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci error = devm_add_action_or_reset(&client->dev, 12378c2ecf20Sopenharmony_ci goodix_disable_regulators, ts); 12388c2ecf20Sopenharmony_ci if (error) 12398c2ecf20Sopenharmony_ci return error; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cireset: 12428c2ecf20Sopenharmony_ci if (ts->reset_controller_at_probe) { 12438c2ecf20Sopenharmony_ci /* reset the controller */ 12448c2ecf20Sopenharmony_ci error = goodix_reset(ts); 12458c2ecf20Sopenharmony_ci if (error) { 12468c2ecf20Sopenharmony_ci dev_err(&client->dev, "Controller reset failed.\n"); 12478c2ecf20Sopenharmony_ci return error; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci error = goodix_i2c_test(client); 12528c2ecf20Sopenharmony_ci if (error) { 12538c2ecf20Sopenharmony_ci if (!ts->reset_controller_at_probe && 12548c2ecf20Sopenharmony_ci ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) { 12558c2ecf20Sopenharmony_ci /* Retry after a controller reset */ 12568c2ecf20Sopenharmony_ci ts->reset_controller_at_probe = true; 12578c2ecf20Sopenharmony_ci goto reset; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci dev_err(&client->dev, "I2C communication failure: %d\n", error); 12608c2ecf20Sopenharmony_ci return error; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci error = goodix_read_version(ts); 12648c2ecf20Sopenharmony_ci if (error) { 12658c2ecf20Sopenharmony_ci dev_err(&client->dev, "Read version failed.\n"); 12668c2ecf20Sopenharmony_ci return error; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci ts->chip = goodix_get_chip_data(ts->id); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (ts->load_cfg_from_disk) { 12728c2ecf20Sopenharmony_ci /* update device config */ 12738c2ecf20Sopenharmony_ci ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL, 12748c2ecf20Sopenharmony_ci "goodix_%s_cfg.bin", ts->id); 12758c2ecf20Sopenharmony_ci if (!ts->cfg_name) 12768c2ecf20Sopenharmony_ci return -ENOMEM; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name, 12798c2ecf20Sopenharmony_ci &client->dev, GFP_KERNEL, ts, 12808c2ecf20Sopenharmony_ci goodix_config_cb); 12818c2ecf20Sopenharmony_ci if (error) { 12828c2ecf20Sopenharmony_ci dev_err(&client->dev, 12838c2ecf20Sopenharmony_ci "Failed to invoke firmware loader: %d\n", 12848c2ecf20Sopenharmony_ci error); 12858c2ecf20Sopenharmony_ci return error; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci } else { 12908c2ecf20Sopenharmony_ci error = goodix_configure_dev(ts); 12918c2ecf20Sopenharmony_ci if (error) 12928c2ecf20Sopenharmony_ci return error; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return 0; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic int goodix_ts_remove(struct i2c_client *client) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = i2c_get_clientdata(client); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (ts->load_cfg_from_disk) 13038c2ecf20Sopenharmony_ci wait_for_completion(&ts->firmware_loading_complete); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci return 0; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_cistatic int __maybe_unused goodix_suspend(struct device *dev) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 13118c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = i2c_get_clientdata(client); 13128c2ecf20Sopenharmony_ci int error; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (ts->load_cfg_from_disk) 13158c2ecf20Sopenharmony_ci wait_for_completion(&ts->firmware_loading_complete); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* We need gpio pins to suspend/resume */ 13188c2ecf20Sopenharmony_ci if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { 13198c2ecf20Sopenharmony_ci disable_irq(client->irq); 13208c2ecf20Sopenharmony_ci return 0; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* Free IRQ as IRQ pin is used as output in the suspend sequence */ 13248c2ecf20Sopenharmony_ci goodix_free_irq(ts); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Output LOW on the INT pin for 5 ms */ 13278c2ecf20Sopenharmony_ci error = goodix_irq_direction_output(ts, 0); 13288c2ecf20Sopenharmony_ci if (error) { 13298c2ecf20Sopenharmony_ci goodix_request_irq(ts); 13308c2ecf20Sopenharmony_ci return error; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci usleep_range(5000, 6000); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND, 13368c2ecf20Sopenharmony_ci GOODIX_CMD_SCREEN_OFF); 13378c2ecf20Sopenharmony_ci if (error) { 13388c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "Screen off command failed\n"); 13398c2ecf20Sopenharmony_ci goodix_irq_direction_input(ts); 13408c2ecf20Sopenharmony_ci goodix_request_irq(ts); 13418c2ecf20Sopenharmony_ci return -EAGAIN; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci /* 13458c2ecf20Sopenharmony_ci * The datasheet specifies that the interval between sending screen-off 13468c2ecf20Sopenharmony_ci * command and wake-up should be longer than 58 ms. To avoid waking up 13478c2ecf20Sopenharmony_ci * sooner, delay 58ms here. 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci msleep(58); 13508c2ecf20Sopenharmony_ci return 0; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic int __maybe_unused goodix_resume(struct device *dev) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 13568c2ecf20Sopenharmony_ci struct goodix_ts_data *ts = i2c_get_clientdata(client); 13578c2ecf20Sopenharmony_ci u8 config_ver; 13588c2ecf20Sopenharmony_ci int error; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { 13618c2ecf20Sopenharmony_ci enable_irq(client->irq); 13628c2ecf20Sopenharmony_ci return 0; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* 13668c2ecf20Sopenharmony_ci * Exit sleep mode by outputting HIGH level to INT pin 13678c2ecf20Sopenharmony_ci * for 2ms~5ms. 13688c2ecf20Sopenharmony_ci */ 13698c2ecf20Sopenharmony_ci error = goodix_irq_direction_output(ts, 1); 13708c2ecf20Sopenharmony_ci if (error) 13718c2ecf20Sopenharmony_ci return error; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci usleep_range(2000, 5000); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci error = goodix_int_sync(ts); 13768c2ecf20Sopenharmony_ci if (error) 13778c2ecf20Sopenharmony_ci return error; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci error = goodix_i2c_read(ts->client, ts->chip->config_addr, 13808c2ecf20Sopenharmony_ci &config_ver, 1); 13818c2ecf20Sopenharmony_ci if (error) 13828c2ecf20Sopenharmony_ci dev_warn(dev, "Error reading config version: %d, resetting controller\n", 13838c2ecf20Sopenharmony_ci error); 13848c2ecf20Sopenharmony_ci else if (config_ver != ts->config[0]) 13858c2ecf20Sopenharmony_ci dev_info(dev, "Config version mismatch %d != %d, resetting controller\n", 13868c2ecf20Sopenharmony_ci config_ver, ts->config[0]); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (error != 0 || config_ver != ts->config[0]) { 13898c2ecf20Sopenharmony_ci error = goodix_reset(ts); 13908c2ecf20Sopenharmony_ci if (error) { 13918c2ecf20Sopenharmony_ci dev_err(dev, "Controller reset failed.\n"); 13928c2ecf20Sopenharmony_ci return error; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci error = goodix_send_cfg(ts, ts->config, ts->chip->config_len); 13968c2ecf20Sopenharmony_ci if (error) 13978c2ecf20Sopenharmony_ci return error; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci error = goodix_request_irq(ts); 14018c2ecf20Sopenharmony_ci if (error) 14028c2ecf20Sopenharmony_ci return error; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return 0; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic const struct i2c_device_id goodix_ts_id[] = { 14108c2ecf20Sopenharmony_ci { "GDIX1001:00", 0 }, 14118c2ecf20Sopenharmony_ci { } 14128c2ecf20Sopenharmony_ci}; 14138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, goodix_ts_id); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 14168c2ecf20Sopenharmony_cistatic const struct acpi_device_id goodix_acpi_match[] = { 14178c2ecf20Sopenharmony_ci { "GDIX1001", 0 }, 14188c2ecf20Sopenharmony_ci { "GDIX1002", 0 }, 14198c2ecf20Sopenharmony_ci { } 14208c2ecf20Sopenharmony_ci}; 14218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, goodix_acpi_match); 14228c2ecf20Sopenharmony_ci#endif 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 14258c2ecf20Sopenharmony_cistatic const struct of_device_id goodix_of_match[] = { 14268c2ecf20Sopenharmony_ci { .compatible = "goodix,gt1151" }, 14278c2ecf20Sopenharmony_ci { .compatible = "goodix,gt1158" }, 14288c2ecf20Sopenharmony_ci { .compatible = "goodix,gt5663" }, 14298c2ecf20Sopenharmony_ci { .compatible = "goodix,gt5688" }, 14308c2ecf20Sopenharmony_ci { .compatible = "goodix,gt911" }, 14318c2ecf20Sopenharmony_ci { .compatible = "goodix,gt9110" }, 14328c2ecf20Sopenharmony_ci { .compatible = "goodix,gt912" }, 14338c2ecf20Sopenharmony_ci { .compatible = "goodix,gt9147" }, 14348c2ecf20Sopenharmony_ci { .compatible = "goodix,gt917s" }, 14358c2ecf20Sopenharmony_ci { .compatible = "goodix,gt927" }, 14368c2ecf20Sopenharmony_ci { .compatible = "goodix,gt9271" }, 14378c2ecf20Sopenharmony_ci { .compatible = "goodix,gt928" }, 14388c2ecf20Sopenharmony_ci { .compatible = "goodix,gt9286" }, 14398c2ecf20Sopenharmony_ci { .compatible = "goodix,gt967" }, 14408c2ecf20Sopenharmony_ci { } 14418c2ecf20Sopenharmony_ci}; 14428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, goodix_of_match); 14438c2ecf20Sopenharmony_ci#endif 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic struct i2c_driver goodix_ts_driver = { 14468c2ecf20Sopenharmony_ci .probe = goodix_ts_probe, 14478c2ecf20Sopenharmony_ci .remove = goodix_ts_remove, 14488c2ecf20Sopenharmony_ci .id_table = goodix_ts_id, 14498c2ecf20Sopenharmony_ci .driver = { 14508c2ecf20Sopenharmony_ci .name = "Goodix-TS", 14518c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(goodix_acpi_match), 14528c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(goodix_of_match), 14538c2ecf20Sopenharmony_ci .pm = &goodix_pm_ops, 14548c2ecf20Sopenharmony_ci }, 14558c2ecf20Sopenharmony_ci}; 14568c2ecf20Sopenharmony_cimodule_i2c_driver(goodix_ts_driver); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 14598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); 14608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Goodix touchscreen driver"); 14618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1462