162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Goodix Touchscreens 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014 Red Hat Inc. 662306a36Sopenharmony_ci * Copyright (c) 2015 K. Merker <merker@debian.org> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This code is based on gt9xx.c authored by andrew@goodix.com: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * 2010 - 2012 Goodix Technology. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/dmi.h> 1662306a36Sopenharmony_ci#include <linux/firmware.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/irq.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/platform_data/x86/soc.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/acpi.h> 2462306a36Sopenharmony_ci#include <linux/of.h> 2562306a36Sopenharmony_ci#include <asm/unaligned.h> 2662306a36Sopenharmony_ci#include "goodix.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define GOODIX_GPIO_INT_NAME "irq" 2962306a36Sopenharmony_ci#define GOODIX_GPIO_RST_NAME "reset" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define GOODIX_MAX_HEIGHT 4096 3262306a36Sopenharmony_ci#define GOODIX_MAX_WIDTH 4096 3362306a36Sopenharmony_ci#define GOODIX_INT_TRIGGER 1 3462306a36Sopenharmony_ci#define GOODIX_CONTACT_SIZE 8 3562306a36Sopenharmony_ci#define GOODIX_MAX_CONTACT_SIZE 9 3662306a36Sopenharmony_ci#define GOODIX_MAX_CONTACTS 10 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define GOODIX_CONFIG_MIN_LENGTH 186 3962306a36Sopenharmony_ci#define GOODIX_CONFIG_911_LENGTH 186 4062306a36Sopenharmony_ci#define GOODIX_CONFIG_967_LENGTH 228 4162306a36Sopenharmony_ci#define GOODIX_CONFIG_GT9X_LENGTH 240 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define GOODIX_BUFFER_STATUS_READY BIT(7) 4462306a36Sopenharmony_ci#define GOODIX_HAVE_KEY BIT(4) 4562306a36Sopenharmony_ci#define GOODIX_BUFFER_STATUS_TIMEOUT 20 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define RESOLUTION_LOC 1 4862306a36Sopenharmony_ci#define MAX_CONTACTS_LOC 5 4962306a36Sopenharmony_ci#define TRIGGER_LOC 6 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* Our special handling for GPIO accesses through ACPI is x86 specific */ 5262306a36Sopenharmony_ci#if defined CONFIG_X86 && defined CONFIG_ACPI 5362306a36Sopenharmony_ci#define ACPI_GPIO_SUPPORT 5462306a36Sopenharmony_ci#endif 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct goodix_chip_id { 5762306a36Sopenharmony_ci const char *id; 5862306a36Sopenharmony_ci const struct goodix_chip_data *data; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts, 6262306a36Sopenharmony_ci const u8 *cfg, int len); 6362306a36Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts, 6462306a36Sopenharmony_ci const u8 *cfg, int len); 6562306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts); 6662306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic const struct goodix_chip_data gt1x_chip_data = { 6962306a36Sopenharmony_ci .config_addr = GOODIX_GT1X_REG_CONFIG_DATA, 7062306a36Sopenharmony_ci .config_len = GOODIX_CONFIG_GT9X_LENGTH, 7162306a36Sopenharmony_ci .check_config = goodix_check_cfg_16, 7262306a36Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_16, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const struct goodix_chip_data gt911_chip_data = { 7662306a36Sopenharmony_ci .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, 7762306a36Sopenharmony_ci .config_len = GOODIX_CONFIG_911_LENGTH, 7862306a36Sopenharmony_ci .check_config = goodix_check_cfg_8, 7962306a36Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_8, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic const struct goodix_chip_data gt967_chip_data = { 8362306a36Sopenharmony_ci .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, 8462306a36Sopenharmony_ci .config_len = GOODIX_CONFIG_967_LENGTH, 8562306a36Sopenharmony_ci .check_config = goodix_check_cfg_8, 8662306a36Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_8, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct goodix_chip_data gt9x_chip_data = { 9062306a36Sopenharmony_ci .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, 9162306a36Sopenharmony_ci .config_len = GOODIX_CONFIG_GT9X_LENGTH, 9262306a36Sopenharmony_ci .check_config = goodix_check_cfg_8, 9362306a36Sopenharmony_ci .calc_config_checksum = goodix_calc_cfg_checksum_8, 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic const struct goodix_chip_id goodix_chip_ids[] = { 9762306a36Sopenharmony_ci { .id = "1151", .data = >1x_chip_data }, 9862306a36Sopenharmony_ci { .id = "1158", .data = >1x_chip_data }, 9962306a36Sopenharmony_ci { .id = "5663", .data = >1x_chip_data }, 10062306a36Sopenharmony_ci { .id = "5688", .data = >1x_chip_data }, 10162306a36Sopenharmony_ci { .id = "917S", .data = >1x_chip_data }, 10262306a36Sopenharmony_ci { .id = "9286", .data = >1x_chip_data }, 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci { .id = "911", .data = >911_chip_data }, 10562306a36Sopenharmony_ci { .id = "9271", .data = >911_chip_data }, 10662306a36Sopenharmony_ci { .id = "9110", .data = >911_chip_data }, 10762306a36Sopenharmony_ci { .id = "9111", .data = >911_chip_data }, 10862306a36Sopenharmony_ci { .id = "927", .data = >911_chip_data }, 10962306a36Sopenharmony_ci { .id = "928", .data = >911_chip_data }, 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci { .id = "912", .data = >967_chip_data }, 11262306a36Sopenharmony_ci { .id = "9147", .data = >967_chip_data }, 11362306a36Sopenharmony_ci { .id = "967", .data = >967_chip_data }, 11462306a36Sopenharmony_ci { } 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic const unsigned long goodix_irq_flags[] = { 11862306a36Sopenharmony_ci IRQ_TYPE_EDGE_RISING, 11962306a36Sopenharmony_ci IRQ_TYPE_EDGE_FALLING, 12062306a36Sopenharmony_ci IRQ_TYPE_LEVEL_LOW, 12162306a36Sopenharmony_ci IRQ_TYPE_LEVEL_HIGH, 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic const struct dmi_system_id nine_bytes_report[] = { 12562306a36Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86) 12662306a36Sopenharmony_ci { 12762306a36Sopenharmony_ci /* Lenovo Yoga Book X90F / X90L */ 12862306a36Sopenharmony_ci .matches = { 12962306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 13062306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), 13162306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci }, 13462306a36Sopenharmony_ci { 13562306a36Sopenharmony_ci /* Lenovo Yoga Book X91F / X91L */ 13662306a36Sopenharmony_ci .matches = { 13762306a36Sopenharmony_ci /* Non exact match to match F + L versions */ 13862306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci#endif 14262306a36Sopenharmony_ci {} 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * Those tablets have their x coordinate inverted 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic const struct dmi_system_id inverted_x_screen[] = { 14962306a36Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86) 15062306a36Sopenharmony_ci { 15162306a36Sopenharmony_ci .ident = "Cube I15-TC", 15262306a36Sopenharmony_ci .matches = { 15362306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Cube"), 15462306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "I15-TC") 15562306a36Sopenharmony_ci }, 15662306a36Sopenharmony_ci }, 15762306a36Sopenharmony_ci#endif 15862306a36Sopenharmony_ci {} 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/** 16262306a36Sopenharmony_ci * goodix_i2c_read - read data from a register of the i2c slave device. 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * @client: i2c device. 16562306a36Sopenharmony_ci * @reg: the register to read from. 16662306a36Sopenharmony_ci * @buf: raw write data buffer. 16762306a36Sopenharmony_ci * @len: length of the buffer to write 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ciint goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct i2c_msg msgs[2]; 17262306a36Sopenharmony_ci __be16 wbuf = cpu_to_be16(reg); 17362306a36Sopenharmony_ci int ret; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci msgs[0].flags = 0; 17662306a36Sopenharmony_ci msgs[0].addr = client->addr; 17762306a36Sopenharmony_ci msgs[0].len = 2; 17862306a36Sopenharmony_ci msgs[0].buf = (u8 *)&wbuf; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci msgs[1].flags = I2C_M_RD; 18162306a36Sopenharmony_ci msgs[1].addr = client->addr; 18262306a36Sopenharmony_ci msgs[1].len = len; 18362306a36Sopenharmony_ci msgs[1].buf = buf; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci ret = i2c_transfer(client->adapter, msgs, 2); 18662306a36Sopenharmony_ci if (ret >= 0) 18762306a36Sopenharmony_ci ret = (ret == ARRAY_SIZE(msgs) ? 0 : -EIO); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (ret) 19062306a36Sopenharmony_ci dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d\n", 19162306a36Sopenharmony_ci len, reg, ret); 19262306a36Sopenharmony_ci return ret; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/** 19662306a36Sopenharmony_ci * goodix_i2c_write - write data to a register of the i2c slave device. 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * @client: i2c device. 19962306a36Sopenharmony_ci * @reg: the register to write to. 20062306a36Sopenharmony_ci * @buf: raw data buffer to write. 20162306a36Sopenharmony_ci * @len: length of the buffer to write 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ciint goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci u8 *addr_buf; 20662306a36Sopenharmony_ci struct i2c_msg msg; 20762306a36Sopenharmony_ci int ret; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci addr_buf = kmalloc(len + 2, GFP_KERNEL); 21062306a36Sopenharmony_ci if (!addr_buf) 21162306a36Sopenharmony_ci return -ENOMEM; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci addr_buf[0] = reg >> 8; 21462306a36Sopenharmony_ci addr_buf[1] = reg & 0xFF; 21562306a36Sopenharmony_ci memcpy(&addr_buf[2], buf, len); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci msg.flags = 0; 21862306a36Sopenharmony_ci msg.addr = client->addr; 21962306a36Sopenharmony_ci msg.buf = addr_buf; 22062306a36Sopenharmony_ci msg.len = len + 2; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci ret = i2c_transfer(client->adapter, &msg, 1); 22362306a36Sopenharmony_ci if (ret >= 0) 22462306a36Sopenharmony_ci ret = (ret == 1 ? 0 : -EIO); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci kfree(addr_buf); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (ret) 22962306a36Sopenharmony_ci dev_err(&client->dev, "Error writing %d bytes to 0x%04x: %d\n", 23062306a36Sopenharmony_ci len, reg, ret); 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciint goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return goodix_i2c_write(client, reg, &value, sizeof(value)); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic const struct goodix_chip_data *goodix_get_chip_data(const char *id) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci unsigned int i; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (i = 0; goodix_chip_ids[i].id; i++) { 24462306a36Sopenharmony_ci if (!strcmp(goodix_chip_ids[i].id, id)) 24562306a36Sopenharmony_ci return goodix_chip_ids[i].data; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return >9x_chip_data; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci unsigned long max_timeout; 25462306a36Sopenharmony_ci int touch_num; 25562306a36Sopenharmony_ci int error; 25662306a36Sopenharmony_ci u16 addr = GOODIX_READ_COOR_ADDR; 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * We are going to read 1-byte header, 25962306a36Sopenharmony_ci * ts->contact_size * max(1, touch_num) bytes of coordinates 26062306a36Sopenharmony_ci * and 1-byte footer which contains the touch-key code. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci const int header_contact_keycode_size = 1 + ts->contact_size + 1; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* 26562306a36Sopenharmony_ci * The 'buffer status' bit, which indicates that the data is valid, is 26662306a36Sopenharmony_ci * not set as soon as the interrupt is raised, but slightly after. 26762306a36Sopenharmony_ci * This takes around 10 ms to happen, so we poll for 20 ms. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT); 27062306a36Sopenharmony_ci do { 27162306a36Sopenharmony_ci error = goodix_i2c_read(ts->client, addr, data, 27262306a36Sopenharmony_ci header_contact_keycode_size); 27362306a36Sopenharmony_ci if (error) 27462306a36Sopenharmony_ci return error; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (data[0] & GOODIX_BUFFER_STATUS_READY) { 27762306a36Sopenharmony_ci touch_num = data[0] & 0x0f; 27862306a36Sopenharmony_ci if (touch_num > ts->max_touch_num) 27962306a36Sopenharmony_ci return -EPROTO; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (touch_num > 1) { 28262306a36Sopenharmony_ci addr += header_contact_keycode_size; 28362306a36Sopenharmony_ci data += header_contact_keycode_size; 28462306a36Sopenharmony_ci error = goodix_i2c_read(ts->client, 28562306a36Sopenharmony_ci addr, data, 28662306a36Sopenharmony_ci ts->contact_size * 28762306a36Sopenharmony_ci (touch_num - 1)); 28862306a36Sopenharmony_ci if (error) 28962306a36Sopenharmony_ci return error; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return touch_num; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (data[0] == 0 && ts->firmware_name) { 29662306a36Sopenharmony_ci if (goodix_handle_fw_request(ts)) 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci usleep_range(1000, 2000); /* Poll every 1 - 2 ms */ 30162306a36Sopenharmony_ci } while (time_before(jiffies, max_timeout)); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* 30462306a36Sopenharmony_ci * The Goodix panel will send spurious interrupts after a 30562306a36Sopenharmony_ci * 'finger up' event, which will always cause a timeout. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci return -ENOMSG; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int goodix_create_pen_input(struct goodix_ts_data *ts) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct device *dev = &ts->client->dev; 31362306a36Sopenharmony_ci struct input_dev *input; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci input = devm_input_allocate_device(dev); 31662306a36Sopenharmony_ci if (!input) 31762306a36Sopenharmony_ci return -ENOMEM; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci input_copy_abs(input, ABS_X, ts->input_dev, ABS_MT_POSITION_X); 32062306a36Sopenharmony_ci input_copy_abs(input, ABS_Y, ts->input_dev, ABS_MT_POSITION_Y); 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * The resolution of these touchscreens is about 10 units/mm, the actual 32362306a36Sopenharmony_ci * resolution does not matter much since we set INPUT_PROP_DIRECT. 32462306a36Sopenharmony_ci * Userspace wants something here though, so just set it to 10 units/mm. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci input_abs_set_res(input, ABS_X, 10); 32762306a36Sopenharmony_ci input_abs_set_res(input, ABS_Y, 10); 32862306a36Sopenharmony_ci input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci input_set_capability(input, EV_KEY, BTN_TOUCH); 33162306a36Sopenharmony_ci input_set_capability(input, EV_KEY, BTN_TOOL_PEN); 33262306a36Sopenharmony_ci input_set_capability(input, EV_KEY, BTN_STYLUS); 33362306a36Sopenharmony_ci input_set_capability(input, EV_KEY, BTN_STYLUS2); 33462306a36Sopenharmony_ci __set_bit(INPUT_PROP_DIRECT, input->propbit); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci input->name = "Goodix Active Pen"; 33762306a36Sopenharmony_ci input->phys = "input/pen"; 33862306a36Sopenharmony_ci input->id.bustype = BUS_I2C; 33962306a36Sopenharmony_ci input->id.vendor = 0x0416; 34062306a36Sopenharmony_ci if (kstrtou16(ts->id, 10, &input->id.product)) 34162306a36Sopenharmony_ci input->id.product = 0x1001; 34262306a36Sopenharmony_ci input->id.version = ts->version; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ts->input_pen = input; 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic void goodix_ts_report_pen_down(struct goodix_ts_data *ts, u8 *data) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int input_x, input_y, input_w, error; 35162306a36Sopenharmony_ci u8 key_value; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (!ts->pen_input_registered) { 35462306a36Sopenharmony_ci error = input_register_device(ts->input_pen); 35562306a36Sopenharmony_ci ts->pen_input_registered = (error == 0) ? 1 : error; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (ts->pen_input_registered < 0) 35962306a36Sopenharmony_ci return; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (ts->contact_size == 9) { 36262306a36Sopenharmony_ci input_x = get_unaligned_le16(&data[4]); 36362306a36Sopenharmony_ci input_y = get_unaligned_le16(&data[6]); 36462306a36Sopenharmony_ci input_w = get_unaligned_le16(&data[8]); 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci input_x = get_unaligned_le16(&data[2]); 36762306a36Sopenharmony_ci input_y = get_unaligned_le16(&data[4]); 36862306a36Sopenharmony_ci input_w = get_unaligned_le16(&data[6]); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci touchscreen_report_pos(ts->input_pen, &ts->prop, input_x, input_y, false); 37262306a36Sopenharmony_ci input_report_abs(ts->input_pen, ABS_PRESSURE, input_w); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_TOUCH, 1); 37562306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_TOOL_PEN, 1); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (data[0] & GOODIX_HAVE_KEY) { 37862306a36Sopenharmony_ci key_value = data[1 + ts->contact_size]; 37962306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_STYLUS, key_value & 0x10); 38062306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_STYLUS2, key_value & 0x20); 38162306a36Sopenharmony_ci } else { 38262306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_STYLUS, 0); 38362306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_STYLUS2, 0); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci input_sync(ts->input_pen); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic void goodix_ts_report_pen_up(struct goodix_ts_data *ts) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci if (!ts->input_pen) 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_TOUCH, 0); 39562306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_TOOL_PEN, 0); 39662306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_STYLUS, 0); 39762306a36Sopenharmony_ci input_report_key(ts->input_pen, BTN_STYLUS2, 0); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci input_sync(ts->input_pen); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci int id = coor_data[0] & 0x0F; 40562306a36Sopenharmony_ci int input_x = get_unaligned_le16(&coor_data[1]); 40662306a36Sopenharmony_ci int input_y = get_unaligned_le16(&coor_data[3]); 40762306a36Sopenharmony_ci int input_w = get_unaligned_le16(&coor_data[5]); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci input_mt_slot(ts->input_dev, id); 41062306a36Sopenharmony_ci input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); 41162306a36Sopenharmony_ci touchscreen_report_pos(ts->input_dev, &ts->prop, 41262306a36Sopenharmony_ci input_x, input_y, true); 41362306a36Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); 41462306a36Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int id = coor_data[1] & 0x0F; 42062306a36Sopenharmony_ci int input_x = get_unaligned_le16(&coor_data[3]); 42162306a36Sopenharmony_ci int input_y = get_unaligned_le16(&coor_data[5]); 42262306a36Sopenharmony_ci int input_w = get_unaligned_le16(&coor_data[7]); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci input_mt_slot(ts->input_dev, id); 42562306a36Sopenharmony_ci input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); 42662306a36Sopenharmony_ci touchscreen_report_pos(ts->input_dev, &ts->prop, 42762306a36Sopenharmony_ci input_x, input_y, true); 42862306a36Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); 42962306a36Sopenharmony_ci input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic void goodix_ts_release_keys(struct goodix_ts_data *ts) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci int i; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci for (i = 0; i < GOODIX_MAX_KEYS; i++) 43762306a36Sopenharmony_ci input_report_key(ts->input_dev, ts->keymap[i], 0); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci int touch_num; 44362306a36Sopenharmony_ci u8 key_value; 44462306a36Sopenharmony_ci int i; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (data[0] & GOODIX_HAVE_KEY) { 44762306a36Sopenharmony_ci touch_num = data[0] & 0x0f; 44862306a36Sopenharmony_ci key_value = data[1 + ts->contact_size * touch_num]; 44962306a36Sopenharmony_ci for (i = 0; i < GOODIX_MAX_KEYS; i++) 45062306a36Sopenharmony_ci if (key_value & BIT(i)) 45162306a36Sopenharmony_ci input_report_key(ts->input_dev, 45262306a36Sopenharmony_ci ts->keymap[i], 1); 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci goodix_ts_release_keys(ts); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/** 45962306a36Sopenharmony_ci * goodix_process_events - Process incoming events 46062306a36Sopenharmony_ci * 46162306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci * Called when the IRQ is triggered. Read the current device state, and push 46462306a36Sopenharmony_ci * the input events to the user space. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_cistatic void goodix_process_events(struct goodix_ts_data *ts) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci u8 point_data[2 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; 46962306a36Sopenharmony_ci int touch_num; 47062306a36Sopenharmony_ci int i; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci touch_num = goodix_ts_read_input_report(ts, point_data); 47362306a36Sopenharmony_ci if (touch_num < 0) 47462306a36Sopenharmony_ci return; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* The pen being down is always reported as a single touch */ 47762306a36Sopenharmony_ci if (touch_num == 1 && (point_data[1] & 0x80)) { 47862306a36Sopenharmony_ci goodix_ts_report_pen_down(ts, point_data); 47962306a36Sopenharmony_ci goodix_ts_release_keys(ts); 48062306a36Sopenharmony_ci goto sync; /* Release any previously registered touches */ 48162306a36Sopenharmony_ci } else { 48262306a36Sopenharmony_ci goodix_ts_report_pen_up(ts); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci goodix_ts_report_key(ts, point_data); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci for (i = 0; i < touch_num; i++) 48862306a36Sopenharmony_ci if (ts->contact_size == 9) 48962306a36Sopenharmony_ci goodix_ts_report_touch_9b(ts, 49062306a36Sopenharmony_ci &point_data[1 + ts->contact_size * i]); 49162306a36Sopenharmony_ci else 49262306a36Sopenharmony_ci goodix_ts_report_touch_8b(ts, 49362306a36Sopenharmony_ci &point_data[1 + ts->contact_size * i]); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cisync: 49662306a36Sopenharmony_ci input_mt_sync_frame(ts->input_dev); 49762306a36Sopenharmony_ci input_sync(ts->input_dev); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/** 50162306a36Sopenharmony_ci * goodix_ts_irq_handler - The IRQ handler 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci * @irq: interrupt number. 50462306a36Sopenharmony_ci * @dev_id: private data pointer. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistatic irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct goodix_ts_data *ts = dev_id; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci goodix_process_events(ts); 51162306a36Sopenharmony_ci goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return IRQ_HANDLED; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic void goodix_free_irq(struct goodix_ts_data *ts) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci devm_free_irq(&ts->client->dev, ts->client->irq, ts); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int goodix_request_irq(struct goodix_ts_data *ts) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, 52462306a36Sopenharmony_ci NULL, goodix_ts_irq_handler, 52562306a36Sopenharmony_ci ts->irq_flags, ts->client->name, ts); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci int i, raw_cfg_len = len - 2; 53162306a36Sopenharmony_ci u8 check_sum = 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci for (i = 0; i < raw_cfg_len; i++) 53462306a36Sopenharmony_ci check_sum += cfg[i]; 53562306a36Sopenharmony_ci check_sum = (~check_sum) + 1; 53662306a36Sopenharmony_ci if (check_sum != cfg[raw_cfg_len]) { 53762306a36Sopenharmony_ci dev_err(&ts->client->dev, 53862306a36Sopenharmony_ci "The checksum of the config fw is not correct"); 53962306a36Sopenharmony_ci return -EINVAL; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (cfg[raw_cfg_len + 1] != 1) { 54362306a36Sopenharmony_ci dev_err(&ts->client->dev, 54462306a36Sopenharmony_ci "Config fw must have Config_Fresh register set"); 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci int i, raw_cfg_len = ts->chip->config_len - 2; 55462306a36Sopenharmony_ci u8 check_sum = 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci for (i = 0; i < raw_cfg_len; i++) 55762306a36Sopenharmony_ci check_sum += ts->config[i]; 55862306a36Sopenharmony_ci check_sum = (~check_sum) + 1; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci ts->config[raw_cfg_len] = check_sum; 56162306a36Sopenharmony_ci ts->config[raw_cfg_len + 1] = 1; /* Set "config_fresh" bit */ 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts, const u8 *cfg, 56562306a36Sopenharmony_ci int len) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int i, raw_cfg_len = len - 3; 56862306a36Sopenharmony_ci u16 check_sum = 0; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci for (i = 0; i < raw_cfg_len; i += 2) 57162306a36Sopenharmony_ci check_sum += get_unaligned_be16(&cfg[i]); 57262306a36Sopenharmony_ci check_sum = (~check_sum) + 1; 57362306a36Sopenharmony_ci if (check_sum != get_unaligned_be16(&cfg[raw_cfg_len])) { 57462306a36Sopenharmony_ci dev_err(&ts->client->dev, 57562306a36Sopenharmony_ci "The checksum of the config fw is not correct"); 57662306a36Sopenharmony_ci return -EINVAL; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (cfg[raw_cfg_len + 2] != 1) { 58062306a36Sopenharmony_ci dev_err(&ts->client->dev, 58162306a36Sopenharmony_ci "Config fw must have Config_Fresh register set"); 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci int i, raw_cfg_len = ts->chip->config_len - 3; 59162306a36Sopenharmony_ci u16 check_sum = 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci for (i = 0; i < raw_cfg_len; i += 2) 59462306a36Sopenharmony_ci check_sum += get_unaligned_be16(&ts->config[i]); 59562306a36Sopenharmony_ci check_sum = (~check_sum) + 1; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci put_unaligned_be16(check_sum, &ts->config[raw_cfg_len]); 59862306a36Sopenharmony_ci ts->config[raw_cfg_len + 2] = 1; /* Set "config_fresh" bit */ 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/** 60262306a36Sopenharmony_ci * goodix_check_cfg - Checks if config fw is valid 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * @ts: goodix_ts_data pointer 60562306a36Sopenharmony_ci * @cfg: firmware config data 60662306a36Sopenharmony_ci * @len: config data length 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_cistatic int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci if (len < GOODIX_CONFIG_MIN_LENGTH || 61162306a36Sopenharmony_ci len > GOODIX_CONFIG_MAX_LENGTH) { 61262306a36Sopenharmony_ci dev_err(&ts->client->dev, 61362306a36Sopenharmony_ci "The length of the config fw is not correct"); 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return ts->chip->check_config(ts, cfg, len); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/** 62162306a36Sopenharmony_ci * goodix_send_cfg - Write fw config to device 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * @ts: goodix_ts_data pointer 62462306a36Sopenharmony_ci * @cfg: config firmware to write to device 62562306a36Sopenharmony_ci * @len: config data length 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ciint goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int error; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci error = goodix_check_cfg(ts, cfg, len); 63262306a36Sopenharmony_ci if (error) 63362306a36Sopenharmony_ci return error; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len); 63662306a36Sopenharmony_ci if (error) 63762306a36Sopenharmony_ci return error; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci dev_dbg(&ts->client->dev, "Config sent successfully."); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Let the firmware reconfigure itself, so sleep for 10ms */ 64262306a36Sopenharmony_ci usleep_range(10000, 11000); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT 64862306a36Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(&ts->client->dev); 65162306a36Sopenharmony_ci acpi_status status; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci status = acpi_evaluate_object(handle, "INTI", NULL, NULL); 65462306a36Sopenharmony_ci return ACPI_SUCCESS(status) ? 0 : -EIO; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(&ts->client->dev); 66062306a36Sopenharmony_ci acpi_status status; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci status = acpi_execute_simple_method(handle, "INTO", value); 66362306a36Sopenharmony_ci return ACPI_SUCCESS(status) ? 0 : -EIO; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci#else 66662306a36Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci dev_err(&ts->client->dev, 66962306a36Sopenharmony_ci "%s called on device without ACPI support\n", __func__); 67062306a36Sopenharmony_ci return -EINVAL; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci dev_err(&ts->client->dev, 67662306a36Sopenharmony_ci "%s called on device without ACPI support\n", __func__); 67762306a36Sopenharmony_ci return -EINVAL; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci#endif 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic int goodix_irq_direction_output(struct goodix_ts_data *ts, int value) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci switch (ts->irq_pin_access_method) { 68462306a36Sopenharmony_ci case IRQ_PIN_ACCESS_NONE: 68562306a36Sopenharmony_ci dev_err(&ts->client->dev, 68662306a36Sopenharmony_ci "%s called without an irq_pin_access_method set\n", 68762306a36Sopenharmony_ci __func__); 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci case IRQ_PIN_ACCESS_GPIO: 69062306a36Sopenharmony_ci return gpiod_direction_output(ts->gpiod_int, value); 69162306a36Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_GPIO: 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * The IRQ pin triggers on a falling edge, so its gets marked 69462306a36Sopenharmony_ci * as active-low, use output_raw to avoid the value inversion. 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_ci return gpiod_direction_output_raw(ts->gpiod_int, value); 69762306a36Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_METHOD: 69862306a36Sopenharmony_ci return goodix_pin_acpi_output_method(ts, value); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return -EINVAL; /* Never reached */ 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int goodix_irq_direction_input(struct goodix_ts_data *ts) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci switch (ts->irq_pin_access_method) { 70762306a36Sopenharmony_ci case IRQ_PIN_ACCESS_NONE: 70862306a36Sopenharmony_ci dev_err(&ts->client->dev, 70962306a36Sopenharmony_ci "%s called without an irq_pin_access_method set\n", 71062306a36Sopenharmony_ci __func__); 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci case IRQ_PIN_ACCESS_GPIO: 71362306a36Sopenharmony_ci return gpiod_direction_input(ts->gpiod_int); 71462306a36Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_GPIO: 71562306a36Sopenharmony_ci return gpiod_direction_input(ts->gpiod_int); 71662306a36Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_METHOD: 71762306a36Sopenharmony_ci return goodix_pin_acpi_direction_input(ts); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return -EINVAL; /* Never reached */ 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ciint goodix_int_sync(struct goodix_ts_data *ts) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci int error; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci error = goodix_irq_direction_output(ts, 0); 72862306a36Sopenharmony_ci if (error) 72962306a36Sopenharmony_ci goto error; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci msleep(50); /* T5: 50ms */ 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci error = goodix_irq_direction_input(ts); 73462306a36Sopenharmony_ci if (error) 73562306a36Sopenharmony_ci goto error; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return 0; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cierror: 74062306a36Sopenharmony_ci dev_err(&ts->client->dev, "Controller irq sync failed.\n"); 74162306a36Sopenharmony_ci return error; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci/** 74562306a36Sopenharmony_ci * goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode 74662306a36Sopenharmony_ci * 74762306a36Sopenharmony_ci * @ts: goodix_ts_data pointer 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ciint goodix_reset_no_int_sync(struct goodix_ts_data *ts) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci int error; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* begin select I2C slave addr */ 75462306a36Sopenharmony_ci error = gpiod_direction_output(ts->gpiod_rst, 0); 75562306a36Sopenharmony_ci if (error) 75662306a36Sopenharmony_ci goto error; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci msleep(20); /* T2: > 10ms */ 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ 76162306a36Sopenharmony_ci error = goodix_irq_direction_output(ts, ts->client->addr == 0x14); 76262306a36Sopenharmony_ci if (error) 76362306a36Sopenharmony_ci goto error; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci usleep_range(100, 2000); /* T3: > 100us */ 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci error = gpiod_direction_output(ts->gpiod_rst, 1); 76862306a36Sopenharmony_ci if (error) 76962306a36Sopenharmony_ci goto error; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci usleep_range(6000, 10000); /* T4: > 5ms */ 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* 77462306a36Sopenharmony_ci * Put the reset pin back in to input / high-impedance mode to save 77562306a36Sopenharmony_ci * power. Only do this in the non ACPI case since some ACPI boards 77662306a36Sopenharmony_ci * don't have a pull-up, so there the reset pin must stay active-high. 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_ci if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) { 77962306a36Sopenharmony_ci error = gpiod_direction_input(ts->gpiod_rst); 78062306a36Sopenharmony_ci if (error) 78162306a36Sopenharmony_ci goto error; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cierror: 78762306a36Sopenharmony_ci dev_err(&ts->client->dev, "Controller reset failed.\n"); 78862306a36Sopenharmony_ci return error; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci/** 79262306a36Sopenharmony_ci * goodix_reset - Reset device during power on 79362306a36Sopenharmony_ci * 79462306a36Sopenharmony_ci * @ts: goodix_ts_data pointer 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_cistatic int goodix_reset(struct goodix_ts_data *ts) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci int error; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci error = goodix_reset_no_int_sync(ts); 80162306a36Sopenharmony_ci if (error) 80262306a36Sopenharmony_ci return error; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return goodix_int_sync(ts); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT 80862306a36Sopenharmony_cistatic const struct acpi_gpio_params first_gpio = { 0, 0, false }; 80962306a36Sopenharmony_cistatic const struct acpi_gpio_params second_gpio = { 1, 0, false }; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_first_gpios[] = { 81262306a36Sopenharmony_ci { GOODIX_GPIO_INT_NAME "-gpios", &first_gpio, 1 }, 81362306a36Sopenharmony_ci { GOODIX_GPIO_RST_NAME "-gpios", &second_gpio, 1 }, 81462306a36Sopenharmony_ci { }, 81562306a36Sopenharmony_ci}; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_last_gpios[] = { 81862306a36Sopenharmony_ci { GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 }, 81962306a36Sopenharmony_ci { GOODIX_GPIO_INT_NAME "-gpios", &second_gpio, 1 }, 82062306a36Sopenharmony_ci { }, 82162306a36Sopenharmony_ci}; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_reset_only_gpios[] = { 82462306a36Sopenharmony_ci { GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 }, 82562306a36Sopenharmony_ci { }, 82662306a36Sopenharmony_ci}; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic int goodix_resource(struct acpi_resource *ares, void *data) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct goodix_ts_data *ts = data; 83162306a36Sopenharmony_ci struct device *dev = &ts->client->dev; 83262306a36Sopenharmony_ci struct acpi_resource_gpio *gpio; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (acpi_gpio_get_irq_resource(ares, &gpio)) { 83562306a36Sopenharmony_ci if (ts->gpio_int_idx == -1) { 83662306a36Sopenharmony_ci ts->gpio_int_idx = ts->gpio_count; 83762306a36Sopenharmony_ci } else { 83862306a36Sopenharmony_ci dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n"); 83962306a36Sopenharmony_ci ts->gpio_int_idx = -2; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci ts->gpio_count++; 84262306a36Sopenharmony_ci } else if (acpi_gpio_get_io_resource(ares, &gpio)) 84362306a36Sopenharmony_ci ts->gpio_count++; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return 0; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/* 84962306a36Sopenharmony_ci * This function gets called in case we fail to get the irq GPIO directly 85062306a36Sopenharmony_ci * because the ACPI tables lack GPIO-name to APCI _CRS index mappings 85162306a36Sopenharmony_ci * (no _DSD UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 data). 85262306a36Sopenharmony_ci * In that case we add our own mapping and then goodix_get_gpio_config() 85362306a36Sopenharmony_ci * retries to get the GPIOs based on the added mapping. 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci const struct acpi_gpio_mapping *gpio_mapping = NULL; 85862306a36Sopenharmony_ci struct device *dev = &ts->client->dev; 85962306a36Sopenharmony_ci LIST_HEAD(resources); 86062306a36Sopenharmony_ci int irq, ret; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ts->gpio_count = 0; 86362306a36Sopenharmony_ci ts->gpio_int_idx = -1; 86462306a36Sopenharmony_ci ret = acpi_dev_get_resources(ACPI_COMPANION(dev), &resources, 86562306a36Sopenharmony_ci goodix_resource, ts); 86662306a36Sopenharmony_ci if (ret < 0) { 86762306a36Sopenharmony_ci dev_err(dev, "Error getting ACPI resources: %d\n", ret); 86862306a36Sopenharmony_ci return ret; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci acpi_dev_free_resource_list(&resources); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* 87462306a36Sopenharmony_ci * CHT devices should have a GpioInt + a regular GPIO ACPI resource. 87562306a36Sopenharmony_ci * Some CHT devices have a bug (where the also is bogus Interrupt 87662306a36Sopenharmony_ci * resource copied from a previous BYT based generation). i2c-core-acpi 87762306a36Sopenharmony_ci * will use the non-working Interrupt resource, fix this up. 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_ci if (soc_intel_is_cht() && ts->gpio_count == 2 && ts->gpio_int_idx != -1) { 88062306a36Sopenharmony_ci irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); 88162306a36Sopenharmony_ci if (irq > 0 && irq != ts->client->irq) { 88262306a36Sopenharmony_ci dev_warn(dev, "Overriding IRQ %d -> %d\n", ts->client->irq, irq); 88362306a36Sopenharmony_ci ts->client->irq = irq; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Some devices with gpio_int_idx 0 list a third unused GPIO */ 88862306a36Sopenharmony_ci if ((ts->gpio_count == 2 || ts->gpio_count == 3) && ts->gpio_int_idx == 0) { 88962306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO; 89062306a36Sopenharmony_ci gpio_mapping = acpi_goodix_int_first_gpios; 89162306a36Sopenharmony_ci } else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) { 89262306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO; 89362306a36Sopenharmony_ci gpio_mapping = acpi_goodix_int_last_gpios; 89462306a36Sopenharmony_ci } else if (ts->gpio_count == 1 && ts->gpio_int_idx == -1 && 89562306a36Sopenharmony_ci acpi_has_method(ACPI_HANDLE(dev), "INTI") && 89662306a36Sopenharmony_ci acpi_has_method(ACPI_HANDLE(dev), "INTO")) { 89762306a36Sopenharmony_ci dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n"); 89862306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD; 89962306a36Sopenharmony_ci gpio_mapping = acpi_goodix_reset_only_gpios; 90062306a36Sopenharmony_ci } else if (soc_intel_is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) { 90162306a36Sopenharmony_ci dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n"); 90262306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO; 90362306a36Sopenharmony_ci gpio_mapping = acpi_goodix_int_last_gpios; 90462306a36Sopenharmony_ci } else if (ts->gpio_count == 1 && ts->gpio_int_idx == 0) { 90562306a36Sopenharmony_ci /* 90662306a36Sopenharmony_ci * On newer devices there is only 1 GpioInt resource and _PS0 90762306a36Sopenharmony_ci * does the whole reset sequence for us. 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_ci acpi_device_fix_up_power(ACPI_COMPANION(dev)); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* 91262306a36Sopenharmony_ci * Before the _PS0 call the int GPIO may have been in output 91362306a36Sopenharmony_ci * mode and the call should have put the int GPIO in input mode, 91462306a36Sopenharmony_ci * but the GPIO subsys cached state may still think it is 91562306a36Sopenharmony_ci * in output mode, causing gpiochip_lock_as_irq() failure. 91662306a36Sopenharmony_ci * 91762306a36Sopenharmony_ci * Add a mapping for the int GPIO to make the 91862306a36Sopenharmony_ci * gpiod_int = gpiod_get(..., GPIOD_IN) call succeed, 91962306a36Sopenharmony_ci * which will explicitly set the direction to input. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE; 92262306a36Sopenharmony_ci gpio_mapping = acpi_goodix_int_first_gpios; 92362306a36Sopenharmony_ci } else { 92462306a36Sopenharmony_ci dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n", 92562306a36Sopenharmony_ci ts->gpio_count, ts->gpio_int_idx); 92662306a36Sopenharmony_ci /* 92762306a36Sopenharmony_ci * On some devices _PS0 does a reset for us and 92862306a36Sopenharmony_ci * sometimes this is necessary for things to work. 92962306a36Sopenharmony_ci */ 93062306a36Sopenharmony_ci acpi_device_fix_up_power(ACPI_COMPANION(dev)); 93162306a36Sopenharmony_ci return -EINVAL; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci /* 93562306a36Sopenharmony_ci * Normally we put the reset pin in input / high-impedance mode to save 93662306a36Sopenharmony_ci * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI 93762306a36Sopenharmony_ci * case, leave the pin as is. This results in the pin not being touched 93862306a36Sopenharmony_ci * at all on x86/ACPI boards, except when needed for error-recover. 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci ts->gpiod_rst_flags = GPIOD_ASIS; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping); 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci#else 94562306a36Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci return -EINVAL; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci#endif /* CONFIG_X86 && CONFIG_ACPI */ 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci/** 95262306a36Sopenharmony_ci * goodix_get_gpio_config - Get GPIO config from ACPI/DT 95362306a36Sopenharmony_ci * 95462306a36Sopenharmony_ci * @ts: goodix_ts_data pointer 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_cistatic int goodix_get_gpio_config(struct goodix_ts_data *ts) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci struct device *dev; 95962306a36Sopenharmony_ci struct gpio_desc *gpiod; 96062306a36Sopenharmony_ci bool added_acpi_mappings = false; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (!ts->client) 96362306a36Sopenharmony_ci return -EINVAL; 96462306a36Sopenharmony_ci dev = &ts->client->dev; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* 96762306a36Sopenharmony_ci * By default we request the reset pin as input, leaving it in 96862306a36Sopenharmony_ci * high-impedance when not resetting the controller to save power. 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ci ts->gpiod_rst_flags = GPIOD_IN; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci ts->avdd28 = devm_regulator_get(dev, "AVDD28"); 97362306a36Sopenharmony_ci if (IS_ERR(ts->avdd28)) 97462306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n"); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci ts->vddio = devm_regulator_get(dev, "VDDIO"); 97762306a36Sopenharmony_ci if (IS_ERR(ts->vddio)) 97862306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(ts->vddio), "Failed to get VDDIO regulator\n"); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ciretry_get_irq_gpio: 98162306a36Sopenharmony_ci /* Get the interrupt GPIO pin number */ 98262306a36Sopenharmony_ci gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN); 98362306a36Sopenharmony_ci if (IS_ERR(gpiod)) 98462306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", 98562306a36Sopenharmony_ci GOODIX_GPIO_INT_NAME); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) { 98862306a36Sopenharmony_ci added_acpi_mappings = true; 98962306a36Sopenharmony_ci if (goodix_add_acpi_gpio_mappings(ts) == 0) 99062306a36Sopenharmony_ci goto retry_get_irq_gpio; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci ts->gpiod_int = gpiod; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Get the reset line GPIO pin number */ 99662306a36Sopenharmony_ci gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags); 99762306a36Sopenharmony_ci if (IS_ERR(gpiod)) 99862306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", 99962306a36Sopenharmony_ci GOODIX_GPIO_RST_NAME); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci ts->gpiod_rst = gpiod; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci switch (ts->irq_pin_access_method) { 100462306a36Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_GPIO: 100562306a36Sopenharmony_ci /* 100662306a36Sopenharmony_ci * We end up here if goodix_add_acpi_gpio_mappings() has 100762306a36Sopenharmony_ci * called devm_acpi_dev_add_driver_gpios() because the ACPI 100862306a36Sopenharmony_ci * tables did not contain name to index mappings. 100962306a36Sopenharmony_ci * Check that we successfully got both GPIOs after we've 101062306a36Sopenharmony_ci * added our own acpi_gpio_mapping and if we did not get both 101162306a36Sopenharmony_ci * GPIOs reset irq_pin_access_method to IRQ_PIN_ACCESS_NONE. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci if (!ts->gpiod_int || !ts->gpiod_rst) 101462306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE; 101562306a36Sopenharmony_ci break; 101662306a36Sopenharmony_ci case IRQ_PIN_ACCESS_ACPI_METHOD: 101762306a36Sopenharmony_ci if (!ts->gpiod_rst) 101862306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE; 101962306a36Sopenharmony_ci break; 102062306a36Sopenharmony_ci default: 102162306a36Sopenharmony_ci if (ts->gpiod_int && ts->gpiod_rst) { 102262306a36Sopenharmony_ci ts->reset_controller_at_probe = true; 102362306a36Sopenharmony_ci ts->load_cfg_from_disk = true; 102462306a36Sopenharmony_ci ts->irq_pin_access_method = IRQ_PIN_ACCESS_GPIO; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/** 103262306a36Sopenharmony_ci * goodix_read_config - Read the embedded configuration of the panel 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer 103562306a36Sopenharmony_ci * 103662306a36Sopenharmony_ci * Must be called during probe 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_cistatic void goodix_read_config(struct goodix_ts_data *ts) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci int x_max, y_max; 104162306a36Sopenharmony_ci int error; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* 104462306a36Sopenharmony_ci * On controllers where we need to upload the firmware 104562306a36Sopenharmony_ci * (controllers without flash) ts->config already has the config 104662306a36Sopenharmony_ci * at this point and the controller itself does not have it yet! 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_ci if (!ts->firmware_name) { 104962306a36Sopenharmony_ci error = goodix_i2c_read(ts->client, ts->chip->config_addr, 105062306a36Sopenharmony_ci ts->config, ts->chip->config_len); 105162306a36Sopenharmony_ci if (error) { 105262306a36Sopenharmony_ci ts->int_trigger_type = GOODIX_INT_TRIGGER; 105362306a36Sopenharmony_ci ts->max_touch_num = GOODIX_MAX_CONTACTS; 105462306a36Sopenharmony_ci return; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; 105962306a36Sopenharmony_ci ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]); 106262306a36Sopenharmony_ci y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]); 106362306a36Sopenharmony_ci if (x_max && y_max) { 106462306a36Sopenharmony_ci input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1); 106562306a36Sopenharmony_ci input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci ts->chip->calc_config_checksum(ts); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci/** 107262306a36Sopenharmony_ci * goodix_read_version - Read goodix touchscreen version 107362306a36Sopenharmony_ci * 107462306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_cistatic int goodix_read_version(struct goodix_ts_data *ts) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci int error; 107962306a36Sopenharmony_ci u8 buf[6]; 108062306a36Sopenharmony_ci char id_str[GOODIX_ID_MAX_LEN + 1]; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf)); 108362306a36Sopenharmony_ci if (error) 108462306a36Sopenharmony_ci return error; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci memcpy(id_str, buf, GOODIX_ID_MAX_LEN); 108762306a36Sopenharmony_ci id_str[GOODIX_ID_MAX_LEN] = 0; 108862306a36Sopenharmony_ci strscpy(ts->id, id_str, GOODIX_ID_MAX_LEN + 1); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci ts->version = get_unaligned_le16(&buf[4]); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci dev_info(&ts->client->dev, "ID %s, version: %04x\n", ts->id, 109362306a36Sopenharmony_ci ts->version); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return 0; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci/** 109962306a36Sopenharmony_ci * goodix_i2c_test - I2C test function to check if the device answers. 110062306a36Sopenharmony_ci * 110162306a36Sopenharmony_ci * @client: the i2c client 110262306a36Sopenharmony_ci */ 110362306a36Sopenharmony_cistatic int goodix_i2c_test(struct i2c_client *client) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci int retry = 0; 110662306a36Sopenharmony_ci int error; 110762306a36Sopenharmony_ci u8 test; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci while (retry++ < 2) { 111062306a36Sopenharmony_ci error = goodix_i2c_read(client, GOODIX_REG_ID, &test, 1); 111162306a36Sopenharmony_ci if (!error) 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci msleep(20); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci return error; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci/** 112162306a36Sopenharmony_ci * goodix_configure_dev - Finish device initialization 112262306a36Sopenharmony_ci * 112362306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer 112462306a36Sopenharmony_ci * 112562306a36Sopenharmony_ci * Must be called from probe to finish initialization of the device. 112662306a36Sopenharmony_ci * Contains the common initialization code for both devices that 112762306a36Sopenharmony_ci * declare gpio pins and devices that do not. It is either called 112862306a36Sopenharmony_ci * directly from probe or from request_firmware_wait callback. 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_cistatic int goodix_configure_dev(struct goodix_ts_data *ts) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci int error; 113362306a36Sopenharmony_ci int i; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci ts->int_trigger_type = GOODIX_INT_TRIGGER; 113662306a36Sopenharmony_ci ts->max_touch_num = GOODIX_MAX_CONTACTS; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ts->input_dev = devm_input_allocate_device(&ts->client->dev); 113962306a36Sopenharmony_ci if (!ts->input_dev) { 114062306a36Sopenharmony_ci dev_err(&ts->client->dev, "Failed to allocate input device."); 114162306a36Sopenharmony_ci return -ENOMEM; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci ts->input_dev->name = "Goodix Capacitive TouchScreen"; 114562306a36Sopenharmony_ci ts->input_dev->phys = "input/ts"; 114662306a36Sopenharmony_ci ts->input_dev->id.bustype = BUS_I2C; 114762306a36Sopenharmony_ci ts->input_dev->id.vendor = 0x0416; 114862306a36Sopenharmony_ci if (kstrtou16(ts->id, 10, &ts->input_dev->id.product)) 114962306a36Sopenharmony_ci ts->input_dev->id.product = 0x1001; 115062306a36Sopenharmony_ci ts->input_dev->id.version = ts->version; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci ts->input_dev->keycode = ts->keymap; 115362306a36Sopenharmony_ci ts->input_dev->keycodesize = sizeof(ts->keymap[0]); 115462306a36Sopenharmony_ci ts->input_dev->keycodemax = GOODIX_MAX_KEYS; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* Capacitive Windows/Home button on some devices */ 115762306a36Sopenharmony_ci for (i = 0; i < GOODIX_MAX_KEYS; ++i) { 115862306a36Sopenharmony_ci if (i == 0) 115962306a36Sopenharmony_ci ts->keymap[i] = KEY_LEFTMETA; 116062306a36Sopenharmony_ci else 116162306a36Sopenharmony_ci ts->keymap[i] = KEY_F1 + (i - 1); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci input_set_capability(ts->input_dev, EV_KEY, ts->keymap[i]); 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X); 116762306a36Sopenharmony_ci input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y); 116862306a36Sopenharmony_ci input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); 116962306a36Sopenharmony_ci input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ciretry_read_config: 117262306a36Sopenharmony_ci /* Read configuration and apply touchscreen parameters */ 117362306a36Sopenharmony_ci goodix_read_config(ts); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* Try overriding touchscreen parameters via device properties */ 117662306a36Sopenharmony_ci touchscreen_parse_properties(ts->input_dev, true, &ts->prop); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) { 117962306a36Sopenharmony_ci if (!ts->reset_controller_at_probe && 118062306a36Sopenharmony_ci ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) { 118162306a36Sopenharmony_ci dev_info(&ts->client->dev, "Config not set, resetting controller\n"); 118262306a36Sopenharmony_ci /* Retry after a controller reset */ 118362306a36Sopenharmony_ci ts->reset_controller_at_probe = true; 118462306a36Sopenharmony_ci error = goodix_reset(ts); 118562306a36Sopenharmony_ci if (error) 118662306a36Sopenharmony_ci return error; 118762306a36Sopenharmony_ci goto retry_read_config; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci dev_err(&ts->client->dev, 119062306a36Sopenharmony_ci "Invalid config (%d, %d, %d), using defaults\n", 119162306a36Sopenharmony_ci ts->prop.max_x, ts->prop.max_y, ts->max_touch_num); 119262306a36Sopenharmony_ci ts->prop.max_x = GOODIX_MAX_WIDTH - 1; 119362306a36Sopenharmony_ci ts->prop.max_y = GOODIX_MAX_HEIGHT - 1; 119462306a36Sopenharmony_ci ts->max_touch_num = GOODIX_MAX_CONTACTS; 119562306a36Sopenharmony_ci input_abs_set_max(ts->input_dev, 119662306a36Sopenharmony_ci ABS_MT_POSITION_X, ts->prop.max_x); 119762306a36Sopenharmony_ci input_abs_set_max(ts->input_dev, 119862306a36Sopenharmony_ci ABS_MT_POSITION_Y, ts->prop.max_y); 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (dmi_check_system(nine_bytes_report)) { 120262306a36Sopenharmony_ci ts->contact_size = 9; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci dev_dbg(&ts->client->dev, 120562306a36Sopenharmony_ci "Non-standard 9-bytes report format quirk\n"); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (dmi_check_system(inverted_x_screen)) { 120962306a36Sopenharmony_ci ts->prop.invert_x = true; 121062306a36Sopenharmony_ci dev_dbg(&ts->client->dev, 121162306a36Sopenharmony_ci "Applying 'inverted x screen' quirk\n"); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci error = input_mt_init_slots(ts->input_dev, ts->max_touch_num, 121562306a36Sopenharmony_ci INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 121662306a36Sopenharmony_ci if (error) { 121762306a36Sopenharmony_ci dev_err(&ts->client->dev, 121862306a36Sopenharmony_ci "Failed to initialize MT slots: %d", error); 121962306a36Sopenharmony_ci return error; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci error = input_register_device(ts->input_dev); 122362306a36Sopenharmony_ci if (error) { 122462306a36Sopenharmony_ci dev_err(&ts->client->dev, 122562306a36Sopenharmony_ci "Failed to register input device: %d", error); 122662306a36Sopenharmony_ci return error; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci /* 123062306a36Sopenharmony_ci * Create the input_pen device before goodix_request_irq() calls 123162306a36Sopenharmony_ci * devm_request_threaded_irq() so that the devm framework frees 123262306a36Sopenharmony_ci * it after disabling the irq. 123362306a36Sopenharmony_ci * Unfortunately there is no way to detect if the touchscreen has pen 123462306a36Sopenharmony_ci * support, so registering the dev is delayed till the first pen event. 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci error = goodix_create_pen_input(ts); 123762306a36Sopenharmony_ci if (error) 123862306a36Sopenharmony_ci return error; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; 124162306a36Sopenharmony_ci error = goodix_request_irq(ts); 124262306a36Sopenharmony_ci if (error) { 124362306a36Sopenharmony_ci dev_err(&ts->client->dev, "request IRQ failed: %d\n", error); 124462306a36Sopenharmony_ci return error; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci return 0; 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci/** 125162306a36Sopenharmony_ci * goodix_config_cb - Callback to finish device init 125262306a36Sopenharmony_ci * 125362306a36Sopenharmony_ci * @cfg: firmware config 125462306a36Sopenharmony_ci * @ctx: our goodix_ts_data pointer 125562306a36Sopenharmony_ci * 125662306a36Sopenharmony_ci * request_firmware_wait callback that finishes 125762306a36Sopenharmony_ci * initialization of the device. 125862306a36Sopenharmony_ci */ 125962306a36Sopenharmony_cistatic void goodix_config_cb(const struct firmware *cfg, void *ctx) 126062306a36Sopenharmony_ci{ 126162306a36Sopenharmony_ci struct goodix_ts_data *ts = ctx; 126262306a36Sopenharmony_ci int error; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (ts->firmware_name) { 126562306a36Sopenharmony_ci if (!cfg) 126662306a36Sopenharmony_ci goto err_release_cfg; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci error = goodix_check_cfg(ts, cfg->data, cfg->size); 126962306a36Sopenharmony_ci if (error) 127062306a36Sopenharmony_ci goto err_release_cfg; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci memcpy(ts->config, cfg->data, cfg->size); 127362306a36Sopenharmony_ci } else if (cfg) { 127462306a36Sopenharmony_ci /* send device configuration to the firmware */ 127562306a36Sopenharmony_ci error = goodix_send_cfg(ts, cfg->data, cfg->size); 127662306a36Sopenharmony_ci if (error) 127762306a36Sopenharmony_ci goto err_release_cfg; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci goodix_configure_dev(ts); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_cierr_release_cfg: 128362306a36Sopenharmony_ci release_firmware(cfg); 128462306a36Sopenharmony_ci complete_all(&ts->firmware_loading_complete); 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cistatic void goodix_disable_regulators(void *arg) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci struct goodix_ts_data *ts = arg; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci regulator_disable(ts->vddio); 129262306a36Sopenharmony_ci regulator_disable(ts->avdd28); 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic int goodix_ts_probe(struct i2c_client *client) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci struct goodix_ts_data *ts; 129862306a36Sopenharmony_ci const char *cfg_name; 129962306a36Sopenharmony_ci int error; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 130462306a36Sopenharmony_ci dev_err(&client->dev, "I2C check functionality failed.\n"); 130562306a36Sopenharmony_ci return -ENXIO; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 130962306a36Sopenharmony_ci if (!ts) 131062306a36Sopenharmony_ci return -ENOMEM; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci ts->client = client; 131362306a36Sopenharmony_ci i2c_set_clientdata(client, ts); 131462306a36Sopenharmony_ci init_completion(&ts->firmware_loading_complete); 131562306a36Sopenharmony_ci ts->contact_size = GOODIX_CONTACT_SIZE; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci error = goodix_get_gpio_config(ts); 131862306a36Sopenharmony_ci if (error) 131962306a36Sopenharmony_ci return error; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* power up the controller */ 132262306a36Sopenharmony_ci error = regulator_enable(ts->avdd28); 132362306a36Sopenharmony_ci if (error) { 132462306a36Sopenharmony_ci dev_err(&client->dev, 132562306a36Sopenharmony_ci "Failed to enable AVDD28 regulator: %d\n", 132662306a36Sopenharmony_ci error); 132762306a36Sopenharmony_ci return error; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci error = regulator_enable(ts->vddio); 133162306a36Sopenharmony_ci if (error) { 133262306a36Sopenharmony_ci dev_err(&client->dev, 133362306a36Sopenharmony_ci "Failed to enable VDDIO regulator: %d\n", 133462306a36Sopenharmony_ci error); 133562306a36Sopenharmony_ci regulator_disable(ts->avdd28); 133662306a36Sopenharmony_ci return error; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci error = devm_add_action_or_reset(&client->dev, 134062306a36Sopenharmony_ci goodix_disable_regulators, ts); 134162306a36Sopenharmony_ci if (error) 134262306a36Sopenharmony_ci return error; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cireset: 134562306a36Sopenharmony_ci if (ts->reset_controller_at_probe) { 134662306a36Sopenharmony_ci /* reset the controller */ 134762306a36Sopenharmony_ci error = goodix_reset(ts); 134862306a36Sopenharmony_ci if (error) 134962306a36Sopenharmony_ci return error; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci error = goodix_i2c_test(client); 135362306a36Sopenharmony_ci if (error) { 135462306a36Sopenharmony_ci if (!ts->reset_controller_at_probe && 135562306a36Sopenharmony_ci ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) { 135662306a36Sopenharmony_ci /* Retry after a controller reset */ 135762306a36Sopenharmony_ci ts->reset_controller_at_probe = true; 135862306a36Sopenharmony_ci goto reset; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci dev_err(&client->dev, "I2C communication failure: %d\n", error); 136162306a36Sopenharmony_ci return error; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci error = goodix_firmware_check(ts); 136562306a36Sopenharmony_ci if (error) 136662306a36Sopenharmony_ci return error; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci error = goodix_read_version(ts); 136962306a36Sopenharmony_ci if (error) 137062306a36Sopenharmony_ci return error; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci ts->chip = goodix_get_chip_data(ts->id); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (ts->load_cfg_from_disk) { 137562306a36Sopenharmony_ci /* update device config */ 137662306a36Sopenharmony_ci error = device_property_read_string(&client->dev, 137762306a36Sopenharmony_ci "goodix,config-name", 137862306a36Sopenharmony_ci &cfg_name); 137962306a36Sopenharmony_ci if (!error) 138062306a36Sopenharmony_ci snprintf(ts->cfg_name, sizeof(ts->cfg_name), 138162306a36Sopenharmony_ci "goodix/%s", cfg_name); 138262306a36Sopenharmony_ci else 138362306a36Sopenharmony_ci snprintf(ts->cfg_name, sizeof(ts->cfg_name), 138462306a36Sopenharmony_ci "goodix_%s_cfg.bin", ts->id); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name, 138762306a36Sopenharmony_ci &client->dev, GFP_KERNEL, ts, 138862306a36Sopenharmony_ci goodix_config_cb); 138962306a36Sopenharmony_ci if (error) { 139062306a36Sopenharmony_ci dev_err(&client->dev, 139162306a36Sopenharmony_ci "Failed to invoke firmware loader: %d\n", 139262306a36Sopenharmony_ci error); 139362306a36Sopenharmony_ci return error; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci return 0; 139762306a36Sopenharmony_ci } else { 139862306a36Sopenharmony_ci error = goodix_configure_dev(ts); 139962306a36Sopenharmony_ci if (error) 140062306a36Sopenharmony_ci return error; 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci return 0; 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistatic void goodix_ts_remove(struct i2c_client *client) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci struct goodix_ts_data *ts = i2c_get_clientdata(client); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (ts->load_cfg_from_disk) 141162306a36Sopenharmony_ci wait_for_completion(&ts->firmware_loading_complete); 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_cistatic int goodix_suspend(struct device *dev) 141562306a36Sopenharmony_ci{ 141662306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 141762306a36Sopenharmony_ci struct goodix_ts_data *ts = i2c_get_clientdata(client); 141862306a36Sopenharmony_ci int error; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (ts->load_cfg_from_disk) 142162306a36Sopenharmony_ci wait_for_completion(&ts->firmware_loading_complete); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* We need gpio pins to suspend/resume */ 142462306a36Sopenharmony_ci if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { 142562306a36Sopenharmony_ci disable_irq(client->irq); 142662306a36Sopenharmony_ci return 0; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* Free IRQ as IRQ pin is used as output in the suspend sequence */ 143062306a36Sopenharmony_ci goodix_free_irq(ts); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* Save reference (calibration) info if necessary */ 143362306a36Sopenharmony_ci goodix_save_bak_ref(ts); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* Output LOW on the INT pin for 5 ms */ 143662306a36Sopenharmony_ci error = goodix_irq_direction_output(ts, 0); 143762306a36Sopenharmony_ci if (error) { 143862306a36Sopenharmony_ci goodix_request_irq(ts); 143962306a36Sopenharmony_ci return error; 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci usleep_range(5000, 6000); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND, 144562306a36Sopenharmony_ci GOODIX_CMD_SCREEN_OFF); 144662306a36Sopenharmony_ci if (error) { 144762306a36Sopenharmony_ci goodix_irq_direction_input(ts); 144862306a36Sopenharmony_ci goodix_request_irq(ts); 144962306a36Sopenharmony_ci return -EAGAIN; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* 145362306a36Sopenharmony_ci * The datasheet specifies that the interval between sending screen-off 145462306a36Sopenharmony_ci * command and wake-up should be longer than 58 ms. To avoid waking up 145562306a36Sopenharmony_ci * sooner, delay 58ms here. 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_ci msleep(58); 145862306a36Sopenharmony_ci return 0; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic int goodix_resume(struct device *dev) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 146462306a36Sopenharmony_ci struct goodix_ts_data *ts = i2c_get_clientdata(client); 146562306a36Sopenharmony_ci u8 config_ver; 146662306a36Sopenharmony_ci int error; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { 146962306a36Sopenharmony_ci enable_irq(client->irq); 147062306a36Sopenharmony_ci return 0; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* 147462306a36Sopenharmony_ci * Exit sleep mode by outputting HIGH level to INT pin 147562306a36Sopenharmony_ci * for 2ms~5ms. 147662306a36Sopenharmony_ci */ 147762306a36Sopenharmony_ci error = goodix_irq_direction_output(ts, 1); 147862306a36Sopenharmony_ci if (error) 147962306a36Sopenharmony_ci return error; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci usleep_range(2000, 5000); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci error = goodix_int_sync(ts); 148462306a36Sopenharmony_ci if (error) 148562306a36Sopenharmony_ci return error; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci error = goodix_i2c_read(ts->client, ts->chip->config_addr, 148862306a36Sopenharmony_ci &config_ver, 1); 148962306a36Sopenharmony_ci if (!error && config_ver != ts->config[0]) 149062306a36Sopenharmony_ci dev_info(dev, "Config version mismatch %d != %d, resetting controller\n", 149162306a36Sopenharmony_ci config_ver, ts->config[0]); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (error != 0 || config_ver != ts->config[0]) { 149462306a36Sopenharmony_ci error = goodix_reset(ts); 149562306a36Sopenharmony_ci if (error) 149662306a36Sopenharmony_ci return error; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci error = goodix_send_cfg(ts, ts->config, ts->chip->config_len); 149962306a36Sopenharmony_ci if (error) 150062306a36Sopenharmony_ci return error; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci error = goodix_request_irq(ts); 150462306a36Sopenharmony_ci if (error) 150562306a36Sopenharmony_ci return error; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci return 0; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cistatic const struct i2c_device_id goodix_ts_id[] = { 151362306a36Sopenharmony_ci { "GDIX1001:00", 0 }, 151462306a36Sopenharmony_ci { } 151562306a36Sopenharmony_ci}; 151662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, goodix_ts_id); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci#ifdef CONFIG_ACPI 151962306a36Sopenharmony_cistatic const struct acpi_device_id goodix_acpi_match[] = { 152062306a36Sopenharmony_ci { "GDIX1001", 0 }, 152162306a36Sopenharmony_ci { "GDIX1002", 0 }, 152262306a36Sopenharmony_ci { "GDX9110", 0 }, 152362306a36Sopenharmony_ci { } 152462306a36Sopenharmony_ci}; 152562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, goodix_acpi_match); 152662306a36Sopenharmony_ci#endif 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci#ifdef CONFIG_OF 152962306a36Sopenharmony_cistatic const struct of_device_id goodix_of_match[] = { 153062306a36Sopenharmony_ci { .compatible = "goodix,gt1151" }, 153162306a36Sopenharmony_ci { .compatible = "goodix,gt1158" }, 153262306a36Sopenharmony_ci { .compatible = "goodix,gt5663" }, 153362306a36Sopenharmony_ci { .compatible = "goodix,gt5688" }, 153462306a36Sopenharmony_ci { .compatible = "goodix,gt911" }, 153562306a36Sopenharmony_ci { .compatible = "goodix,gt9110" }, 153662306a36Sopenharmony_ci { .compatible = "goodix,gt912" }, 153762306a36Sopenharmony_ci { .compatible = "goodix,gt9147" }, 153862306a36Sopenharmony_ci { .compatible = "goodix,gt917s" }, 153962306a36Sopenharmony_ci { .compatible = "goodix,gt927" }, 154062306a36Sopenharmony_ci { .compatible = "goodix,gt9271" }, 154162306a36Sopenharmony_ci { .compatible = "goodix,gt928" }, 154262306a36Sopenharmony_ci { .compatible = "goodix,gt9286" }, 154362306a36Sopenharmony_ci { .compatible = "goodix,gt967" }, 154462306a36Sopenharmony_ci { } 154562306a36Sopenharmony_ci}; 154662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, goodix_of_match); 154762306a36Sopenharmony_ci#endif 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic struct i2c_driver goodix_ts_driver = { 155062306a36Sopenharmony_ci .probe = goodix_ts_probe, 155162306a36Sopenharmony_ci .remove = goodix_ts_remove, 155262306a36Sopenharmony_ci .id_table = goodix_ts_id, 155362306a36Sopenharmony_ci .driver = { 155462306a36Sopenharmony_ci .name = "Goodix-TS", 155562306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(goodix_acpi_match), 155662306a36Sopenharmony_ci .of_match_table = of_match_ptr(goodix_of_match), 155762306a36Sopenharmony_ci .pm = pm_sleep_ptr(&goodix_pm_ops), 155862306a36Sopenharmony_ci }, 155962306a36Sopenharmony_ci}; 156062306a36Sopenharmony_cimodule_i2c_driver(goodix_ts_driver); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 156362306a36Sopenharmony_ciMODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); 156462306a36Sopenharmony_ciMODULE_DESCRIPTION("Goodix touchscreen driver"); 156562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1566